zoukankan      html  css  js  c++  java
  • Tensorflow实现手写体分类(含dropout)

    一、手写体分类

    1. 数据集

    import tensorflow as tf
    from tensorflow.examples.tutorials.mnist import input_data
    import os
    
    os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
    os.environ["CUDA_VISIBLE_DEVICES"] = "0"
    config = tf.ConfigProto(allow_soft_placement = True)
    gpu_options = tf.GPUOptions(per_process_gpu_memory_fraction = 0.33)
    config.gpu_options.allow_growth = True
    
    max_steps = 20  # 最大迭代次数
    learning_rate = 0.001   # 学习率
    dropout = 0.9   # dropout时随机保留神经元的比例
    data_dir = '.MNIST_DATA'   # 样本数据存储的路径
    log_dir = 'E:MNIST_LOG'    # 输出日志保存的路径
    
    # 获取数据集,并采用采用one_hot热编码
    mnist = input_data.read_data_sets(data_dir,one_hot = True)
    # mnist=input_data.read_data_sets('MNIST_data',one_hot=True)
    
    '''下载数据是直接调用了tensorflow提供的函数read_data_sets,输入两个参数,
    第一个是下载到数据存储的路径,第二个one_hot表示是否要将类别标签进行独热编码。
    它首先回去找制定目录下有没有这个数据文件,没有的话才去下载,有的话就直接读取。
    所以第一次执行这个命令,速度会比较慢。'''
    
    # sess = tf.InteractiveSession(config = config)

    下面的图是通过调用 tf.summary.image('input', image_shaped_input, 10)得到的,具体见2.初始化参数

    2. 初始化参数

    with tf.name_scope('input'):
        x = tf.placeholder(tf.float32, [None, 784], name='x-input')
        y_ = tf.placeholder(tf.float32, [None, 10], name='y-input')
    
    # 保存图像信息
    with tf.name_scope('input_reshape'):
        image_shaped_input = tf.reshape(x, [-1, 28, 28, 1])
        tf.summary.image('input', image_shaped_input, 10)
    
    # 初始化权重参数
    def weight_variable(shape):
        initial = tf.truncated_normal(shape, stddev = 0.1)
        return tf.Variable(initial)
    
    # 初始化偏执参数
    def bias_variable(shape):
        initial = tf.constant(0.1, shape = shape)
        return tf.Variable(initial)
    
    # 绘制参数变化
    def variable_summaries(var):
        with tf.name_scope('summaries'):
            # 计算参数的均值,并使用tf.summary.scaler记录
            mean = tf.reduce_mean(var)
            tf.summary.scalar('mean', mean)
    
            # 计算参数的标准差
            with tf.name_scope('stddev'):
                stddev = tf.sqrt(tf.reduce_mean(tf.square(var - mean)))
            # 使用tf.summary.scaler记录下标准差,最大值,最小值
            tf.summary.scalar('stddev', stddev)
            tf.summary.scalar('max', tf.reduce_max(var))
            tf.summary.scalar('min', tf.reduce_min(var))
            # 用直方图记录参数的分布
            tf.summary.histogram('histogram', var)
    

      

    第一层的weight和biases的变化情况

     

     第二层的weight和biases的变化情况

     3. 构建神经网络

    下面是单层神经网络模型

    # 构建神经网络
    def nn_layer(input_tensor, input_dim, output_dim, layer_name, act=tf.nn.relu):
        # 设置命名空间
        with tf.name_scope(layer_name):
            # 调用之前的方法初始化权重w,并且调用参数信息的记录方法,记录w的信息
            with tf.name_scope('weights'):
                weights = weight_variable([input_dim, output_dim])
                variable_summaries(weights)
            # 调用之前的方法初始化权重b,并且调用参数信息的记录方法,记录b的信息
            with tf.name_scope('biases'):
                biases = bias_variable([output_dim])
                variable_summaries(biases)
            # 执行wx+b的线性计算,并且用直方图记录下来
            with tf.name_scope('linear_compute'):
                preactivate = tf.matmul(input_tensor, weights) + biases
                tf.summary.histogram('linear', preactivate)
            # 将线性输出经过激励函数,并将输出也用直方图记录下来
            activations = act(preactivate, name='activation')
            tf.summary.histogram('activations', activations)
        # 返回激励层的最终输出
        return activations

    下面要建双层神经网络,第一层加dropout

    hidden1 = nn_layer(x, 784, 500, 'layer1')
    
    # 创建dropout层
    with tf.name_scope('dropout'):
    keep_prob = tf.placeholder(tf.float32)
    tf.summary.scalar('dropout_keep_probability', keep_prob)
    dropped = tf.nn.dropout(hidden1, keep_prob)
    
    y = nn_layer(dropped, 500, 10, 'layer2', act=tf.identity)  

    模型图如下:

     dropout变化如下:

    第一层和第二层的weights、bias、未激活前,激活后的值分布如下:

      tf.summary.histogram接受任意大小和形状的张量,并将该张量压缩成一个由许多分箱组成的直方图数据结构,这些分箱有各种宽度和计数。例如,假设我们要将数字 [0.5, 1.1, 1.3, 2.2, 2.9, 2.99] 整理到不同的分箱中,我们可以创建三个分箱: * 一个分箱包含 0 到 1 之间的所有数字(会包含一个元素:0.5), * 一个分箱包含 1 到 2 之间的所有数字(会包含两个元素:1.1 和 1.3), * 一个分箱包含 2 到 3 之间的所有数字(会包含三个元素:2.2、2.9 和 2.99)。TensorFlow 使用类似的方法创建分箱,但与我们的示例不同,它不创建整数分箱。对于大型稀疏数据集,可能会导致数千个分箱。相反,这些分箱呈指数分布,许多分箱接近 0,有较少的分箱的数值较大。 然而,将指数分布的分箱可视化是非常艰难的。如果将高度用于为计数编码,那么即使元素数量相同,较宽的分箱所占的空间也越大。反过来推理,如果用面积为计数编码,则使高度无法比较。因此,直方图会将数据重新采样并分配到统一的分箱。很不幸,在某些情况下,这可能会造成假象。

      直方图可视化工具中的每个切片显示单个直方图。切片是按步骤整理的;较早的切片(如,步骤 0)位于较“靠后”的位置,颜色也较深,而较晚的切片则靠近前景,颜色也较浅。右侧的 y 轴显示步骤编号。

    举例:下图表示时间步骤76,对应的直方图的分箱位于0.0695附近,分箱中有712个元素

    切换historm到覆盖模式

    信息中心左侧有一个控件,可以将直方图模式从“偏移”切换到“覆盖”:在“偏移”模式下,可视化旋转 45 度,以便各个直方图切片不再按时间展开,而是全部绘制在相同的 y 轴上。

    现在,每个切片都是图表上的一条单独线条,y 轴显示的是每个分箱内的项目数。颜色较深的线条表示较早的步,而颜色较浅的线条表示较晚的步。同样,可以将鼠标悬停在图表上以查看其他一些信息。

     

    4. 损失函数+优化器

    # 创建损失函数
    with tf.name_scope('loss'):
        # 计算交叉熵损失(每个样本都会有一个损失)
        diff = tf.nn.softmax_cross_entropy_with_logits_v2(labels=y_, logits=y)
        with tf.name_scope('total'):
            # 计算所有样本交叉熵损失的均值
            cross_entropy = tf.reduce_mean(diff)
        tf.summary.scalar('loss', cross_entropy)
        
    # 使用AdamOptimizer优化器训练模型,最小化交叉熵损失
    with tf.name_scope('train'):
        train_step = tf.train.AdamOptimizer(learning_rate).minimize(cross_entropy)
    
    # 计算准确率
    with tf.name_scope('accuracy'):
        with tf.name_scope('correct_prediction'):
            # 分别将预测和真实的标签中取出最大值的索引,弱相同则返回1(true),不同则返回0(false)
            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))
            
    tf.summary.scalar('accuracy', accuracy)

    5. 训练

    sess = tf.Session()
    #summaries合并
    merged = tf.summary.merge_all()
    # 写到指定的磁盘路径中
    train_writer = tf.summary.FileWriter(log_dir + '/train', sess.graph)
    test_writer = tf.summary.FileWriter(log_dir + '/test',sess.graph)
    
    #运行初始化所有变量
    # global_variables_initializer().run()
    sess.run(tf.global_variables_initializer())
    
    def feed_dict(train):
        """Make a TensorFlow feed_dict: maps data onto Tensor placeholders."""
        if train:
            xs, ys = mnist.train.next_batch(10)
            k = dropout
        else:
            xs, ys = mnist.test.images[:100], mnist.test.labels[:100]
            k = 1.0
        return {x: xs, y_: ys, keep_prob: k}
    
    for i in range(100):
        if i % 10 == 0:  #记录测试集的summary与accuracy
            summary, acc = sess.run([merged, accuracy], feed_dict=feed_dict(False))
            test_writer.add_summary(summary, i)
            print('Accuracy at step %s: %s' % (i, acc))
        else:  # 记录训练集的summary
            summary, _ = sess.run([merged, train_step], feed_dict=feed_dict(True))
            train_writer.add_summary(summary, i)
    
    train_writer.close()
    test_writer.close()
    

      

    准确率:

    损失函数:

     

     参考文献:

    【1】莫烦Python

    【2】TensorBoard 直方图信息中心

  • 相关阅读:
    【应试】数据通信与网络
    【应试】操作系统OS
    【笔记】 卷积
    【HDU 5920】 Ugly Problem
    【笔记】位运算
    【洛谷P1378】油滴扩展
    【洛谷 P1120】 小木棍[数据加强版]
    [codeforces]Round #538 (Div. 2) F. Please, another Queries on Array?
    [BZOJ]2563: 阿狸和桃子的游戏
    [BZOJ]4668: 冷战
  • 原文地址:https://www.cnblogs.com/nxf-rabbit75/p/10632201.html
Copyright © 2011-2022 走看看