(1) 真正使程序运行起来的是 :train_step.run(feed_dict={x: batch[0], y_: batch[1]})
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("F:/MNIST_data/MNIST_data/", one_hot=True)
import tensorflow as tf
sess = tf.InteractiveSession()
x = tf.placeholder("float", shape=[None, 784])
y_ = tf.placeholder("float", shape=[None, 10])
W = tf.Variable(tf.zeros([784,10]))
b = tf.Variable(tf.zeros([10]))
sess.run(tf.initialize_all_variables())
y = tf.nn.softmax(tf.matmul(x,W) + b)
cross_entropy = -tf.reduce_sum(y_*tf.log(y))
train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)
for i in range(1000):
batch = mnist.train.next_batch(50)
train_step.run(feed_dict={x: batch[0], y_: batch[1]})
correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(y_,1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
print (accuracy.eval(feed_dict={x: mnist.test.images, y_: mnist.test.labels}))
(2)为什么relu比sigmoid好?
1 .在多层神经网络中,sigmoid求梯度的代价过大;
2. sigmoid在深层神经网络中,容易出现梯度消失的现在,就是前面几层的梯度变化几乎为0;
3. relu可以使部分神经元失活,防止过拟合
第一个问题:为什么引入非线性激励函数?
如果不用激励函数(其实相当于激励函数是f(x) = x),在这种情况下你每一层输出都是上层输入的线性函数,很容易验证,无论你神经网络有多少层,输出都是输入的线性组合,与只有一个隐藏层效果相当,这种情况就是多层感知机(MLP)了。
正因为上面的原因,我们决定引入非线性函数作为激励函数,这样深层神经网络就有意义了(不再是输入的线性组合,可以逼近任意函数)。最早的想法是sigmoid函数或者tanh函数,输出有界,很容易充当下一层输入(以及一些人的生物解释balabala)。
第二个问题:为什么引入Relu呢?
第一,采用sigmoid等函数,反向传播求误差梯度时,求导计算量很大,而Relu求导非常容易。
第二,对于深层网络,sigmoid函数反向传播时,很容易就会出现梯度消失的情况(在sigmoid接近饱和区时,变换太缓慢,导数趋于0),从而无法完成深层网络的训练。
第三,Relu会使一部分神经元的输出为0,这样就造成了网络的稀疏性,并且减少了参数的相互依存关系,缓解了过拟合问题的发生(以及一些人的生物解释balabala)。
首先,我们使用mnist数据库做个测试,建立一个10层的神经网络,每层的平均梯度幅度如下:
epoch:1 iteration:10/300
3.23e-07 8.3215e-07 3.3605e-06 1.5193e-05 6.4892e-05 0.00027249 0.0011954 0.006295 0.029835 0.12476 0.38948
epoch:1 iteration:20/300
4.4649e-07 1.3282e-06 5.6753e-06 2.5294e-05 0.00010326 0.00043651 0.0019583 0.0096396 0.040469 0.16142 0.5235
可以看到,最开始的几层只有1e-6到1e-7这个量级的梯度,基本上梯度在最后3层就已经饱和了。使用SGD等算法的话,前边几层的参数在梯度下降的时候几乎没有得到改变,自始至终都是随机值。
而使用ReLU呢:
epoch:1 iteration:10/300
0.68193 0.47672 0.48507 0.48 0.49133 0.47511 0.45136 0.48241 0.50238 0.62887 3.7748
epoch:1 iteration:20/300
0.49834 0.3182 0.26373 0.23835 0.23295 0.2293 0.2558 0.27504 0.29768 0.36264 0.51806
可以看到,梯度的scale几乎没什么变化。
最近Google的论文Batch Normalization[1]解决了sigmoid的saturate问题,但效果仍然没有ReLU好,证明ReLU至少在图像分类问题上是比sigmoid更接近本质的,至于这个本质是什么,现在还不得而知。
是因为 上边说的稀疏性吗?MSRA的论文Parametric ReLU[2]否定了这个说法,非稀疏的激活函数能得到更好的效果。所以,这个问题只能等大神们的进一步分析了。
(3)关于维度和squeeze的问题:
import tensorflow as tf
raw = tf.Variable([[[[2,6],[2,3]]]])
squeezed = tf.squeeze(raw,1)
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print(raw.shape)
print('-----------------------------')
print(sess.run(squeezed).shape)
print(sess.run(squeezed))
例如此时,raw的shape是:1*1*2*2,外部有几个框就是几个维度,这个2前面有4个【,所以维度为4,又因为[2,6]跟其中的2同地位的是6,所以是_*_*_*2,而跟[2,6]同地位的是[2,3],所以是_*_*2*2;
squeeze是删除指定位置的维度,并且该位置必须是1才能被删;
(4)
def conv2d(x, W):
return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='SAME')
在学习tensorflow看到卷积这部分时,不明白这里的4个参数是什么意思,文档里面也没有具体说明。strides在官方定义中是一个一维具有四个元素的张量,其规定前后必须为1,所以我们可以改的是中间两个数,中间两个数分别代表了水平滑动和垂直滑动步长值。
在卷积核移动逐渐扫描整体图时候,因为步长的设置问题,可能导致剩下未扫描的空间不足以提供给卷积核的,大小扫描 比如有图大小为5*5,卷积核为2*2,步长为2,卷积核扫描了两次后,剩下一个元素,不够卷积核扫描了,这个时候就在后面补零,补完后满足卷积核的扫描,这种方式就是same。如果说把刚才不足以扫描的元素位置抛弃掉,就是valid方式。
(5)
def max_pool_2x2(x):
return tf.nn.max_pool(x, ksize=[1, 2, 2, 1],
strides=[1, 2, 2, 1], padding='SAME')
本例采用的是最大值池化tf.max_pool()。池化的核函数大小为2x2,因此ksize=[1,2,2,1],步长为2,因此strides=[1,2,2,1]:
(5)
W_conv1 = weight_variable([5, 5, 1, 32])
。卷积在每个5x5的patch中算出32个特征。卷积的权重张量形状是[5, 5, 1, 32],前两个维度是patch的大小,接着是输入的通道数目,最后是输出的通道数目。
x_image = tf.reshape(x, [-1,28,28,1])
把x变成一个4d向量,其第2、第3维对应图片的宽、高,最后一维代表图片的颜色通道数(因为是灰度图所以这里的通道数为1,如果是rgb彩色图,则为3)。
# -*- coding: utf-8 -*-
"""
Created on Thu Aug 9 09:34:58 2018
@author: Administrator
"""
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("F:/MNIST_data/MNIST_data/", one_hot=True)
import tensorflow as tf
sess = tf.InteractiveSession()
x = tf.placeholder("float", shape=[None, 784])
y_ = tf.placeholder("float", shape=[None, 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 conv2d(x, W):
return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='SAME')
def max_pool_2x2(x):
return tf.nn.max_pool(x, ksize=[1, 2, 2, 1],
strides=[1, 2, 2, 1], padding='SAME')
W_conv1 = weight_variable([5, 5, 1, 32])
b_conv1 = bias_variable([32])
x_image = tf.reshape(x, [-1,28,28,1])
h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)
h_pool1 = max_pool_2x2(h_conv1)
W_conv2 = weight_variable([5, 5, 32, 64])
b_conv2 = bias_variable([64])
h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2)
h_pool2 = max_pool_2x2(h_conv2)
W_fc1 = weight_variable([7 * 7 * 64, 1024])
b_fc1 = bias_variable([1024])
h_pool2_flat = tf.reshape(h_pool2, [-1, 7*7*64])
h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, W_fc1) + b_fc1)
keep_prob = tf.placeholder("float")
h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)
W_fc2 = weight_variable([1024, 10])
b_fc2 = bias_variable([10])
y_conv=tf.nn.softmax(tf.matmul(h_fc1_drop, W_fc2) + b_fc2)
cross_entropy = -tf.reduce_sum(y_*tf.log(y_conv))
train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)
correct_prediction = tf.equal(tf.argmax(y_conv,1), tf.argmax(y_,1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
sess.run(tf.initialize_all_variables())
for i in range(2000):
batch = mnist.train.next_batch(50)
if i%100 == 0:
train_accuracy = accuracy.eval(feed_dict={
x:batch[0], y_: batch[1], keep_prob: 1.0})
print ("step %d, training accuracy %g"%(i, train_accuracy))
train_step.run(feed_dict={x: batch[0], y_: batch[1], keep_prob: 0.5})
print ("test accuracy %g"%accuracy.eval(feed_dict={
x: mnist.test.images, y_: mnist.test.labels, keep_prob: 1.0}))