实现与优化深度神经网络

全连接神经网络

辅助阅读:TensorFlow中文社区教程 - 英文官方教程(http://www.tensorfly.cn/tfdoc/tutorials/mnist_tf.html)

Linear Model

加载lesson 1(https://github.com/ahangchen/GDLnotes/blob/master/note/lesson-1/practical.md)中的数据集将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()创建一个计算单元。

上面这些变量都是一种Tensor的概念,它们是一个个的计算单元,我们在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。

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次,提高其准确度,这样训练的准确度为83.2%,为了快速查看训练效果,每轮训练只给10000个训练数据(subset),恩,每次都是相同的训练数据,将计算单元graph传给session。

初始化参数

传给session优化器 - train_loss的梯度optimizer,训练损失 - train_loss,每次的预测结果,循环执行训练。

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次循环后,会用验证集进行验证一次,验证也同时修正了一部分参数。

valid_prediction.eval()

最后用测试集进行测试。

注意如果lesson 1中没有对数据进行乱序化,可能训练集预测准确度很高,验证集和测试集准确度会很低。

这样训练的准确度为83.2%

SGD

每次只取一小部分数据做训练,计算loss时,也只取一小部分数据计算loss,准确率提高到86.5%,而且准确率随训练次数增加而提高的速度变快了,每次输入的训练数据只有128个,随机取起点,取连续128个数据。

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来存放这块空间。

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少。

神经网络

上面SGD的模型只有一层WX+b,现在使用一个RELU作为中间的隐藏层,连接两个WX+b,仍然只需要修改Graph计算单元为:

Y = W2 * RELU(W1*X + b1) + b2

为了在数学上满足矩阵运算,我们需要这样的矩阵运算:

[n * 10] = RELU([n * 784] · [784 * N] + [n * N]) · [N * 10] + [n * 10]

这里N取1024,即1024个隐藏结点,于是四个参数被修改:

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]))

预测值计算方法改为:

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

(https://github.com/ahangchen/GDLnotes/blob/master/src/neural/nn_overfit.py)

优化

Regularization

在前面实现的RELU连接的两层神经网络(https://github.com/ahangchen/GDLnotes/blob/master/src/neural/full_connect.py)中,加Regularization进行约束,采用加l2 norm的方法,进行调节:

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

可以用tf.nn.l2_loss(t)对一个Tensor对象求l2 norm。

需要对我们使用的各个W都做这样的计算(参考tensorflow官方example

(https://github.com/tensorflow/tensorflow/blob/master/tensorflow/models/image/mnist/convolutional.py))

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使之降到同一个量级。

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 = 1000offset = (step * batch_size) % offset_range

可以看到,在step500后,训练集就一直是100%,验证集一直是77.6%,准确度无法随训练次数上升,最后的测试准确度是85.4%。

DropOut

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

参考aymericdamien/TensorFlow-Examples(https://github.com/aymericdamien/TensorFlow-Examples/blob/master/examples/3%20-%20Neural%20Networks/alexnet.py)中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方法,指数下降调整步长,具体使用方法官方文档(https://www.tensorflow.org/versions/r0.8/api_docs/python/train.html#exponential_decay)说的特别清楚。

注意这里面的cur_step传给优化器,优化器在训练中对其做自增计数,与之前单纯两层神经网络对比,准确率直接提高到90.6%.

Deep Network

增加神经网络层数,增加训练次数到20000,为了避免修改网络层数需要重写代码,用循环实现中间层。

# middle layerfor 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_cntstddev = np.sqrt(2.0 / n)

第一次测试时,用正太分布设置所有W的数值,将标准差设置为1,由于网络增加了一层,寻找step调整方向时具有更大的不确定性,很容易导致loss变得很大.

因此需要用stddev调整其标准差到一个较小的范围(怎么调整有许多研究,这里直接找了一个来用)。

启用regular时,也要适当调一下β,不要让它对原本的loss造成过大的影响。

DropOut时,因为后面的layer得到的信息越重要,需要动态调整丢弃的比例,到后面的layer,丢弃的比例要减小。

keep_prob += 0.5 * i / (layer_cnt + 1)

训练时,调节参数,你可能遇到消失(或爆炸)的梯度问题(http://wiki.jikexueyuan.com/project/neural-networks-and-deep-learning-zh-cn/chapter5.html),

训练到一定程度后,梯度优化器没有什么作用,loss和准确率总是在一定范围内徘徊。

官方教程表示最好的训练结果是,准确率97.5%。

我的nn_overfit.py(https://github.com/ahangchen/GDLnotes/blob/master/src/neural/nn_overfit.py)开启六层神经网络,启用Regularization、DropOut、Learning Rate Decay,训练次数20000(应该还有再训练的希望,在这里虽然loss下降很慢了,但仍然在下降),训练结果是,准确率95.2%。

原文发布于微信公众号 - 人工智能LeadAI(atleadai)

原文发表时间:2017-11-10

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏量化投资与机器学习

深度学习Matlab工具箱代码注释之cnnsetup.m

%%========================================================================= %...

2625
来自专栏AI科技评论

干货 | 一篇文章教你用TensorFlow写名著

前言 最近看完了 LSTM 的一些外文资料,主要参考了 Colah 的 blog以及 Andrej Karpathy blog的一些关于 RNN 和 LST...

3618
来自专栏利炳根的专栏

学习笔记CB012: LSTM 简单实现、完整实现、torch、小说训练word2vec lstm机器人

LSTM(Long Short Tem Memory)特殊递归神经网络,神经元保存历史记忆,解决自然语言处理统计方法只能考虑最近n个词语而忽略更久前词语的问题。...

4376
来自专栏云时之间

Tensorflow 笔记:搭建神经网络

用张量表示数据,用计算图搭建神经网络,用会话执行计算图,优化线上的权重(参数),得到模型。

3975
来自专栏机器学习原理

机器学习(8)——其他聚类层次聚类画出原始数据的图小结

层次聚类 紧接上章,本章主要是介绍和K-Means算法思想不同而的其他聚类思想形成的聚类算法。 k-means算法却是一种方便好用的聚类算法,但是始终有K值选择...

3536
来自专栏大数据挖掘DT机器学习

R语言与分类算法-神经网络

人工神经网络(ANN)从以下四个方面去模拟人的智能行为: 物理结构:人工神经元将模拟生物神经元的功能 计算模拟:人脑的神经元有局部计算和存储的功能,通...

33810
来自专栏AI研习社

SSD: Single Shot MultiBox Detector 深度学习笔记之SSD物体检测模型

算法概述 本文提出的SSD算法是一种直接预测目标类别和bounding box的多目标检测算法。 与faster rcnn相比,该算法没有生成 propos...

5037
来自专栏专知

【Keras教程】用Encoder-Decoder模型自动撰写文本摘要

【导读】这篇博文介绍了如何在深度学习框架Keras上实现文本摘要问题,探讨了如何使用编码器-解码器递归神经网络体系结构来解决文本摘要问题,如何实现文本摘要问题的...

5385
来自专栏数据科学与人工智能

【数据挖掘】聚类算法总结

一、层次聚类 1、层次聚类的原理及分类 1)层次法(Hierarchicalmethods)先计算样本之间的距离。每次将距离最近的点合并到同一个类。然后,再计算...

4139
来自专栏求索之路

cs231n之SVM算法和SoftMax算法

1.环境搭建以及前置条件 1.前置环境: 1.mac 2.pycharm 3.python3 4.Anaconda 2.环境搭建: 1.官网下载并安装Ana...

2966

扫码关注云+社区