最近在学习 Hands-On Mathine Learning with Scikit_learn & TensorFlow,所以资料代码来源于本书chaper 10
学习这本书的好处在于都是讲基础,但是本书给了一个完整的设计流程,其中包含很多参考文献。
下面先上代码,
1、导入TensorFlow和加载数据集
import tensorflow as tf
import numpy as np
from tensorflow.examples.tutorials.mnist import input_data
#加载MNIST数据集
mnist = input_data.read_data_sets("./data/MNIST_data/", one_hot=True)
2、模型参数
输入层:简单来说就是一维的28*28的输入
第二层:300个神经元
第三层:100个神经元
最后一层:10个神经元(识别的0-9)
epochs:运行次数
batch_size:每次选多少数据
#输入,输出
INPUT_NODE = 28*28
OUTPUT_NODE = 10
n_hidden1 = 300
n_hidden2 =100
# 模型相关的参数
n_epochs=400
batch_size=20
3、神经网络层建立
input_tensor:该层输入数据
n_neurons:该层神经元输出
activation:激活函数(relu,elu或者None,利用softmax最后一层不需要激活函数)
当然也可以用 leaky relu等激活函数
例如:定义一个leaky relu函数
def leaky_relu(z,name=None):
return tf.maximum(0.01*z,z,name=name)
关于激活函数的内容可参考这篇文章:Bing Xu(2015) Empirical Evaluation of Rectified Activations in Convolution Network
elu 参考:FAST AND ACCURATE DEEP NETWORK LEARNING BY EXPONENTIAL LINEAR UNITS (ELUS)
- 权重的初始化
首先训练深度神经网络会有梯度消失和爆炸的问题,参见这篇博客。简而言之,不同层的梯度相差比较大,梯度消失可能使结果不会收敛到一个比较好的解。梯度爆炸则会引起算法发散。
最开始Glorot and Bengio(2010)研究了一些激活函数和初始化,提出一种方法来减轻这个问题。这篇文章主要通过监控训练时候的激活函数和梯度来评估激活函数和初始化的有效性。
论文中的策略和问题分析:首先采用均匀分布,
如下图(统计的激活函数的均值和标准差),刚开始训练的时候,第四层激活函数(sigmoid)的值很快趋于0,而前面几层在0.5附近波动,这种情况持续很长时间,在100个epoch后,最后一层缓慢上升,前面几层开始下降,最后都趋于一个稳定的状态。
作者认为为了保证为了正向和反向信号流动的合理,应该保证输入和输出的方差相等,同样对于梯度也是。但是,实际中输入和输出的数量不相等,方差不会相等,因此作者提出一个折中的策略,
ni
和
ni+1
是输入输出层的输入输出个数。
如图所示:对于该层网络权重初始化结合输入输出个数,设置方差为前后两层神经元数量的平均值的倒数。
前面的均匀分布
U[−1n√,1n√]
的初始化的方差
Var[W]=4n12=13n
.
因此,提出均与分布normalized initialization:
U[−6√nj+nj+1√,6√nj+nj+1√]
,这个均匀分布的方差刚好是
2nj+nj+1
上面这种初始化的方式针对于sigmoid激活函数,当然对于Relu/PRelu等激活函数在层数更深的时候并不一定好用。Kaiming 大神(2015)利用权重初始化方差为
Var[W]=2ni
在深层网络得到效果比上面的好。这篇文章详解参考这篇csdn blog.
每层网络定义代码如下:
def neurom_layer(input_tensor, n_neurons, name, activation=None):
with tf.name_scope(name):
n_inputs=int(input_tensor.get_shape()[1])
stddev=2/np.sqrt(n_inputs)
init=tf.truncated_normal((n_inputs, n_neurons), stddev)
W=tf.Variable(init,name="weigths")
b=tf.Variable(tf.zeros([n_neurons]),name="biases")
z=tf.matmul(input_tensor,W)+b
if activation=="relu":
return tf.nn.relu(z)
else:
return z
- 训练的主函数
def train(mnist):
首先构建网络:
x = tf.placeholder(tf.float32, [None, INPUT_NODE], name='x-input')
y = tf.placeholder(tf.float32, [None,OUTPUT_NODE], name='y-input')
with tf.name_scope("dnn"):
hidden1= neurom_layer(x,n_hidden1,"n_hidden1",activation="relu")
hidden2= neurom_layer(hidden1,n_hidden2,"n_hidden2",activation="relu")
logits = neurom_layer(hidden2,OUTPUT_NODE,"outputs")
计算交叉熵:
# 计算交叉熵及其平均值
cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(labels=tf.argmax(y,1),logits=logits)
loss = tf.reduce_mean(cross_entropy,name="loss")
设置学习率:
learning_rate = 0.01;
# 也可以设置指数衰减的学习率,不过参数需要配置。
#learning_rate = tf.train.exponential_decay(
# LEARNING_RATE_BASE,
# global_step,
# mnist.train.num_examples / BATCH_SIZE,
# LEARNING_RATE_DECAY,
# staircase=True)
下面采用随机梯度下降来进行训练:贴一个最优化方法总结最优化深度学习最全优化方法总结比较
# 随机梯度下降优化器优化损失函数,反向传播更新参数
train_op = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss)#, global_step=global_step)
然后计算准确度,这里的logits是个1维包含是个数的向量,tf.nn.in_top_k则是判断是否softmax输出的最大值跟输入匹配。
# 计算准确度
with tf.name_scope("eval"):
correct_prediction = tf.nn.in_top_k(logits,tf.argmax(y,1),1)
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
训练过程:
# 初始化会话并开始训练过程。
with tf.Session() as sess:
tf.global_variables_initializer().run()
test_feed = {x: mnist.test.images, y: mnist.test.labels}
for epoch in range(n_epochs):
for iteration in range(batch_size):
xs,ys=mnist.train.next_batch(batch_size)
sess.run(train_op,feed_dict={x:xs,y:ys})
acc_train=accuracy.eval(feed_dict={x:xs,y:ys})
test_train=accuracy.eval(feed_dict={x: mnist.test.images, y: mnist.test.labels})
if epoch%10 == 0:
print(epoch,"train accuracy:",acc_train,"Test accuracy",test_train)
#训练
train(mnist)
4、模型训练总结与注意事项
本书总结了深度模型构建和训练时候的一些关注点。如下:
1. 权重初始化
2. 激活函数选择
3. Batch Normalization 出自:Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift。 同样是为了避免梯度消失和爆炸问题,跟权重初始化作用一样,在每层训练的之前,将每个隐藏层输出结果在batch上也进行标准化后再送入下一层。(参考知乎话题:深度学习中 Batch Normalization为什么效果好?)。
4. 重用网络预训练 或迁移学习
5. 优化策略的选取
6. 避免过拟合:(early Stopping,L1,L2,Dropout,Max-Norm regularization,data Augmentation)
(注:以上仅个人观点)
参考Hands-On Mathine Learning with Scikit_learn & TensorFlow
[1]Glorot and Bengio(2010):Understanding the difficulty of training deep feedforward neural networks
[2]Kaiming He(2015):Delving Deep into Rectifiers: Surpassing Human-Level Performance on ImageNet Classification