本篇博客主要有2个目的,第一,记录学习使用TensorFlow
的操作流程;第二,将TensorFlow
训练数据模型过程中的参数数据进行可视化记录。
1.使用TensorFlow
搭建一个3层的神经网络(输入层,隐藏层,输出层)的模型训练经典的MNIST
数据集,从而来预测手写体数字。
2.训练过程中使用TensorBoard
来可视化训练过程中参数数据
实例的Github代码地址
Step1 导入响应的库和加载数据集
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
#以独热编码的方式加载数据集
mnist = input_data.read_data_sets('./MNIST_data/',one_hot=True)
Step2 模型相关的参数设置
将模型相关的可能会变化的参数提前设置出来,方便后面统一更改
in_unit = 784
h1_unit = 300
learningrate = 0.05 # 梯度下降法学习率
dropout_keep_prob = 0.75 # dropout时保留神经元的比例,神经网络不为0的参数变为原理的1/dropout_keep_prob倍
batch_size = 100 # 梯度下降法选取的batch的size
max_iter = 3000 # 迭代次数
sava_dir = '../data/' # 存放数据结果
log_dir = '../log/' # 日志目录
Step3 设置TensorFlow中的计算图
1. 在TensorFlow
启动session
运行节点操作时,先设置好TensorFlow
计算图,有利于全局把控计算图中的所有的节点操作。(TensorFlow
中的计算图包括节点和边,其中节点为运算操作,而边代表数据的流动即张量,但是一些边没有数据流动表示节点运算操作之间的依赖关系;TensorFlow
中的节点操作运行需要通过Session
会话来启动,使用session.run()
或节点操作对象调用eval()
2. tf.placeholder
为TensorFlow
中的占位符,作为外部数据(包括数据集和其他一些模型参数)的输入占位,当运行节点操作时候需要设置feed_dict
参数来对占位符数据进行填充。
3. 见下面NO3
说明部分
4. 在第一层隐藏层的输出后使用tf.nn.dropout
再加了一层dropout
层
5. 模型训练优化器选用的是AdamOptimizer
,loss
函数是交叉熵,使用的是tf
自带的tf.nn.softmax_cross_entropy_with_logits
来计算真实值和预测值的交叉熵
tf.reset_default_graph()
train_graph = tf.Graph()
with train_graph.as_default():
# step 3.1 设置算法模型中的输入,使用占位符,占用输入的数据(什么情况下使用占位符,什么情况下设置tf变量)
train_x = tf.placeholder(dtype=tf.float32,shape=[None,in_unit],name = 'train_x')
train_y = tf.placeholder(dtype=tf.float32,shape=[None,10],name = 'train_y')
# step 3.2构造神经网络
# 创建第一层隐藏层
hidden_layer1 = nn_layer(train_x,input_dim=in_unit,output_dim=h1_unit,layer_name='hider_layer1',act=tf.nn.relu)
#在第一层隐藏层上创建一层 dropout层 —— 随机关闭一些hidden_layer1的神经元
with tf.name_scope('dropout'):
dropout_prob = tf.placeholder(dtype=tf.float32, name='dropout_prob')
tf.summary.scalar('dropout_keep_probability',dropout_prob)
hidden_layer1_dropout = tf.nn.dropout(hidden_layer1,dropout_prob)
#创建输出层,包括10个类别,输出层的输入是hidden_layer1_dropout,输出是[1,10]
y = nn_layer(hidden_layer1_dropout,h1_unit,10,layer_name='out_layer',act=tf.identity)
# step 3.3 创建损失函数
with tf.name_scope('loss'):
cross_entropy_diff = tf.nn.softmax_cross_entropy_with_logits(labels=train_y, logits=y)
with tf.name_scope('total'):
cross_entropy = tf.reduce_mean(cross_entropy_diff)
tf.summary.scalar('loss', cross_entropy)
# step 3.4 选择优化器训练并设计计算准确率的节点
optimizer = tf.train.AdamOptimizer(learning_rate=learningrate)
train_op = optimizer.minimize(cross_entropy)
with tf.name_scope('accuracy'):
with tf.name_scope('correct_prediction'):
correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(train_y, 1))
with tf.name_scope('accuracy'):
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
tf.summary.scalar('accuracy', accuracy)
NO3:
其中构建单层神经网络的操作封装于函数nn_layer
,返回一个Tensor
对象。weight_variable
函数和bias_variable
函数中使用tf.Variable
来初始化网络层中对应的权重w
和偏置项b
. 其中tf.matmul(input_tensor,weight)+bias
是该层网络的所有神经元的wx+b
的向量表示,表示神经元的输入—g(wx+b)
,其中g
为激活函数。
def nn_layer(input_tensor,input_dim,output_dim,layer_name,act=tf.nn.relu):
"""
建立神经网络层(一层),并返回该层网络层的输出的tensor对象
:param input_tensor:特征数据
:param input_dim:输入数据的维度大小
:param output_dim:该层神经元的个数
:param layer_name:命名空间
:param act:神经元对应的激活函数
"""
#设置命名空间
with tf.name_scope(layer_name):
#初始化权重,并记录权重变化
with tf.name_scope('weights'):
weight = weight_variable([input_dim,output_dim])
variable_summeries(weight)# 记录权重变化
with tf.name_scope('bias'):
bias = bias_variable([output_dim])
variable_summeries(bias)
with tf.name_scope('linear_compute'):
preact = tf.matmul(input_tensor,weight)+bias
tf.summary.histogram('linear',preact)
activeation = act(preact,name = 'activation')
tf.summary.histogram('activation',activeation)
return activeation
def weight_variable(shape):
"""
将每一层的神经网络的对应的权重参数w,初始化并封装到function中
"""
inita_w = tf.truncated_normal(shape,stddev=0.1)
return tf.Variable(inita_w,dtype=tf.float32)
def bias_variable(shape):
"""
将每一层的神经网络的对应的偏置项b,初始化并封装到function中
"""
inita_b = tf.constant(0.1,shape=shape)
return tf.Variable(inita_b)
Step4 启动TensorFlow Session
来实现计算图中的训练操作并将相应的Summary
记录到日志文件
1.初始化Session
并设置Session
对应的计算图,初始化TensorFlow
的变量操作 tf.global_variables_initializer().run()
2. 计算图中的节点运行方式有两种,方式一:session.run()
,函数中设置好计算图中对应的节点操作,如session.run([train_op,cross_entropy,accuracy])
其中train_op
表示运行模型训练的操作,cross_entropy
表示运行获取训练模型交叉熵的操作,accuracy表示获取模型运行的准确率操作,run
函数返回的节点操作运行的对应结果。方式二,在tf.InteractiveSession
初始化session
情况下可以使用oper.eval()
来运行操作,如train_op.eval()
。该方式一次只能运行一个节点操作。
session = tf.InteractiveSession(graph=train_graph)
# step 4.1 合并summary并初始化所有变量
merged = tf.summary.merge_all()
train_writer = tf.summary.FileWriter(log_dir+'/train',graph=train_graph)
test_writer = tf.summary.FileWriter(log_dir+'/test',graph=train_graph)
tf.global_variables_initializer().run()
# Step 4.2 训练模型并记录到TensorBoard
for iter in range(max_iter):
trainx_batch_x,train_batch_y = mnist.train.next_batch(batch_size)
#迭代10次记录一下accuracy
if iter % 10 == 0:
summmary,acc,loss = session.run([merged,accuracy,cross_entropy],feed_dict={train_x:trainx_batch_x,train_y:train_batch_y,dropout_prob:1.0})
test_writer.add_summary(summmary,iter)#写入日志
print('loss at step %s: %s'%(iter,loss))
print('Accuracy at step %s: %s'%(iter,acc))
else:
if iter % 100 == 0:
#记录tensor运行节点的信息
run_options = tf.RunOptions(trace_level=tf.RunOptions.FULL_TRACE)
run_metadata = tf.RunMetadata()
#将配置信息和记录运行信息的proto传入运行的过程,从而记录运行时每一个节点的时间、空间开销信息
summmary,_ = session.run([merged,train_op],
feed_dict={train_x:trainx_batch_x,train_y:train_batch_y,dropout_prob:dropout_keep_prob},
options=run_options,
run_metadata=run_metadata)
#将节点运行时的信息写入日志文件
train_writer.add_run_metadata(run_metadata,'step %d' % iter)
train_writer.add_summary(summmary,iter)
pass
else:
summmary,_ = session.run([merged,train_op],feed_dict={train_x:trainx_batch_x,train_y:train_batch_y,dropout_prob:dropout_keep_prob})
train_writer.add_summary(summmary,iter)
train_writer.close()
test_writer.close()
session.close()
TensorBoard
能记录的数据类型为:
标量:SCALARS
图片:IMAGES
音频:AUDIO
计算图:GRAPHS
数据分布图:DISTRIBUTIONS
直方图:HISTOGRAMS
嵌入向量:EMBEDDINGS
对上述数据的记录方式有:
tf.summary.audio(name, tensor)
tf.summary.scalar(name,tensor)
tf.summary.image(name, tensor)
tf.summary.histogram(name, tensor)
#其中name表示生成的节点的名称。 也将作为TensorBoard中的一个系列名称。tensor为要记录的数据。
#其中嵌入向量EMBEDDINGS的可视化,需要依赖于模型的保存,需要定义tf.train.Saver对象,再配置projector.ProjectorConfig对象。
基本可视化步骤(摘自其他博客):
1.建立一个Graph
计算图,即想从该计算图中记录某些数据的信息并可视化。
代码实现中的 Step 3
中的代码 为建立计算图的过程。
train_graph = tf.Graph()
2.确定要在Graph
计算图中的哪些节点放置Summary Operations
以用来记录信息。
其中tf.name_scope(name)
为给节点设置上下文,可以理解为节点的文件夹管理,一层包含一层的关系
如Step 3
设计计算图中的建立神经网络的代码:
#记录其中交叉熵的值
tf.summary.scalar('loss', cross_entropy)
#记录激活函数层的输出值
tf.summary.histogram('activation',activeation)
3.计算图中设计的Summary Operations
并不会真正去执行计算记录,需要使用Session中的run去执行,或者被其他操作节点依赖执行。在TensorFlow代码实现
的Step
中创建的Summary Operations
没有被其他节点依赖,需要特地去运行Summary节点操作。Step 4
中通过代码merged = tf.summary.merge_all()
将所有的Summary Operations
合并成一个节点,从而直接run
该节点即可,也可以通过代码tf.summary.merge(input_list)
,合并指定的一些Summary Operations
成一个节点再run
。
4.使用tf.summary.FileWriter
将运行后输出的数据都保存到本地磁盘中。
如Step 4 中的代码
#graph参数为指定要获取数据信息的计算图,对应着第一步。
train_writer = tf.summary.FileWriter(log_dir+'/train',graph=train_graph)