神经网络学习(十四)卷积神经网络TensorFlow实现

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/hoho1151191150/article/details/79741105

系列博客是博主学习神经网络中相关的笔记和一些个人理解,仅为作者记录笔记之用,不免有很多细节不对之处。

说明

上一节,我们简单实现了一个卷积神经网络,本节我们采用TensorFlow实现手写字的识别。本节代码参考自《TensorFlow实战》。

实现

首先载入 MNIST 数据,并创建默认的 Interactive Session:

import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
mnist_data = input_data.read_data_sets("MNIST_data/",one_hot = True)
sess = tf.InteractiveSession()

接下来定义初始化权重和偏置的函数,以便重复使用。我们需要给权重添加一些噪音,打破其对称性,比如截断的正态分布噪声,标准差设为 0.1,同时因为我们使用ReLU激活函数,我们给偏置一个小的正值用来避免死亡节点:

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,[1,2,2,1],strides = [1,2,2,1],padding = 'SAME')

这里的 tf.nn.conv2d 是 TensorFlow 中的 2 维卷积函数,参数中 x 是输入, W 是卷积核,比如 [5,5,1,32]: 前面两个数字代表卷积核的尺寸;第三个数字代表有多少个 channel。因为我们是灰度图,所以是 1,如果是彩色的图,这里应该是 3。最后一个数字代表卷积核的数量,也是就是这个卷积层会提取多类的特征。padding代表边界的处理方式,这里的 ‘SAME’ 代表卷积后的输出和输入保持同样(same) 的尺寸,padding 也可以设置为为‘VALID’。

tf.nn.conv2d 是TensorFlow 中的最大池化函数,这里我们采用 2 × 2 的最大池化。因为希望整体上缩小图片尺寸,池化层的 strides 设置为 2 步长。

下面是输入的 placeholder,x是特征,y_是真实的标签,我们还需要将 1D 的输入向量转化为 2D 的图片结构(r eshape中前面的 -1 表示样本数量不固定):

x = tf.placeholder(tf.float32, [None, 784])
y_ = tf.placeholder(tf.float32, [None, 10])
x_image = tf.reshape(x,[-1,28,28,1])

接下来定义第一个卷积层,定义非常简单,先初始化 weights 和 bias,这里的 [5,5,1,32] 代表卷积核的尺寸为 5 × 5,1 是 channel 数,32 是卷积核的数量。初始化卷积层参数后,使用 conv2d函数进行卷积操作,接着再使用 ReLU激活函数进行非线性处理,最后,使用最大池化函数对卷积的输出结果进行池化操作:

W_conv1 = weight_variable([5,5,1,32])
b_conv1 = bias_variable([32])
a_conv1 = tf.nn.relu(conv2d(x_image,W_conv1) + b_conv1)
a_pool1 = max_pool_2x2(a_conv1)

W_conv2 = weight_variable([5,5,32,64])
b_conv2 = bias_variable([64])
a_conv2 = tf.nn.relu(conv2d(a_pool1,W_conv2) + b_conv2)
a_pool2 = max_pool_2x2(a_conv2)

两个卷积层之后,我们再添加全连接层,进过两次池化后,图片的尺寸变为原来的 1/4,即为 7 × 7。第二个卷积层的卷积核数量为 64,全连接层的输入为 7 × 7 × 64 的 1D 向量,隐含节点我们设置为 1024,并使用 ReLU激活函数。

W_fc1 = weight_variable([7*7*64, 1024])
b_fc1 = bias_variable([1024])
a_pool2_flat = tf.reshape(a_pool2,[-1,7*7*64])
a_fc1 = tf.nn.relu(tf.matmul(a_pool2_flat,W_fc1) + b_fc1)

为了减轻过拟合,下面使用一个 Dropout 层、在训练时随机丢弃一部分节点的数据来减轻过拟合,预测时则保留全部节点来追求最好的性能。

keep_prob = tf.placeholder(tf.float32)
a_fc1_drop = tf.nn.dropout(a_fc1,keep_prob)

最后,将 dropout 层连接到一个 softmax 层,得到最后的概率输出:

W_fc2 = weight_variable([1024,10])
b_fc2 = bias_variable([10])
y_conv = tf.nn.softmax(tf.matmul(a_fc1_drop,W_fc2) + b_fc2)

定义完网络后,我们定义代需要优化的代价函数和优化器,并给予一个小的学习速率:

cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(y_conv),
                                              reduction_indices = [1]))
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,tf.float32))

下面是开始训练过程。首先是初始化所有参数,设置训练时 Dropout 层的 keep_prob 比率为 0.5,然后使用大小为 50 的 mini-batch,共进行 20000次训练,参与训练的样本总数为 100 万。其中没经过 100 次,对准确率做一次评测,最后用总的 test 数据进行测评。


tf.global_variables_initializer().run()
for i in range(20000):
    batch = mnist_data.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, train_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_data.test.images,y_: mnist_data.test.labels,keep_prob:1.0})))

结果

经过快两个小时的运行,最后模型在 test 数据的准确率为 99.23%。比我自己实现的卷积神经网络高了 0.2% 的准确率。基于长瘦网络优于矮胖网络的基本认识,下面做一个对比试验,两个卷积层的卷积核数都设置为 32 个,多添加一个全连接层,全连接层的节点都设置为 100,这个模型在 test 数据的准确率变低了,只有 99.04%。
第一个网络的参数个数:
5 × 5 × 32+32+5 × 5 × 64+64+7 × 7 × 64 × 1024+1024+1024 × 10+10 = 3225007;
第二个网络的参数个数:
5 × 5 × 32+32+5 × 5 × 32+32+7 × 7 × 32 × 100+100+100 × 100+100+100 × 10+10 = 169674。
第二个模型的参数大约是第一个模型的5%。我们上一节实现的1+2网络,参数共计:
9 × 9 × 20+20+10 × 10 × 20 × 100+100+100 × 100+100+100 × 10+10 = 212850。
这两个模型的参数相差不大,识别率也差不多。
下面是包含L2正则化的一个版本:


from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets('mnist_data/',one_hot = True)

import tensorflow as tf
sess = tf.InteractiveSession()
#重新定义:weights
def weight_variable(shape,lamda):
    initial = tf.truncated_normal(shape, stddev=0.1)
    if lamda is not None:
        weight_loss = tf.multiply(tf.nn.l2_loss(initial),lamda,name = 'weight_loss')
        tf.add_to_collection('losses',weight_loss)
    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')
#重新定义:loss
def loss(y_,y_conv):
    cross_entropy = -tf.reduce_sum(y_*tf.log(y_conv),axis = [1])
    cross_entropy_mean = tf.reduce_mean(cross_entropy)
    tf.add_to_collection('losses',cross_entropy_mean)

    return tf.add_n(tf.get_collection('losses'),name = 'total_loss')

x = tf.placeholder(tf.float32, shape=[None, 784])
y_ = tf.placeholder(tf.float32, shape=[None, 10])
x_image = tf.reshape(x, [-1,28,28,1])

W_conv1 = weight_variable([5, 5, 1, 32],lamda =  0.00)
b_conv1 = bias_variable([32])
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],lamda =  0.00)
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],lamda =  0.05)
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(tf.float32)
h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)


W_fc2 = weight_variable([1024, 10],lamda =  0.05)
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))
lossVar = loss(y_,y_conv)
train_step = tf.train.AdamOptimizer(1e-4).minimize(lossVar)
correct_prediction = tf.equal(tf.argmax(y_conv,1), tf.argmax(y_,1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
tf.global_variables_initializer().run()

for i in range(20000):
    batch_xs, batch_ys = mnist.train.next_batch(50)
    train_step.run(feed_dict={x: batch_xs, y_: batch_ys, keep_prob: 0.5})
    if i%100 == 0:
        print('step %d'%(i))


print(accuracy.eval(feed_dict={x: mnist.test.images, y_: mnist.test.labels, keep_prob: 1.0}))

猜你喜欢

转载自blog.csdn.net/hoho1151191150/article/details/79741105