TensorFlow实现多层感知机及可视化训练过程中的数据记录

996 阅读6分钟
原文链接: blog.csdn.net

说明(what)

本篇博客主要有2个目的,第一,记录学习使用TensorFlow的操作流程;第二,将TensorFlow训练数据模型过程中的参数数据进行可视化记录。

具体操作(how)

实例描述

1.使用TensorFlow搭建一个3层的神经网络(输入层,隐藏层,输出层)的模型训练经典的MNIST数据集,从而来预测手写体数字。
2.训练过程中使用TensorBoard来可视化训练过程中参数数据
实例的Github代码地址

TensorFlow代码实现

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.placeholderTensorFlow中的占位符,作为外部数据(包括数据集和其他一些模型参数)的输入占位,当运行节点操作时候需要设置feed_dict参数来对占位符数据进行填充。
3. 见下面NO3说明部分
4. 在第一层隐藏层的输出后使用tf.nn.dropout再加了一层dropout
5. 模型训练优化器选用的是AdamOptimizerloss函数是交叉熵,使用的是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可视化过程

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)
  1. 运行整个程序,并在终端输入运行TensorBoard的指令,再打开web端查看可视化的结果
    命令:tensorboard --logdir='./ML/log/'
    tensorboard命令
    打开对应的网址 http://0.0.0.0:6006/