tensorflow提供了三种不同的加速神经网路训练的并行计算模式
(一)数据并行:
(二)模型并行:
(三)流水线并行:
主流深度学习框架对比(2017):
第一章
Tensorflow实现Softmax Regression识别手写数字
数据集:28x28像素的手写数字组成。
1.在导入mnist 数据集时,会碰到一系列的问题,在这里做一些简要的说明:
(1)导入数据集时报错如下:(图是别地找的,但报错信息就是这样)
碰到这种情况,直接在官网上下载数据集,不用解压,将存放数据集的路径添加到数据读取函数中,就可以解决,具体见后面的代码:
(2)由于我之前用的是cpu版本的tensorflow,在做mnist实验时没有遇到这种情况,后来更换为gpu版本的时,在读取数据时会报错, 具体信息是:SymbolDatabase has no attribute RegisterServiceDescriptor(图是别地找的,但报错信息就是这样)
百度了一下发现解决的方案很少,也没有提供有价值的信息, 最后在github上这里找到了一些信息。看大家的讨论大致意思是由于protobuf版本的问题,打开pycharm的interpreter:
有一个3.2.0版本的protobuf.
怎么会同时从在两个版本的protobuf,我好想知道为什么了
问题解决了。
继续我的mnist手写字体识别。。。。。。。。用一个没有隐含层的神经网络实现mnist手写字体识别。
重点:理解softmax regression
在处理多分类问题时,通常需要使用softmax regression模型,它的工作原理是:将可以判断为某类的特征相加,
然后将这写特征转换为判定是这一类的概率。具体的原理及数学推导可参考这篇博客。
2.理解交叉熵损失函数:
cross-entropy的定义如下:

现在有了损失函数定义,现在再定义一个优化算法,就可以对模型进行训练:
常见的优化算法有随机梯度下降。
完整代码:
import tensorflow as tf from tensorflow.examples.tutorials.mnist import input_data mnist_data_path = r'E:\code\112\tensorflow_project\chapter5\data\tensorflow_data' mnist = input_data.read_data_sets(mnist_data_path, one_hot=True) input_nodes = 28 * 28 out_nodes = 10 x = tf.placeholder(dtype=tf.float32, shape=[None, input_nodes], name='x-input') y_ = tf.placeholder(dtype=tf.float32, shape=[None, out_nodes], name='y-input') # 定义权重矩阵 w = tf.Variable(initial_value=tf.random_normal(shape=[input_nodes, out_nodes], mean=0, stddev=0.1), dtype=tf.float32, trainable=True) b = tf.Variable(initial_value=tf.zeros([10]), dtype=tf.float32, trainable=True) output = tf.matmul(x, w) + b y = tf.nn.softmax(output) # 定义一个loss function来描述模型对分类问题的分类精度 cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(y))) train_step = tf.train.GradientDescentOptimizer(learning_rate=0.5).minimize(cross_entropy) correction_prediction = tf.equal(tf.argmax(y, axis=1), tf.argmax(y_, axis=1)) accuracy = tf.reduce_mean(tf.cast(correction_prediction, tf.float32)) with tf.Session() as sess: init_op = tf.initialize_all_variables() sess.run(init_op) for i in range(1000): # 每次训练都从数据集中随机抽取一百个数据,构成一个mini-batch,对神经网络进行训练 # 使用一小部分样本进行训练称为随机梯度下降(SGD),如果每次训练都使用全部样本,计算量大,而且也不容易跳出局部最优。 # 使用随机梯度下降可以得到更快的收敛速度 batch_x, batch_y = mnist.train.next_batch(100) sess.run(train_step, feed_dict={x: batch_x, y_: batch_y}) # print(i) if i % 10 == 0: accuracy_result = sess.run(accuracy, feed_dict={x: mnist.test.images, y_: mnist.test.labels}) print('After {} iterations the accuracy is {} .'.format(i, accuracy_result))
运行结果:
通过上面的例子,实现了一个非常简单的softmax regression算法
下面对之前的程序进行一些改进:对神经网络添加隐藏层, 隐藏层的节点数为500,同时对神经网络参数的更新采用滑动均值模型,采用指数衰减的学习率。
(1)关于滑动均值模型:在网络的训练中采用滑动均值模型,在测试中不使用。滑动均值模型与一阶滞后滤波具有相似性,一阶滞后滤波具体表达式为:
a的取值范围为[0, 1].
本次采样值+a上次滤波结果,
采用此算法的优点是:
1、降低周期性的干扰;
2、在波动频率较高的场合有很好的效果。
tf.train.ExponentialMovingAverage
来实现滑动平均模型,在采用随机梯度下降算法训练神经网络时,使用其可以提高模型在测试数据上的鲁棒性(robustness)。TensorFlow下的 tf.train.ExponentialMovingAverage
需要提供一个衰减率参数decay。该衰减率用于控制模型更新的速度。ExponentialMovingAverage 对每一个待更新的变量(variable)都会维护一个影子变量(shadow variable)。影子变量的初始值就是这个变量的初始值:
上述公式与之前介绍的一阶滞后滤波法的公式相比较,会发现有很多相似的地方,从名字上面也可以很好的理解这个算法的原理:平滑、滤波,即使数据平滑变化,通过调整参数来调整变化的稳定性。
在滑动平滑模型中, decay 决定了模型更新的速度,越大越趋于稳定。实际运用中,decay 一般会设置为十分接近 1 的常数(0.999或0.9999)。为了使得模型在训练的初始阶段更新得更快,ExponentialMovingAverage 还提供了 num_updates 参数来动态设置 decay 的大小:
关于滑动平均模型参考了这篇博客,作者表达的很清楚,引用一下
(2)在模型中添加正则化:通过正则化,能够将表征模型复杂度的指标加入到损失函数中。
regularizer_L2 = tf.contrib.layers.l2_regularizer(regularizer_rate) loss_function = cross_entropy_mean + regularizer_L2(weight_1) + regularizer_L2(weight_2)
(3)指数衰减学习率:
在训练模型的时候,通常会遇到这种情况:我们平衡模型的训练速度和损失(loss)后选择了相对合适的学习率(learning rate),但是训练集的损失下降到一定的程度后就不在下降了,比如training loss一直在0.8和0.9之间来回震荡,不能进一步下降。如下图所示:
遇到这种情况通常可以通过适当降低学习率(learning rate)来实现。但是,降低学习率又会延长训练所需的时间。
学习率衰减(learning rate decay)就是一种可以平衡这两者之间矛盾的解决方案。学习率衰减的基本思想是:学习率随着训练的进行逐渐衰减。
学习率衰减基本有两种实现方法:
- 线性衰减。例如:每过5个epochs学习率减半
- 指数衰减。例如:每过5个epochs将学习率乘以0.1
我采用的是指数衰减的方法:
采用指数衰减必须初始化一个初始的学习率,以及一个衰减的速率。
计算的公式为:
decayed_learning_rate = learning_rate * decay_rate^(global_step/decay_steps)
其中:
同时将神经网络的前向传播过程结构化:通过inference函数来表示
再通过定义train()函数来训练神经网络:
程序的运行结果如下所示:
后面持续更行,会添加模型保存以及调用tensorboard的部分程序。。。