本文来自CNN 卷积神经网络
在此基础上加上了自己(粘贴)的笔记。
卷积神经网络包含输入层、隐藏层和输出层,隐藏层又包含卷积层和pooling层,图像输入到卷积神经网络后通过卷积来不断的提取特征,每提取一个特征就会增加一个feature map,所以会看到视频教程中的立方体不断的增加厚度,那么为什么厚度增加了但是却越来越瘦了呢,哈哈这就是pooling层的作用喽,pooling层也就是下采样,通常采用的是最大值pooling和平均值pooling,因为参数太多喽,所以通过pooling来稀疏参数,使我们的网络不至于太复杂。
好啦,既然你对卷积神经网络已经有了大概的了解,下次课我们将通过代码来实现一个基于MNIST数据集的简单卷积神经网络。
定义卷积层的 weight bias
首先我们导入tensorflow,采用的数据集依然是tensorflow里面的mnist数据集,我们需要先导入它。
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
# number 1 to 10 data
mnist = input_data.read_data_sets('MNIST_data', one_hot=True)
WARNING:tensorflow:From <ipython-input-1-e544549f6194>:4: read_data_sets (from tensorflow.contrib.learn.python.learn.datasets.mnist) is deprecated and will be removed in a future version.
Instructions for updating:
Please use alternatives such as official/mnist/dataset.py from tensorflow/models.
WARNING:tensorflow:From C:\Anaconda\lib\site-packages\tensorflow\contrib\learn\python\learn\datasets\mnist.py:260: maybe_download (from tensorflow.contrib.learn.python.learn.datasets.base) is deprecated and will be removed in a future version.
Instructions for updating:
Please write your own downloading logic.
WARNING:tensorflow:From C:\Anaconda\lib\site-packages\tensorflow\contrib\learn\python\learn\datasets\mnist.py:262: extract_images (from tensorflow.contrib.learn.python.learn.datasets.mnist) is deprecated and will be removed in a future version.
Instructions for updating:
Please use tf.data to implement this functionality.
Extracting MNIST_data\train-images-idx3-ubyte.gz
WARNING:tensorflow:From C:\Anaconda\lib\site-packages\tensorflow\contrib\learn\python\learn\datasets\mnist.py:267: extract_labels (from tensorflow.contrib.learn.python.learn.datasets.mnist) is deprecated and will be removed in a future version.
Instructions for updating:
Please use tf.data to implement this functionality.
Extracting MNIST_data\train-labels-idx1-ubyte.gz
WARNING:tensorflow:From C:\Anaconda\lib\site-packages\tensorflow\contrib\learn\python\learn\datasets\mnist.py:110: dense_to_one_hot (from tensorflow.contrib.learn.python.learn.datasets.mnist) is deprecated and will be removed in a future version.
Instructions for updating:
Please use tf.one_hot on tensors.
Extracting MNIST_data\t10k-images-idx3-ubyte.gz
Extracting MNIST_data\t10k-labels-idx1-ubyte.gz
WARNING:tensorflow:From C:\Anaconda\lib\site-packages\tensorflow\contrib\learn\python\learn\datasets\mnist.py:290: DataSet.__init__ (from tensorflow.contrib.learn.python.learn.datasets.mnist) is deprecated and will be removed in a future version.
Instructions for updating:
Please use alternatives such as official/mnist/dataset.py from tensorflow/models.
def compute_accuracy(v_xs, v_ys):
global prediction
y_pre = sess.run(prediction, feed_dict={xs: v_xs, keep_prob: 1})
correct_prediction = tf.equal(tf.argmax(y_pre,1), tf.argmax(v_ys,1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
result = sess.run(accuracy, feed_dict={xs: v_xs, ys: v_ys, keep_prob: 1})
return result
接着呢,我们定义Weight变量,输入shape,返回变量的参数。其中我们使用tf.truncted_normal产生随机变量来进行初始化:
def weight_variable(shape):
initial = tf.truncated_normal(shape, stddev=0.1)
return tf.Variable(initial)
同样的定义biase变量,输入shape ,返回变量的一些参数。其中我们使用tf.constant常量函数来进行初始化:
def bias_variable(shape):
initial = tf.constant(0.1, shape=shape) #初始值为0.1
return tf.Variable(initial)
定义卷积,tf.nn.conv2d函数是tensoflow里面的二维的卷积函数,x是图片的所有参数,W是此卷积层的权重,然后定义步长值,和的两个1是默认值,中间两个1代表padding时在x方向运动一步,y方向运动一步,padding采用的方式是SAME。
实际上是卷积窗口大小对应feature map,含义:,因为在卷积池化过程中不需要对batch和channels操作,所以这两个是1;指不跳过任何一个样本和颜色通道。每一个样本及通道都会计算,高度宽度步长可合理调节
def conv2d(x, W):
# stride [1, x_movement, y_movement, 1]
# Must have strides[0] = strides[3] = 1
return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='SAME')
pooling 将特征表现得更明显
接着定义池化pooling,为了得到更多的图片信息,在之前卷积层的padding时我们选的是一次一步,也就是,这样得到的图片尺寸没有变化,而我们希望压缩一下图片也就是参数能少一些从而减小系统的复杂度,因此我们采用pooling来稀疏化参数,也就是卷积神经网络中所谓的下采样层。
pooling 有两种,一种是最大值池化,一种是平均值池化,本例采用的是最大值池化tf.max_pool()。池化的核函数大小为2x2,因此,步长为2,因此:
def max_pool_2x2(x):
# stride [1, x_movement, y_movement, 1]
return tf.nn.max_pool(x, ksize=[1,2,2,1], strides=[1,2,2,1], padding='SAME')
第一个参数x的shape为【batch,height,width,channels】
ksize为池化窗口的大小 是一个四位向量 一般为【1,height,width,1】 因为我们不想在batch和channels上做操作,所以这两个维度上设为1
第三个参数,和卷积类似,窗口在每一个维度上滑动的步长,所以一般设为【1,stride,stride,1】
之后,我们要一层层的加上不同的 layer. 分别是:
convolutional layer1 + max pooling;
convolutional layer2 + max pooling;
fully connected layer1 + dropout;
fully connected layer2 to prediction.
我们利用上节课定义好的函数来构建我们的网络
图片处理
首先呢,我们定义一下输入的placeholder
xs=tf.placeholder(tf.float32,[None,784])
ys=tf.placeholder(tf.float32,[None,10])
我们还定义了dropout的placeholder,它是解决过拟合的有效手段
keep_prob=tf.placeholder(tf.float32)
接着呢,我们需要处理我们的xs,把xs的形状变成,-1代表先不考虑输入的图片例子多少这个维度,后面的1是channel的数量,因为我们输入的图片是黑白的,因此channel是1,例如如果是RGB图像,那么channel就是3。
x_image = tf.reshape(xs, [-1, 28, 28, 1])
# print(x_image.shape) # [n_samples, 28,28,1] 其实这个-1地方reshape函数算出的数就是samples的多少
-1就像placeholder中的None一样,我们自己不用去管这个维度的大小,reshape会自动计算,但是我的这个列表中只能有一个 -1 。原因很简单,多个 -1 会造成多解的方程情况
建立卷积层
-
W_conv1
接着我们定义第一层卷积,先定义本层的Weight,本层我们的卷积核patch的大小是5x5,因为黑白图片channel是1所以输入是1,输出是32个featuremap
-
b_conv1
接着定义bias,它的大小是32个长度,因此我们传入它的shape为
-
h_conv1
定义好了Weight和bias,我们就可以定义卷积神经网络的第一个卷积层
h_conv1=conv2d(x_image,W_conv1)+b_conv1
,同时我们对h_conv1进行非线性处理,也就是激活函数来处理喽,这里我们用的是tf.nn.relu(修正线性单元)来处理,要注意的是,因为采用了SAME的padding方式,输出图片的大小没有变化依然是28x28,只是厚度变厚了,因此现在的输出大小就变成了28x28x32 -
h_pool1
最后我们再进行pooling的处理就ok啦,经过pooling的处理,输出大小就变为了14x14x32
## conv1 layer ##
W_conv1 = weight_variable([5,5, 1,32]) # patch 5x5, in size 1, out size 32
b_conv1 = bias_variable([32])
h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1) # output size 28x28x32
h_pool1 = max_pool_2x2(h_conv1) # output size 14x14x32
WARNING:tensorflow:From C:\Anaconda\lib\site-packages\tensorflow\python\framework\op_def_library.py:263: colocate_with (from tensorflow.python.framework.ops) is deprecated and will be removed in a future version.
Instructions for updating:
Colocations handled automatically by placer.
-
W_conv2 b_conv2
接着呢,同样的形式我们定义第二层卷积,本层我们的输入就是上一层的输出,本层我们的卷积核patch的大小是5x5,有32个featuremap所以输入就是32,输出我们定为64
-
h_conv2
接着我们就可以定义卷积神经网络的第二个卷积层,这时的输出的大小就是14x14x64
-
h_pool2
最后也是一个pooling处理,输出大小为7x7x64
## conv2 layer ##
W_conv2 = weight_variable([5,5, 32, 64]) # patch 5x5, in size 32, out size 64
b_conv2 = bias_variable([64])
h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2) # output size 14x14x64
h_pool2 = max_pool_2x2(h_conv2) # output size 7x7x64
建立全连接层
好的,接下来我们定义我们的 fully connected layer,
进入全连接层时, 我们通过tf.reshape()将h_pool2的输出值从一个三维的变为一维的数据, -1表示先不考虑输入图片例子维度, 将上一个输出结果展平.
此时weight_variable的shape输入就是第二个卷积层展平了的输出大小: 7x7x64, 后面的输出size我们继续扩大,定为1024
然后将展平后的h_pool2_flat与本层的W_fc1相乘(注意这个时候不是卷积了)
如果我们考虑过拟合问题,可以加一个dropout的处理
## fc1 layer ##
W_fc1 = weight_variable([7*7*64, 1024])
b_fc1 = bias_variable([1024])
# [n_samples, 7, 7, 64] ->> [n_samples, 7*7*64]
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)
h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)
WARNING:tensorflow:From <ipython-input-12-48931eb901b7>:7: calling dropout (from tensorflow.python.ops.nn_ops) with keep_prob is deprecated and will be removed in a future version.
Instructions for updating:
Please use `rate` instead of `keep_prob`. Rate should be set to `rate = 1 - keep_prob`.
接下来我们就可以进行最后一层的构建了,好激动啊, 输入是1024,最后的输出是10个 (因为mnist数据集就是[0-9]十个类),prediction就是我们最后的预测值
然后呢我们用softmax分类器(多分类,输出是各个类的概率),对我们的输出进行分类
## fc2 layer ##
W_fc2 = weight_variable([1024, 10])
b_fc2 = bias_variable([10])
prediction = tf.nn.softmax(tf.matmul(h_fc1_drop, W_fc2) + b_fc2)
选优化方法
接着呢我们利用交叉熵损失函数来定义我们的cost function
我们用tf.train.AdamOptimizer()作为我们的优化器进行优化,使我们的cross_entropy最小
# the error between prediction and real data
cross_entropy = tf.reduce_mean(-tf.reduce_sum(ys * tf.log(prediction),
reduction_indices=[1])) # loss
train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)
WARNING:tensorflow:From C:\Anaconda\lib\site-packages\tensorflow\python\ops\math_ops.py:3066: to_int32 (from tensorflow.python.ops.math_ops) is deprecated and will be removed in a future version.
Instructions for updating:
Use tf.cast instead.
定义Session,初始化变量
sess = tf.Session()
# important step
# tf.initialize_all_variables() no long valid from
# 2017-03-02 if using tensorflow >= 0.12
if int((tf.__version__).split('.')[1]) < 12 and int((tf.__version__).split('.')[0]) < 1:
init = tf.initialize_all_variables()
else:
init = tf.global_variables_initializer()
sess.run(init)
好啦接着就是训练数据啦,我们假定训练1000步,每50步输出一下准确率, 注意sess.run()时记得要用feed_dict给我们的众多 placeholder 喂数据哦.
for i in range(1000):
batch_xs, batch_ys = mnist.train.next_batch(100)
sess.run(train_step, feed_dict={xs: batch_xs, ys: batch_ys, keep_prob: 0.5})
if i % 50 == 0:
print(compute_accuracy(
mnist.test.images[:1000], mnist.test.labels[:1000]))
0.11
0.775
0.868
0.891
0.908
0.926
0.926
0.937
0.946
0.943
0.951
0.953
0.954
0.955
0.959
0.959
0.962
0.966
0.966
0.963
网友评论