TensorFlow实现与优化深度神经网络

转载请注明作者:梦里风林
Github工程地址:https://github.com/ahangchen/GDLnotes
欢迎star,有问题可以到Issue区讨论
官方教程地址
视频/字幕下载

全连接神经网络

辅助阅读:TensorFlow中文社区教程 - 英文官方教程

代码见:full_connect.py

Linear Model

  • 加载lesson 1中的数据集
  • 将Data降维成一维,将label映射为one-hot encoding

    def reformat(dataset, labels):
    dataset = dataset.reshape((-1, image_size * image_size)).astype(np.float32)
    # Map 0 to [1.0, 0.0, 0.0 ...], 1 to [0.0, 1.0, 0.0 ...]
    labels = (np.arange(num_labels) == labels[:, None]).astype(np.float32)
    return dataset, labels

    TensorFlow Graph

  • 使用梯度计算train_loss,用tf.Graph()创建一个计算单元
  • 用tf.constant将dataset和label转为tensorflow可用的训练格式(训练中不可修改)
  • 用tf.truncated_normal生成正太分布的数据,作为W的初始值,初始化b为可变的0矩阵
  • 用tf.variable将上面的矩阵转为tensorflow可用的训练格式(训练中可以修改)
  • 用tf.matmul实现矩阵相乘,计算WX+b,这里实际上logit只是一个变量,而非结果
  • 用tf.nn.softmax_cross_entropy_with_logits计算WX+b的结果相较于原来的label的train_loss,并求均值
  • 使用梯度找到最小train_loss
    python optimizer = tf.train.GradientDescentOptimizer(0.5).minimize(loss)
  • 计算相对valid_dataset和test_dataset对应的label的train_loss

上面这些变量都是一种Tensor的概念,它们是一个个的计算单元,我们在Graph中设置了这些计算单元,规定了它们的组合方式,就好像把一个个门电路串起来那样

TensorFLow Session

Session用来执行Graph里规定的计算,就好像给一个个门电路通上电,我们在Session里,给计算单元冲上数据,That’s Flow.

  • 重复计算单元反复训练800次,提高其准确度
  • 为了快速查看训练效果,每轮训练只给10000个训练数据(subset),恩,每次都是相同的训练数据
  • 将计算单元graph传给session
  • 初始化参数
  • 传给session优化器 - train_loss的梯度optimizer,训练损失 - train_loss,每次的预测结果,循环执行训练
    python with tf.Session(graph=graph) as session: tf.initialize_all_variables().run() for step in range(num_steps): _, l, predictions = session.run([optimizer, loss, train_prediction])
  • 在循环过程中,W和b会保留,并不断得到修正
  • 在每100次循环后,会用验证集进行验证一次,验证也同时修正了一部分参数
    python valid_prediction.eval()
  • 最后用测试集进行测试
  • 注意如果lesson 1中没有对数据进行乱序化,可能训练集预测准确度很高,验证集和测试集准确度会很低

这样训练的准确度为83.2%

SGD

  • 每次只取一小部分数据做训练,计算loss时,也只取一小部分数据计算loss
  • 对应到程序中,即修改计算单元中的训练数据,
    • 每次输入的训练数据只有128个,随机取起点,取连续128个数据:
      python offset = (step * batch_size) % (train_labels.shape[0] - batch_size) batch_data = train_dataset[offset:(offset + batch_size), :] batch_labels = train_labels[offset:(offset + batch_size), :]
  • 由于这里的数据是会变化的,因此用tf.placeholder来存放这块空间
    python tf_train_dataset = tf.placeholder(tf.float32, shape=(batch_size, image_size * image_size)) tf_train_labels = tf.placeholder(tf.float32, shape=(batch_size, num_labels))
  • 计算3000次,训练总数据量为384000,比之前8000000少

准确率提高到86.5%,而且准确率随训练次数增加而提高的速度变快了

神经网络

  • 上面SGD的模型只有一层WX+b,现在使用一个RELU作为中间的隐藏层,连接两个WX+b
  • 仍然只需要修改Graph计算单元为
    python Y = W2 * RELU(W1*X + b1) + b2
  • 为了在数学上满足矩阵运算,我们需要这样的矩阵运算:
    [n * 10] = RELU([n * 784] · [784 * N] + [n * N]) · [N * 10] + [n * 10]
  • 这里N取1024,即1024个隐藏结点
  • 于是四个参数被修改
    python weights1 = tf.Variable( tf.truncated_normal([image_size * image_size, hidden_node_count])) biases1 = tf.Variable(tf.zeros([hidden_node_count])) weights2 = tf.Variable( tf.truncated_normal([hidden_node_count, num_labels])) biases2 = tf.Variable(tf.zeros([num_labels]))
  • 预测值计算方法改为
    python ys = tf.matmul(tf_train_dataset, weights1) + biases1 hidden = tf.nn.relu(ys) logits = tf.matmul(hidden, weights2) + biases2
  • 计算3000次,可以发现准确率一开始提高得很快,后面提高速度变缓,最终测试准确率提高到88.8%

深度神经网络实践

代码见nn_overfit.py

优化

Regularization

在前面实现的RELU连接的两层神经网络中,加Regularization进行约束,采用加l2 norm的方法,进行调节:

代码实现上,只需要对tf_sgd_relu_nn中train_loss做修改即可:

  • 可以用tf.nn.l2_loss(t)对一个Tensor对象求l2 norm
  • 需要对我们使用的各个W都做这样的计算(参考tensorflow官方example

    l2_loss = tf.nn.l2_loss(weights1) + tf.nn.l2_loss(weights2)
  • 添加到train_loss上
  • 这里还有一个重要的点,Hyper Parameter: β
  • 我觉得这是一个拍脑袋参数,取什么值都行,但效果会不同,我这里解释一下我取β=0.001的理由
  • 如果直接将l2_loss加到train_loss上,每次的train_loss都特别大,几乎只取决于l2_loss
  • 为了让原本的train_loss与l2_loss都能较好地对参数调整方向起作用,它们应当至少在同一个量级
  • 观察不加l2_loss,step 0 时,train_loss在300左右
  • 加l2_loss后, step 0 时,train_loss在300000左右
  • 因此给l2_loss乘0.0001使之降到同一个量级
    python loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits, tf_train_labels)) + 0.001 * l2_loss
  • 所有其他参数不变,训练3000次,准确率提高到92.7%
  • 黑魔法之所以为黑魔法就在于,这个参数可以很容易地影响准确率,如果β = 0.002,准确率提高到93.5%

OverFit问题

在训练数据很少的时候,会出现训练结果准确率高,但测试结果准确率低的情况

  • 缩小训练数据范围:将把batch数据的起点offset的可选范围变小(只能选择0-1128之间的数据):

    offset_range = 1000
    offset = (step * batch_size) % offset_range
  • 可以看到,在step500后,训练集就一直是100%,验证集一直是77.6%,准确度无法随训练次数上升,最后的测试准确度是85.4%

DropOut

采取Dropout方式强迫神经网络学习更多知识

参考aymericdamien/TensorFlow-Examples中dropout的使用

  • 我们需要丢掉RELU出来的部分结果
  • 调用tf.nn.dropout达到我们的目的:

    keep_prob = tf.placeholder(tf.float32)
    if drop_out:
    hidden_drop = tf.nn.dropout(hidden, keep_prob)
    h_fc = hidden_drop
  • 这里的keep_prob是保留概率,即我们要保留的RELU的结果所占比例,tensorflow建议的语法是,让它作为一个placeholder,在run时传入
  • 当然我们也可以不用placeholder,直接传一个0.5:

    if drop_out:
    hidden_drop = tf.nn.dropout(hidden, 0.5)
    h_fc = hidden_drop
  • 这种训练的结果就是,虽然在step 500对训练集预测没能达到100%(起步慢),但训练集预测率达到100%后,验证集的预测正确率仍然在上升
  • 这就是Dropout的好处,每次丢掉随机的数据,让神经网络每次都学习到更多,但也需要知道,这种方式只在我们有的训练数据比较少时很有效
  • 最后预测准确率为88.0%

Learning Rate Decay

随着训练次数增加,自动调整步长

  • 在之前单纯两层神经网络基础上,添加Learning Rate Decay算法
  • 使用tf.train.exponential_decay方法,指数下降调整步长,具体使用方法官方文档说的特别清楚
  • 注意这里面的cur_step传给优化器,优化器在训练中对其做自增计数
  • 与之前单纯两层神经网络对比,准确率直接提高到90.6%

Deep Network

增加神经网络层数,增加训练次数到20000

  • 为了避免修改网络层数需要重写代码,用循环实现中间层

    # middle layer
    for i in range(layer_cnt - 2):
    y1 = tf.matmul(hidden_drop, weights[i]) + biases[i]
    hidden_drop = tf.nn.relu(y1)
    if drop_out:
    keep_prob += 0.5 * i / (layer_cnt + 1)
    hidden_drop = tf.nn.dropout(hidden_drop, keep_prob)
  • 初始化weight在迭代中使用

    for i in range(layer_cnt - 2):
    if hidden_cur_cnt > 2:
    hidden_next_cnt = int(hidden_cur_cnt / 2)
    else:
    hidden_next_cnt = 2
    hidden_stddev = np.sqrt(2.0 / hidden_cur_cnt)
    weights.append(tf.Variable(tf.truncated_normal([hidden_cur_cnt, hidden_next_cnt], stddev=hidden_stddev)))
    biases.append(tf.Variable(tf.zeros([hidden_next_cnt])))
    hidden_cur_cnt = hidden_next_cnt
  • 第一次测试时,用正太分布设置所有W的数值,将标准差设置为1,由于网络增加了一层,寻找step调整方向时具有更大的不确定性,很容易导致loss变得很大
  • 因此需要用stddev调整其标准差到一个较小的范围(怎么调整有许多研究,这里直接找了一个来用)

python stddev = np.sqrt(2.0 / n)

  • 启用regular时,也要适当调一下β,不要让它对原本的loss造成过大的影响
  • DropOut时,因为后面的layer得到的信息越重要,需要动态调整丢弃的比例,到后面的layer,丢弃的比例要减小

    keep_prob += 0.5 * i / (layer_cnt + 1)
  • 训练时,调节参数,你可能遇到消失(或爆炸)的梯度问题
    训练到一定程度后,梯度优化器没有什么作用,loss和准确率总是在一定范围内徘徊
  • 官方教程表示最好的训练结果是,准确率97.5%,
  • 我的nn_overfit.py开启六层神经网络,
    启用Regularization、DropOut、Learning Rate Decay,
    训练次数20000(应该还有再训练的希望,在这里虽然loss下降很慢了,但仍然在下降),训练结果是,准确率95.2%

觉得我的文章对您有帮助的话,给个star可好?

TensorFlow实现与优化深度神经网络的更多相关文章

  1. TensorFlow 深度学习笔记 TensorFlow实现与优化深度神经网络

    转载请注明作者:梦里风林 Github工程地址:https://github.com/ahangchen/GDLnotes 欢迎star,有问题可以到Issue区讨论 官方教程地址 视频/字幕下载 全 ...

  2. 优化深度神经网络(三)Batch Normalization

    Coursera吴恩达<优化深度神经网络>课程笔记(3)-- 超参数调试.Batch正则化和编程框架 1. Tuning Process 深度神经网络需要调试的超参数(Hyperparam ...

  3. 优化深度神经网络(一) dropout 初始化

    Coursera吴恩达<优化深度神经网络>课程笔记(1)-- 深度学习的实用层面 1. Train/Dev/Test sets  训练集(Training sets).验证集(Develo ...

  4. 优化深度神经网络(二)优化算法 SGD Momentum RMSprop Adam

    Coursera吴恩达<优化深度神经网络>课程笔记(2)-- 优化算法 深度机器学习中的batch的大小 深度机器学习中的batch的大小对学习效果有何影响? 1. Mini-batch ...

  5. Batch Normalization原理及其TensorFlow实现——为了减少深度神经网络中的internal covariate shift,论文中提出了Batch Normalization算法,首先是对”每一层“的输入做一个Batch Normalization 变换

    批标准化(Bactch Normalization,BN)是为了克服神经网络加深导致难以训练而诞生的,随着神经网络深度加深,训练起来就会越来越困难,收敛速度回很慢,常常会导致梯度弥散问题(Vanish ...

  6. 代码详解:TensorFlow Core带你探索深度神经网络“黑匣子”

    来源商业新知网,原标题:代码详解:TensorFlow Core带你探索深度神经网络“黑匣子” 想学TensorFlow?先从低阶API开始吧~某种程度而言,它能够帮助我们更好地理解Tensorflo ...

  7. TensorFlow之CNN:运用Batch Norm、Dropout和早停优化卷积神经网络

    学卷积神经网络的理论的时候,我觉得自己看懂了,可是到了用代码来搭建一个卷积神经网络时,我发现自己有太多模糊的地方.这次还是基于MINIST数据集搭建一个卷积神经网络,首先给出一个基本的模型,然后再用B ...

  8. 最大似然估计 (Maximum Likelihood Estimation), 交叉熵 (Cross Entropy) 与深度神经网络

    最近在看深度学习的"花书" (也就是Ian Goodfellow那本了),第五章机器学习基础部分的解释很精华,对比PRML少了很多复杂的推理,比较适合闲暇的时候翻开看看.今天准备写 ...

  9. Keras入门(一)搭建深度神经网络(DNN)解决多分类问题

    Keras介绍   Keras是一个开源的高层神经网络API,由纯Python编写而成,其后端可以基于Tensorflow.Theano.MXNet以及CNTK.Keras 为支持快速实验而生,能够把 ...

随机推荐

  1. CentOS6.5 下在Nginx中添加SSL证书以支持HTTPS协议访问

    参考文献: 1. NginxV1.8.0安装与配置 2. CentOS下在Nginx中添加SSL证书以支持HTTPS协议访问 3. nginx配置ssl证书的方法 4.nginx强制使用https访问 ...

  2. 我的Python成长之路---第三天---Python基础(10)---2016年1月16日(雾霾)

    二.collections collections是对Python现有的数据类型的补充,在使用collections中的对象要先导入import collections模块 1.Counter——计数 ...

  3. Get与POST的理解

    针对GET& POST的掌握可以说是迷迷糊糊的,今天特意拿出来好好整理一下,便于掌握理解. 在服务器端都有一个用来标识资源位置的符号,被称为统一资源标识(URL). URI有两种形式.分别为U ...

  4. POJ 2479 不相交最大子段和

    题目意思还是很好理解的,在一个数列中,找出不相交的两个子串使得其和最大. 解题思路: 对于每个i来说,求出[0 ~ i - 1] 的最大子段和以及[i ~ n - 1]的最大子段和,在加起来,求最大的 ...

  5. 手势滑动结束 Activity(一)基本功能的实现

    喜欢听音乐的朋友可能都看过天天动听这款 app, 这款 app 有一个亮点就是在切换页面(Fragment)的时候能够通过手势滑动来结束当前页面.这里先说一下,我为什么会这么关心这个功能呢,由于前两天 ...

  6. GUI动态创建button

    #include "cocos2d.h" #include "cocos-ext.h" USING_NS_CC; USING_NS_CC_EXT; using ...

  7. 浅尝key-value数据库(一)——一览NoSQL

    浅尝key-value数据库(一)——一览NoSQL 最近由于一个项目的关系,研究了一下key-value数据库这个最近很火的概念.本系列从项目需求的角度分析并测试了几个key-value数据库的性能 ...

  8. html5游戏开发--"动静"结合用地图块拼成大地图 & 初探lufyl

    一.前言   本次教程将向大家讲解如何用html5将小地图块拼成大地图,以及如何用现有的高级html5游戏开发库件lufylegend.js开发游戏.   首先让我们来了解了解如何用html5实现动画 ...

  9. CentOS: make menuconfig error: curses.h: No such file or directory

    the problem  when use centos5 to build kernel or busybox step 1. Centos中关于 ncurses.h:no such file or ...

  10. spark集群安装配置

    spark集群安装配置 一. Spark简介 Spark是一个通用的并行计算框架,由UCBerkeley的AMP实验室开发.Spark基于map reduce 算法模式实现的分布式计算,拥有Hadoo ...