本章节主要介绍卷积神经网络,以及如何使用TensorFlow构建卷积神经网络结构。其他内容学习请前往:TensorFlow 学习目录。
目录
一、卷积神经网络的Back Propagation的推导过程
四、使用TensorFlow构建CNN在Fashion-MNIST数据集上进行训练和预测
一、卷积神经网络的Back Propagation的推导过程
具体过程请参考:CNN 卷积神经网络Back Propagation推导过程
二、理解其编码过程
<1>理解卷积操作
定义:原图大小,卷积核大小,移动步长S。
- 窄卷积(valid):图像通过窄卷积后的图像大小为。
- 同卷积(same):表示卷积之后的图像尺寸与原图片的尺寸大小一样,同卷积的步长是固定的,滑动步长S=1,一般操作的时候需要用到padding技术,以此确保尺寸不变。
- 全卷积(full):将每个图像的每一个像素点用卷积操作展开,如下图,操作之后的图像会变大,并且全卷积的步长S=1也是确定的。所以卷积之后的图像大小为。
TensorFlow中的代码形式如下:
feature_map = tf.nn.conv2d(input, filter, strides, padding, use_cudnn_on_gpu=True)
参数:
- input:输入图像
- filter:定义的一个卷积核,其张量形式为,inputchannels表示的是input的通道数量,如果说input是原始输入图像的话,如果是灰度图像,那么其通道数为1,如果是RGB图像,那么通道数是3,outputchannels表示在本卷积层,需要构建多少个卷积核,每一个卷积核计算的inputchannels个feature maps通过按像素相加的形式得到新的feature maps。如果输入的input是前一层卷积层的输出,那么很自然本层的inputchannels等于上一层卷积层或者池化层的outputchannels。
- strides:步长,其张量形式为。
- padding:定义元素边框和元素内容之间的空间。只有两种操作选项模式,第一种为”SAME“,第二种为”VALID“,这两种方式就是本文前部分讲解的同卷积和窄卷积。
- use_cudnn_on_gpu:是否使用GPU,默认值为True。
<2>理解池化操作
- 均匀池化:区域内取均值
- 最大值池化:区域内取最大值
TensorFlow中的代码形式如下:
tf.nn.max_pool(input, ksize, strides, padding, name=None)
tf.nn.avg_pool(input, ksize, strides, padding, name=None)
参数:
- input:需要进行池化的输入,例如:卷积之后的feature maps。
- ksize:池化窗口的大小,其张量形式为,因为我们并不想在batch和channels上进行池化操作,所以这两个维度为1。
- strides:和卷积参数含义基本类似,即窗口在每一个维度上滑动的步长,其张量形式为。
- padding:和卷积参数含义一致,VALID、SAME,其中VALID表示不进行padding操作,SAME表示进行padding操作。
三、TensorFlow对CNN进行编码使用到的编程技巧
<1> 使用全局池化来代替原有的全连接层
其思想非常的简单,如果最后一层卷积层的输出通道为分类数,那么此时我连接一个大小为卷积层feature maps的大小的池化层,那么我就将一个二维张量变成了一个标量,那么此时,如果分类数为10, 就是10个标量,然后将这10个量,连成一个向量作为预测输出即可。在下面的代码中会具体体现。可以与TensorFlow 手写数字识别中的代码进行类比。
<2>使用多通道卷积技术
上面个介绍的卷积层中使用的是单个尺寸的卷积核对输入数据卷积操作,而多通道卷积核是采用不同尺寸的滤波器对上一层的feature maps或者输入图片进行特征提取。
h_pool1 = max_pool_2x2(h_conv1)
# 此时获得如为h_pool1
W_conv2_5x5 = weight_variable([5, 5, 64, 64])
b_conv2_5x5 = bias_variable([64])
W_conv2_7x7 = weight_variable([7, 7, 64, 64])
b_conv2_7x7 = bias_variable([64])
W_conv2_3x3 = weight_variable([3, 3, 64, 64])
b_conv2_3x3 = bias_variable([64])
W_conv2_1x1 = weight_variable([3, 3, 64, 64])
b_conv2_1x1 = bias_variable([64])
h_conv2_1x1 = tf.nn.relu(conv2d(h_pool1, W_conv2_1x1) + b_conv2_1x1)
h_conv2_3x3 = tf.nn.relu(conv2d(h_pool1, W_conv2_3x3) + b_conv2_3x3)
h_conv2_5x5 = tf.nn.relu(conv2d(h_pool1, W_conv2_5x5) + b_conv2_5x5)
h_conv2_7x7 = tf.nn.relu(conv2d(h_pool1, W_conv2_7x7) + b_conv2_7x7)
h_conv2 = tf.concat([h_conv2_5x5,h_conv2_7x7,h_conv2_3x3,h_conv2_1x1],3)
解析一下h_conv2的张量形状,主要是看最后一个维度,表示四种不同的滤波器连接在一起形成了大小为256的输出通道。
四、使用TensorFlow构建CNN在Fashion-MNIST数据集上进行训练和预测
Fashion-MNIST数据集的解析请参考:MNIST、Fashion-MNIST、SmallNORB三款标准图像数据集。
import tensorflow as tf
import numpy as np
import get_Dataset
x_train, y_train, x_test, y_test = get_Dataset.get_Dataset(name='fashion')
def conv2d(x, id, filter_size):
with tf.variable_scope('conv2d_' + str(id)):
w = tf.get_variable(name='filter', initializer=tf.truncated_normal(shape=filter_size, stddev=0.1),
dtype=tf.float32)
b = tf.get_variable(name='bias', initializer=tf.constant(0.1, shape=[filter_size[3]], dtype=tf.float32))
z = tf.nn.relu(tf.nn.conv2d(x, w, strides=[1, 1, 1, 1], padding='SAME') + b)
return z
def pooling2x2(x):
return tf.nn.max_pool(x, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
def pooling7x7(x):
return tf.nn.avg_pool(x, ksize=[1, 7, 7, 1], strides=[1, 7, 7, 1], padding='SAME')
inputs = tf.placeholder(dtype=tf.float32, shape=[None, 784], name='inputs')
labels = tf.placeholder(dtype=tf.float32, shape=[None, 10], name='labels')
predict_labels = tf.placeholder(dtype=tf.int64, shape=[None], name='predict_labels')
net = tf.reshape(inputs, shape=[-1, 28, 28, 1])
net = conv2d(net, 1, [5, 5, 1, 64])
net = pooling2x2(net)
net = conv2d(net, 2, [3, 3, 64, 64])
net = pooling2x2(net)
net = conv2d(net, 3, [3, 3, 64, 10])
net = pooling7x7(net)
logits = tf.reshape(net, [-1, 10])
loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=labels, logits=logits))
train_step = tf.train.AdamOptimizer(1e-4).minimize(loss)
correct_prediction = tf.equal(tf.argmax(logits, 1), predict_labels)
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
epochs = 50
batch_size = 32
with tf.Session(config=tf.ConfigProto(allow_soft_placement=True)) as sess:
sess.run(tf.global_variables_initializer())
for epoch in range(epochs):
for batch in range(int(x_train.shape[0] / batch_size)):
batch_xs = x_train[batch * batch_size: (batch + 1) * batch_size]
batch_ys = y_train[batch * batch_size: (batch + 1) * batch_size]
feed_dict = {
inputs: batch_xs,
labels: batch_ys
}
sess.run(train_step, feed_dict=feed_dict)
acc = sess.run(accuracy, feed_dict={inputs: x_test, predict_labels: y_test})
print("Epoch ", epoch + 1, " acc=", acc)
输出:
Epoch 1 acc= 0.6975
Epoch 2 acc= 0.7331
Epoch 3 acc= 0.7561
Epoch 4 acc= 0.7683
Epoch 5 acc= 0.7788
Epoch 6 acc= 0.7857
Epoch 7 acc= 0.7924
Epoch 8 acc= 0.7975
Epoch 9 acc= 0.8007
Epoch 10 acc= 0.805
Epoch 11 acc= 0.809
Epoch 12 acc= 0.8134
Epoch 13 acc= 0.8163
Epoch 14 acc= 0.8183
Epoch 15 acc= 0.8222
Epoch 16 acc= 0.8249
Epoch 17 acc= 0.827
Epoch 18 acc= 0.8291
Epoch 19 acc= 0.8307
Epoch 20 acc= 0.8318
Epoch 21 acc= 0.8335
Epoch 22 acc= 0.8362
Epoch 23 acc= 0.8371
Epoch 24 acc= 0.838
Epoch 25 acc= 0.839
Epoch 26 acc= 0.8408
Epoch 27 acc= 0.8415
Epoch 28 acc= 0.8443
Epoch 29 acc= 0.8452
Epoch 30 acc= 0.8473
Epoch 31 acc= 0.8487
Epoch 32 acc= 0.8497
Epoch 33 acc= 0.851
Epoch 34 acc= 0.8517
Epoch 35 acc= 0.8525
Epoch 36 acc= 0.8532
Epoch 37 acc= 0.8537
Epoch 38 acc= 0.8545
Epoch 39 acc= 0.8549
Epoch 40 acc= 0.856
Epoch 41 acc= 0.857
Epoch 42 acc= 0.8578
Epoch 43 acc= 0.8588
Epoch 44 acc= 0.8599
Epoch 45 acc= 0.8599
Epoch 46 acc= 0.8611
Epoch 47 acc= 0.8621
Epoch 48 acc= 0.8631
Epoch 49 acc= 0.8642
Epoch 50 acc= 0.8654