http://scs.ryerson.ca/~aharley/vis/conv/ 很炫酷的一个手写识别网站
卷积神经网络(CNN)是深度学习一个特殊示例,在计算机视觉上有着非常重要的影响。
CNN的一个典型特性就是输入的基本上全是图片,这可以有很搞笑的实现并减少需要的参数。
读入MNIST数据并定义placeholder后:
import tensorflow as tf
import tensorflow.examples.tutorials.mnist.input_data as input_data
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True) #下载并加载mnist数据
x = tf.placeholder(tf.float32, [None, 784]) #输入的数据占位符
y_actual = tf.placeholder(tf.float32, shape=[None, 10]) #输入的标签占位符
定义四个函数,分别用于初始化权值W,初始化偏置项b, 构建卷积层和构建池化层。
#定义一个函数,用于初始化所有的权值 W
def weight_variable(shape):
initial = tf.truncated_normal(shape, stddev=0.1)
return tf.Variable(initial)
#定义一个函数,用于初始化所有的偏置项 b
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(x):
return tf.nn.max_pool(x, ksize=[1, 2, 2, 1],strides=[1, 2, 2, 1], padding='SAME')
定义卷积神经网络有两个基本概念:filter与characteristic maps。
卷积层的主要目的就是为了检测图像中的特性或可见性,如边缘、线,块,颜色等等,这些都是由隐藏层负责的,
它们会与输入层相连接,在CNN中,输入数据平不是与隐藏层中的神经元全连接,而只是很小的包含图片像素值
的局部控件相连。
在本例子中,隐藏层的每一个神经元是与输入层中5*5(25个神经元)小区域相连接。
对于我们描述的卷积层,经常在卷积层后面加一个池化层,池化层简单的浓缩卷积层的输出结果并创建一个压缩
版本的信息并输出,max-pooling这种方法中通过保留2*2区域中的最大值来压缩信息。
接下来构建网络。整个网络由两个卷积层(包含激活层和池化层),一个全连接层,一个dropout层和一个softmax层组成。
#构建网络
x_image = tf.reshape(x, [-1,28,28,1]) #转换输入数据shape,以便于用于网络中
在这里我们把shape转换成了4D tensor,第二与第三唯独对应的是照片的宽度与高度,最后一个维度是颜色通道数,
阶 形状 维数 实例
0 [ ] 0-D 一个 0维张量. 一个纯量.
1 [D0] 1-D 一个1维张量的形式[5].
2 [D0, D1] 2-D 一个2维张量的形式[3, 4].
3 [D0, D1, D2] 3-D 一个3维张量的形式 [1, 4, 3].
n [D0, D1, ... Dn] n-D 一个n维张量的形式 [D0, D1, ... Dn].
W_conv1 = weight_variable([5, 5, 1, 32])
b_conv1 = bias_variable([32])
h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1) #第一个卷积层
h_pool1 = max_pool(h_conv1) #第一个池化层
实现第一层卷积与池化层,使用32个filters,每一个都有一个大小为5*5的窗口,shape【5,5,1,32】的权重矩阵W,前两个是窗口的大小,第三个是channel的数量,最后一个定义我们想使用多少个特征,
ReLU(Rectified Linear unit)激活函数最近变成了神经网络中隐藏层的默认激活函数。这个简单的函数包含了返回max(0,x),所以对于负值,它会返回0,其它返回x。在我们的例子中,我们会在卷积层后的隐藏层中使用这个激活函数。
当构建一个深度神经网络时,可以相互叠加很多层。为演示如何做到这样,我会创建64个filters且窗口大小为5*5的第二层卷积层。此时我们会需传递32个channels,因为这是前一层的输出结果:
W_fc1 = weight_variable([7 * 7 * 64, 1024])
b_fc1 = bias_variable([1024])
h_pool2_flat = tf.reshape(h_pool2, [-1, 7*7*64]) #reshape成向量
h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, W_fc1) + b_fc1) #第一个全连接层
tensor的第一维度表示第二层卷积层的输出,大小为7*7带有64个filters,第二个参数是层中的神经元数量,我们可自由设置。
接下来,我们将tensor打平到vector中。我们在之前章节中已经看到softmax需要将图片打平成一个vector任为输入。通过打平后的vector乘以权重矩阵W_fc1,
再加上bias b_fc1,最后应用ReLU激活函数后就能实现
keep_prob = tf.placeholder("float")
h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob) #dropout层
根据给出的keep_prob参数,将输入tensor x按比例输出。x : 输入tensor
keep_prob : float类型,每个元素被保留下来的概率
W_fc2 = weight_variable([1024, 10])
b_fc2 = bias_variable([10])
y_predict=tf.nn.softmax(tf.matmul(h_fc1_drop, W_fc2) + b_fc2) #softmax层
最后在模型中添加softmax层,softmax函数返回输入属于每一个分类的概率且概率的综合为1
网络构建好后,就可以开始训练了。
cross_entropy = -tf.reduce_sum(y_actual*tf.log(y_predict)) #交叉熵
train_step = tf.train.GradientDescentOptimizer(1e-3).minimize(cross_entropy) #梯度下降法
correct_prediction = tf.equal(tf.argmax(y_predict,1), tf.argmax(y_actual,1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float")) #精确度计算
sess=tf.InteractiveSession()
sess.run(tf.initialize_all_variables())
for i in range(20000):
batch = mnist.train.next_batch(50)
if i%100 == 0: #训练100次,验证一次
train_acc = accuracy.eval(feed_dict={x:batch[0], y_actual: batch[1], keep_prob: 1.0})
print 'step %d, training accuracy %g'%(i,train_acc)
train_step.run(feed_dict={x: batch[0], y_actual: batch[1], keep_prob: 0.5})
test_acc=accuracy.eval(feed_dict={x: mnist.test.images, y_actual: mnist.test.labels, keep_prob: 1.0})
print "test accuracy %g"%test_acc
Tensorflow依赖于一个高效的C++后端来进行计算。与后端的这个连接叫做session。一般而言,使用TensorFlow程序的流程是先创建一个图,然后在session中启动它。
这里,我们使用更加方便的InteractiveSession
类。通过它,你可以更加灵活地构建你的代码。它能让你在运行图的时候,插入一些计算图,这些计算图是由某些操作(operations)构成的。这对于工作在交互式环境中的人们来说非常便利,比如使用IPython。