TensorFlow基础知识

TensorFlow采用声明式编程范式,其优势包括:

  1. 代码可读性强
  2. 支持引用透明,声明式编程没有内部状态,不依赖于外部环境
  3. 提供预编译优化能力

基础概念

数据流图基本概念

  1. 节点
    a. 数学函数和表达式:Add,MatMul
    b. 存储模型参数的变量:W,b
    c. 占位符(placeholder):Input
    d. 梯度值:Gradients
    e. 更新参数的操作:Update W
  2. 有向边
    包括数据边(实线)和依赖边(虚线)
  3. 执行原理
    不以代码定义顺序执行,以节点逻辑关系决定各节点的执行顺序,数据流图是一个有向无环图

张量(Tensor)

TensorFlow中的张量包括标量,向量,矩阵,高维张量等等。
TF中使用句柄实现张量,存储张量的元信息和指向张量数据内存的指针,使用引用计数释放不再需要的张量。

import tensorflow as tf

a = tf.constant(1.0) # 一般不使用Tensor()构造函数创建张量
b = tf.constant(2.0) # 使用操作间接创建
c = tf.add(a, b)
print([a, b, c])

with tf.Session() as sess:
    print(c.eval()) # 调用张量的eval()函数求解
    print(sess.run([a, b, c])) # 使用会话求解
稀疏张量(SparseTensor)

用于处理高维稀疏数据,包含indices,values,dense_shape三个属性。
indices:形状为(N, ndims)的Tensor,N为非0元素个数,ndims表示张量阶数
values:形状为(N)的Tensor,保存indices中指定的非0元素的值
dense_shape:形状为(ndims)的Tensor,表示该稀疏张量对应稠密张量的形状

import tensorflow as tf

sp = tf.SparseTensor(indices = [[0, 2], [1, 3]], values = [1, 2], dense_shape = [3, 4])
with tf.Session() as sess:
    print(sp.eval())

操作

计算节点

Operation类,不需要显式构造
tf.global_variables_initializer的本质是将initial_value传入变量中的Assign节点,实现赋值

存储节点

Variable类
包含四个子节点:变量初始值(initial_value),更新操作(Assign),读取操作(read)和变量操作((a),括号代表有状态)
变量有状态,生命周期和数据流图相同,普通节点是临时创建的,当依赖它们的所有操作执行完毕后会被释放

数据节点

Placeholder类,调用tf.placeholder()创建,用于向数据流图中传入数据

import tensorflow as tf
import numpy as np

with tf.name_scope("PlaceholderExample"):
    x = tf.placeholder(tf.float32, shape=(2, 2), name="x") # 创建placeholder
    y = tf.matmul(x, x, name="natmul")

with tf.Session() as sess:
    rand_array = np.random.randn(2, 2)
    print(sess.run(y, feed_dict={x: rand_array})) # 使用feed_dict喂入数据

会话

Session类

sess = tf.Session() # sess不会被设置为默认会话
sess.run(#something)
sess.close()
# or
with tf.Session() as sess:
    Tensor.eval() # 参数内需传入session,如果在with作用域内,则会使用默认sess
    Operation.run() # 在内部调用了Session.run()
    sess.run()
    # do something
    # with结束后调用Session.__exit__关闭会话

InteractiveSession交互式会话

a = tf.constant(5.0)
sess = tf.InteractiveSession() # sess会被设置为默认会话
print(a.eval()) # 可直接调用eval()
sess.close()

优化器

损失函数

常用损失函数:

  1. 平方损失函数[图片上传失败...(image-e7292-1539227980315)])^{2})

  2. 交叉熵损失函数[图片上传失败...(image-b988f9-1539227980315)]))

  3. 指数损失函数[图片上传失败...(image-8b85bc-1539227980315)]))

经验风险(平均损失)[图片上传失败...(image-e0b247-1539227980315)]&space;=&space;\frac{1}{N}\sum&space;L(f(x_{i};\theta),y_{i}))

常用正则化项有L0、L1、L2范式
结构风险能减少过拟合,由经验风险加上正则项构成[图片上传失败...(image-191c50-1539227980315)]&space;=&space;\frac{1}{N}\sum&space;L(f(x_{i};\theta),y_{i})&space;+&space;\lambda&space;J(\theta))

优化算法包括梯度下降法,牛顿法,Adam等

优化器

Optimizer类,通过实例子类使用。
实现了minimize()函数,该函数内部调用compute_gradients()和apply_gradiets()计算梯度值并更新参数

示例代码

X = tf.placeholder(...)
Y_ = tf.placeholder(...)
w = tf.Variable(...)
b = tf.Variable(...)
Y = tf.matmul(X, w) + b
loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=Y_, logits=Y))
optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.01)
global_step = tf.Variable(0, name='global_step', trainable=False)
train_op=optimizer.minimize(loss, global_step=global_step)
with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    for step in xrange(max_train_steps):
        sess.run(train_op, feed_dict={...})

一元线性回归实例

import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt

# 设定超参数
learning_rate = 0.01
max_train_steps = 1000
log_step = 50

# 加载训练数据
train_X = np.array([[3.3], [4.4], [5.5], [6.71], [6.93], [4.168], [9.779], [6.182], [7.59], [2.167], [7.042], [10.791], [5.313], [7.997], [5.654], [9.27], [3.1]], dtype = np.float32)
train_Y = np.array([[1.7], [2.76], [2.09], [3.19], [1.694], [1.573], [3.366], [2.596], [2.53], [1.221], [2.827], [3.465], [1.65], [2.904], [2.42], [2.94], [1.3]], dtype = np.float32)
total_samples = train_X.shape[0]

# 设定参数
X = tf.placeholder(tf.float32, [None, 1])
W = tf.Variable(tf.random_normal([1, 1]), name = "weight")
b = tf.Variable(tf.zeros([1]), name = "bias")
Y = tf.matmul(X, W) + b

# 设定loss函数和初始化optimizer
Y_ = tf.placeholder(tf.float32, [None, 1])
loss = tf.reduce_sum(tf.pow(Y-Y_, 2)) / (total_samples)
optimizer = tf.train.GradientDescentOptimizer(learning_rate)

# 训练数据
train_op = optimizer.minimize(loss)
with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())

     print("Start training")
    for step in range(max_train_steps):
        sess.run(train_op, feed_dict={X: train_X, Y_: train_Y})
        if step % log_step == 0:
            c = sess.run(loss, feed_dict={X: train_X, Y_: train_Y})
            print("Step:%d, loss==%.4f, W==%.4f, b==%.4f" % (step, c, sess.run(W), sess.run(b)))
    final_loss = sess.run(loss, feed_dict={X: train_X, Y_: train_Y})
    weight, bias = sess.run([W, b])
    print("Step:%d, loss==%.4f, W==%.4f, b==%.4f" % (max_train_steps, final_loss, sess.run(W), sess.run(b)))
    print("Linear Regression Model: Y==%.4f*X+%.4f" % (weight, bias))

#使用matplotlib绘制图片
%matplotlib inline
plt.plot(train_X, train_Y, 'ro', label = 'Training data')
plt.plot(train_X, weight * train_X + bias, label = 'Fitting line')
plt.legend()
plt.show()

数据处理方式

输入数据集

用于模型训练、验证和测试的数据集
大数据集一般使用输入流水线并行读取

  1. 创建文件名列表:使用python列表或tf.train.match_filenames_once()
  2. 创建文件名队列:使用tf.train.string_input_producer(),打乱数据,随机读取
  3. 创建Reader和Decoder:
# 创建文件名队列
filename_queue = tf.train.string_input_producer(['stat0.csv', 'stat1.csv'])
reader = tf.TextLineReader()
# 从中取出一条数据
_, value = reader.read(filename_queue)
record_defaults = [[0], [0], [0.0], [0.0]]
# 将数据转换为特征张量
id, age, income, outgo = tf.decode_csv(value, record_defaults = record_defaults)
# 将特征组合成一条记录
features = tf.stack([id, age, income, outgo])
  1. 创建样例队列:使用tf.train.start_queue_runners()
  2. 批样例队列:使用tf.train.shuffle_batch(),打乱样例并聚合成批数据

模型参数

W和b,训练对象

  1. 创建模型参数:W = tf.Variable(...)
    几种生成随机张量的方法:
    a. tf.random_normal:正态分布
    b. tf.truncated:截尾正态分布
    c. tf.random_uniform:均匀分布
    d. tf.multinomial:多项式分布
    e. tf.random_gamma:伽马分布
    f. tf.random_shuffle: 按维度重洗
    g. tf.random_crop:按形状裁剪
W = tf.Variable(tf.random_normal(shape=(1, 4), stddev=0.35), name="W") # 使用随机方法初始化参数
W_replica = tf.Variable(W.initialized_value(), name="W_replica") # 使用W的初始值初始化参数
W_twice = tf.Variable(W.initialized_value() * 2.0, name="W_twice")
  1. 初始化模型参数
w = tf.Variable(...)
b = tf.Variable(...)
with tf.Session() as sess:
    sess.run(tf.global_variables_initializer()) # 初始化所有全局变量
    sess.run(tf.local_variables_initializer()) # 初始化所有局部变量
    sess.run(tf.variables_initializer([w])) # 初始化部分变量
  1. 更新模型参数
    使用tf.assign()或tf.assign_add()等函数进行赋值
  2. 保存参数模型
    使用tf.train.Saver 读写模型参数到checkpoint文件
  3. 恢复参数模型
W = tf.Variable(0.0, name='W')
double = tf.multiply(2.0, W)
saver = tf.train.Saver({'weights': W})
with tf.Session() as sess:
    sess.run(tf.global_variables_initializer()) # 使用初始化器初始化
    saver.restore(sess, 'tmp/summary/test.ckpt') # 读取ckpt文件初始化
    for i in range(4):
        sess.run(tf.assign_add(W, 1.0))
        saver.save(sess, '/tmp/summary/test.ckpt') # 保存到ckpt文件,注意保存的是sess
  1. 变量作用域
    深度神经网络有大量参数,使用tf.Variable非常笨重,这时候使用tf.get_variable和tf.variable_scope更方便
def conv_relu(input, kernel_shape, bias_shape):
    weights = tf.get_variable("weights", kernel_shape, initializer=tf.random_normal_initializer()) # 通过 initializer来初始化变量
    biases = tf.get_variable("biases", bias_shape, initializer-tf.constant_initializer(0.0))
    conv = tf.nn.conv2d(input, weights, strides=[1,1,1,1], padding='SAME')
    return tf.nn.relu(conv + biases)

def my_image_filter(input_images):
    with tf.variable_scope("conv1", reuse=True): # 使用tf.variable_scope()设置作用域
        relu1 = conv_relu(input_images, [5, 5, 32, 32], [32])
    with tf.variable_scope("conv2", reuse=True):
        relu2 = conv_relu(relu1, [5, 5, 32, 32], [32])

命令行参数

一般指超参数和集群参数

  1. 使用argparse解析命令行参数
    a. 创建解析器
    b. 添加待解析参数
    c. 解析参数
parser = argparse.ArgumentParser(prog='demo', description='A demo program', epilog='The end of usage') # 创建解析器
parser.add_argument('name') # 添加参数
parser.add_argument('-a', '--age', type=int, required=True)
parser.add_argument('-s', '--status', choices=['alpha', 'beta', 'released'], type=str, dest='myStatus')
parser.add_argument('-v', '--version', action='version', version='%(prog)s 1.0')
args = parser.parse_args() # 解析
args, unparsed = parser.parse.known_args() # 将命令中未定义的参数返回给unparsed
print(args)
  1. 使用tf.app.flags解析
flags = tf.app.flags # 创建flags
flags.DEFINE_string("data_dir", "tmp/mnist-data", "Directory for string mnist data") # 定义string参数,内部会调用add_argument()
FLAGS = flags.FLAGS # 解析出来的参数字典
def main(_):
    print(FLAGS.data_dir) # 调用FLAGS的__getattr__获取参数
if __name__ == "__main__"
    tf.app.run()

编程框架

单机

  1. 创建数据流图
  2. 创建会话

分布式

PS-worker框架
PS用于存储模型参数,worker负责进行训练,计算梯度

  1. 创建集群
tf.train.ClusterSpec({"worker": ["worker().example.com:2222", "worker1.example.com:2222", "worker2.example.com:2222"], "ps": ["ps0.example.com:2222", "ps1.example.com:2222"]}) # 定义cluster
if FLAGS.num_gpus > 0:
    if FLAGS.num_gpus < num_workers:
        raise ValueError("number of gpus is less than number of workers")
    gpu = (FLAGS.task_index % FLAGS.num_gpus)
    worker_device = "/job:worker/task:%d/gpu:%d" % (FLAGS.task_index, gpu)
elif FLAGS.num_gpus == 0:
    cpu = 0
    worker_device = "/job:worker/task:%d/cpu:%d" % (FLAGS.task_index, cpu)

with tf.device(tf.train.replica_device_setter(worker_device=worker_device, ps_device="/job:ps/cpu:0", cluster=cluster)): # 将操作放置到目标设备
    W1 = tf.Variable(...)
    ...
  1. 创建分布式数据流图
  2. 创建并行分布式会话
  3. 使用Supervisor管理模型训练
sv = tf.train.Supervisor(logdir="/my/training/dir") # Supervisor管理单机训练
with sv.managed_session() as sess:
    while not sv.should_stop():
        sess.run(train_op)
server = tf.train.Server(cluster, job_name=FLAGS.job_name, task_index=FLAGS.task_index) # Supervisor管理分布式训练
is_chief = (FLAGS.task_index == 0)
sv = tf.train.Supervisor(logdir="/sharde_dir/...", is_chief=is_chief)
with sv.managed_session(server.target) as sess:
    while not sv.should_stop:
        sess.run(train_op)

TensorBoard

引入抽象节点,代表一组特定操作的集合,用于简化数据流图的网络结构。
示例代码:

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import tensorflow as tf

from tensorflow.examples.tutorials.mnist import input_data

mnist = input_data.read_data_sets('/Users/lyfne/Documents/PythonProject/CIFAR10/mnist_data', one_hot=True)

with tf.name_scope('input'): # 使用name_scope()创建抽象节点
    x = tf.placeholder(tf.float32, [None, 784], name='x-input')
    y_ = tf.placeholder(tf.float32, [None, 10], name='y-input')

with tf.name_scope('softmax_layer'):
    with tf.name_scope('weights'):
        weights = tf.Variable(tf.zeros([784, 10]))
    with tf.name_scope('biases'):
        biases = tf.Variable(tf.zeros([10]))
    with tf.name_scope('Wx_plus_b'):
        y = tf.matmul(x, weights) + biases

with tf.name_scope('cross_entropy'):
    diff = tf.nn.softmax_cross_entropy_with_logits(labels=y_, logits=y)
    with tf.name_scope('total'):
        cross_entropy = tf.reduce_mean(diff)
        tf.summary.scalar('cross_entropy', cross_entropy)

with tf.name_scope('train'):
    train_step = tf.train.AdamOptimizer(0.001).minimize(cross_entropy)

with tf.name_scope('accuracy'):
    with tf.name_scope('correct_prediction'):
        correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))
    with tf.name_scope('accuracy'):
        accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))

sess = tf.InteractiveSession()
writer = tf.summary.FileWriter('/Users/lyfne/Documents/PythonProject/CIFAR10/summary', sess.graph) # 创建FileWriter,向事件文件写入序列化数据。传入参数为存放目录和当前数据流图
tf.global_variables_initializer().run()
writer.close()

启动方法:
在命令行输入tensorboard --logdir=/dir, 其中dir为你存放log文件的目录
打开浏览器。输入localhost:6006进入TensorBoard页面

汇总数据、事件数据和FileWriter工作原理

  • 汇总数据是tf.summary.Summary类或其内嵌类的实例,包括Image、Audio和Value。其内容在summary.proto里。
  • 事件数据是tf.summary.Event类的实例,表示在会话中执行操作时产生的事件信息,包括时间戳、全局步数等。其内容在event.proto中。
  • FileWriter向事件文件中写入的是事件数据,其他数据会转换为事件数据进行存储。当用户创建FileWriter的时候,会在logdir目录下创建一个事件文件,FileWriter内部的SummaryToEventTransformer会调用add_graph将序列化后的数据流图写入事件文件。

可视化学习过程

汇总操作是一种独立的操作,输入张量,输出汇总数据。

tf.summary.scalar # 获取带标量值的汇总数据
tf.summary.histogram # 获取带统计值的汇总数据
tf.summary.image # 获取带图像的汇总数据
tf.summary.audio # 获取带音频的汇总数据

可视化高维数据

EMBEDDINGS,嵌入投影仪,内置t-SNE和主成分分析两种降维方法。
三种输入数据:嵌入变量,嵌入变量元数据,投影配置参数

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342

推荐阅读更多精彩内容