前面介绍的算法能够将精度提升到98%,然而卷积神经网络能够将精度提升到99%。
卷积神经网络-CNN
CNN是一种多层神经网络;
相比于传统的BP(back propagation):
1、权值太多,计算量太大;
2、权值太多,需要大量样本进行训练;
由此提出:局部感受野,原理是部分工作,部分不工作。
CNN
CNN通过局部感受野和权值共享减少神经网络需要训练的参数个数。卷积窗口通常为5x5;部分神经元的权值是一样的;
卷积计算
卷积的步长和要得到多少卷积特征有关;
池化pooling
Pooling常用的三种方式:
1、max-pooling
2、mean-pooling
3、stochastic pooling
常用的池化窗口为2x2,步长为2;
池化的作用是保留更加重要的特征,提取比较大的值,即重要特征。
卷积Padding
SAME PADDING:给平面外部补0;卷积窗口采样后得到一个跟原来大小相同的平面;(必须覆盖所有的原始数据)
VALID PADDING:不会超过平面外部;卷积窗口采样后得到一个比原来平面小的平面;(不能超出原始数据)
由于SAME PADDING需要保持卷积之后的平面和原始平面大小一样,因此在与卷积核运算时,会超出原始平面范围,需对超出平面部分进行补0;
VALID PADDING需要保证卷积之后的平面均为有效值,因此与卷积核运算过程不会超出原始平面范围。
例子
假设有一个2828的平面,用22步长为2的窗口对其进行pooling操作。
使用SAME PADDING的方式,得到1414的平面
使用VALID PADDING的方式,得到1414的平面
假设一个23的平面,用22步长为2的窗口对其进行pooling操作。
使用SAME PADDING的方式,得到12的平面
使用VALID PADDING的方式,得到11的平面
LeNET-5
卷积神经网络应用于MINIT数据集分类
# 加载数据 定义变量
mnist = input_data.read_data_sets('MNIST_data',one_hot=True)
#每个批次的大小
batch_size = 64
#计算一共有多少个批次
n_batch = mnist.train.num_examples // batch_size
#定义两个placeholder
x = tf.placeholder(tf.float32,[None,784]) #28*28
y = tf.placeholder(tf.float32,[None,10])
# tf.placeholder 初始化一个数组,None指任意行,
#初始化权值
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) # Creates a constant tensor.
return tf.Variable(initial)
#卷积层
def conv2d(x,W):
#x input tensor of shape `[batch, in_height, in_width, in_channels]`
#W filter / kernel tensor of shape [filter_height, filter_width, in_channels, out_channels]
#`strides[0] = strides[3] = 1`. strides[1]代表x方向的步长,strides[2]代表y方向的步长
#padding: A `string` from: `"SAME", "VALID"`
return tf.nn.conv2d(x,W,strides=[1,1,1,1],padding='SAME')
#池化层
def max_pool_2x2(x):
# Performs the max pooling on the input.
# 第一个参数value: 需要池化的输入,一般池化层接在卷积层后面,所以输入通常是feature map,依然是[batch, height, width, channels]这样的shape
# 第二个参数ksize:池化窗口的大小,取一个四维向量,一般是[1, height, width, 1],因为我们不想在batch和channels上做池化,所以这两个维度设为了1
# 第三个参数strides:和卷积类似,窗口在每一个维度上滑动的步长,一般也是[1, stride,stride, 1]
# 第四个参数padding:和卷积类似,可以取'VALID' 或者'SAME'
return tf.nn.max_pool(x,ksize=[1,2,2,1],strides=[1,2,2,1],padding='SAME')
卷积层和池化层
#改变x的格式转为4D的格式[batch, in_height, in_width, in_channels] [批次大小 高度 宽度 通道数]
x_image = tf.reshape(x,[-1,28,28,1]) # -1 自动匹配维度的含义
#初始化第一个卷积层的权值和偏置
W_conv1 = weight_variable([5,5,1,32])#5*5的采样窗口,32个卷积核从1个平面抽取特征 #输入通道数1
b_conv1 = bias_variable([32])#每一个卷积核一个偏置值
#把x_image和权值向量进行卷积,再加上偏置值,然后应用于relu激活函数
h_conv1 = tf.nn.relu(conv2d(x_image,W_conv1) + b_conv1)
h_pool1 = max_pool_2x2(h_conv1)#进行max-pooling
#初始化第二个卷积层的权值和偏置 # 输入32 输出64
W_conv2 = weight_variable([5,5,32,64])#5*5的采样窗口,64个卷积核从32个平面抽取特征
b_conv2 = bias_variable([64])#每一个卷积核一个偏置值
#把h_pool1和权值向量进行卷积,再加上偏置值,然后应用于relu激活函数
h_conv2 = tf.nn.relu(conv2d(h_pool1,W_conv2) + b_conv2)
h_pool2 = max_pool_2x2(h_conv2)#进行max-pooling
28 * 28的图片第一次卷积后还是28 * 28,第一次池化后变为14 * 14
第二次卷积后为14 * 14,第二次池化后变为了7 * 7
进过上面操作后得到64张7 * 7的平面
(64,7,7,64) 7 * 7 特征值的大小 64 * 64 是图片多少
卷积不改变维度,池化才改变维度
全链接层
#初始化第一个全连接层的权值
W_fc1 = weight_variable([7*7*64,1024])#上一层有7*7*64个神经元,全连接层有1024个神经元
b_fc1 = bias_variable([1024])#1024个节点
#把池化层2的输出扁平化为1维,将第二层池化层输出,转换维度为一维
h_pool2_flat = tf.reshape(h_pool2,[-1,7*7*64]) # 7*7*64 代表神经元个数 -1 自动匹配
#求第一个全连接层的输出::输出维度1*1024
h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat,W_fc1) + b_fc1)
#keep_prob用来表示神经元的输出概率
keep_prob = tf.placeholder(tf.float32)
h_fc1_drop = tf.nn.dropout(h_fc1,keep_prob) # dropout 防止过拟合
#初始化第二个全连接层
W_fc2 = weight_variable([1024,10])
b_fc2 = bias_variable([10])
#计算输出 输出维度1*10
prediction = tf.nn.softmax(tf.matmul(h_fc1_drop,W_fc2) + b_fc2)
代价函数,梯度下降优化,取误差的全局极小值
#交叉熵代价函数
cross_entropy = tf.losses.softmax_cross_entropy(y,prediction)
#使用AdamOptimizer进行优化
train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)
#结果存放在一个布尔列表中
correct_prediction = tf.equal(tf.argmax(prediction,1),tf.argmax(y,1))#argmax返回一维张量中最大的值所在的位置
#求准确率
accuracy = tf.reduce_mean(tf.cast(correct_prediction,tf.float32))
新建会话,开始训练模型
此处可以结合上一讲,自适应的学习率,看看效果
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
for epoch in range(21):
for batch in range(n_batch):
batch_xs,batch_ys = mnist.train.next_batch(batch_size)
sess.run(train_step,feed_dict={x:batch_xs,y:batch_ys,keep_prob:0.7})
acc = sess.run(accuracy,feed_dict={x:mnist.test.images,y:mnist.test.labels,keep_prob:1.0})
print ("Iter " + str(epoch) + ", Testing Accuracy= " + str(acc))
上一讲自适应的学习率
lr = tf.Variable(0.001, dtype=tf.float32)
# 每次迭代时候更新
sess.run(tf.assign(lr, 0.001 * (0.95 ** epoch)))
learning_rate = sess.run(lr)
长短时记忆网络-LSTM
卷积网络比LSTM更加适合处理图像
#定义RNN网络
def RNN(X,weights,biases):
# inputs=[batch_size, max_time, n_inputs]
inputs = tf.reshape(X,[-1,max_time,n_inputs]) # LSTM对数据格式有要求 3维 与卷积类似
#定义LSTM
lstm_cell = tf.nn.rnn_cell.LSTMCell(lstm_size) # 有lstm_size个brock
# final_state[state, batch_size, cell.state_size]
# final_state[0]是cell state
# final_state[1]是hidden_state
# outputs: The RNN output `Tensor`.
# If time_major == False (default), this will be a `Tensor` shaped:
# `[batch_size, max_time, cell.output_size]`.
# If time_major == True, this will be a `Tensor` shaped:
# `[max_time, batch_size, cell.output_size]`.
outputs,final_state = tf.nn.dynamic_rnn(lstm_cell,inputs,dtype=tf.float32) # 输出三维数据与softmax略有不一样 final_state指最终的输出
# outputs 保留28个序列的每个输出。softmax激活函数
results = tf.nn.softmax(tf.matmul(final_state[1],weights) + biases)
return results
#计算RNN的返回结果,接下来的计算过程,与前几讲所述的内容基本一致
prediction= RNN(x, weights, biases)
以图像处理的数据集为例,卷积神经网络的效果明显优于RNN