一、CNN基本组成
卷积神经网络采用了三种基本概念:局部感受野(local receptive fields),共享权重(shared weights),池化(pooling)。
1、局部感受野
将图像像素输入神经元排列成矩阵形式。把输入像素连接到一个隐藏神经元层。但是我们不会把每个输入像素连接到每个隐藏神经元。我们只是把输入图像进行小的,局部区域的连接。第一个隐藏层中的每个神经元会连接到一个输入神经元的一个小区域,例如,一个 5 × 5 的区域,对应于 25 个输入像素。输入图像的这个区域被称为隐藏神经元的局部感受野。它是输入像素上的一个小窗口。每个连接学习一个权重。隐藏神经元同时也学习一个总的偏置。
然后在整个输入图像上交叉移动局部感受野。大部分时候跨距是1。
2、共享权重与偏置
我们会对24×24隐藏神经元中的每一个使用相同的权重和偏置,也被叫做卷积核。卷积网络能很好地适应图像的平移不变性。
一个完整的卷积层有很多个特征映射,这里选择为3个特征映射。每个特征映射有自己的权重与偏置。
3、池化
我们要构造一个混合层简化卷积层的输出。例如,混合层的每个单元可能概括了前一层的一个 2×2的区域。常见的混合的程序被称为最大值混合(max-pooling)。在最大值混合中,一个混合单元简单地输出其2×2输入区域的最大激活值。
4、全连接层
将池化后的神经元全部连接到若干个神经元上。
5、softmax regression输出层
二、tensorflow手册实现
1、在输出层之前加入了弃权(dropout),以一定百分比激活神经元,剩下的失效,能有效得抑制过拟合。
2、由于10000个28*28的float型数据数据太大,最后在测试集上计算正确率时显存不足而不能执行。将10000个数据分多次计算可以有效地解决这个问题。
# -- coding: utf-8 -- import tensorflow as tf import numpy as np # 下载mnist数据到路径下 import tensorflow.examples.tutorials.mnist.input_data as input_data mnist = input_data.read_data_sets("MNIST_data/", one_hot=True) sess = tf.InteractiveSession() def weight_variable(shape): # 前一个shape是constant函数参数,后一个是传进来的参数,第二个mean参数为均值默认为0,stddev为标准差 initial = tf.truncated_normal(shape=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): # 因为图片只有两维,步长strides取[1,stride,stride,1],same表示输出填充为原有大小 return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='SAME') def max_pool_2x2(x): # 池化为2*2(shape是[batch, height, width, channels]) return tf.nn.max_pool(x, ksize=[1, 2, 2, 1],strides=[1, 2, 2, 1], padding='SAME') x = tf.placeholder("float", shape=[None, 784]) y_ = tf.placeholder("float", shape=[None, 10]) # 5*5的local receptive fields,输入一个通道,输出32个通道 W_conv1 = weight_variable([5, 5, 1, 32]) b_conv1 = bias_variable([32]) # 把x变成一个4d向量,其第2、第3维对应图片的宽、高,最后一维代表图片的颜色通道数 # (因为是灰度图所以这里的通道数为1,如果是rgb彩色图,则为3) x_image = tf.reshape(x, [-1,28,28,1]) # 卷积,激活函数使用的ReLU,输出32@28*28 h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1) # 池化,输出32@14*14 h_pool1 = max_pool_2x2(h_conv1) # 第二层 W_conv2 = weight_variable([5, 5, 32, 64]) b_conv2 = bias_variable([64]) # 得到64@14*14 h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2) # 得到64@7*7 h_pool2 = max_pool_2x2(h_conv2) # 全连接层 W_fc1 = weight_variable([7 * 7 * 64, 1024]) 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) # dropout防止过拟合,以keep_prob的百分比保留神经元,用在全连接层 keep_prob = tf.placeholder("float") h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob) # softmax regression W_fc2 = weight_variable([1024, 10]) 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)) # 学习率1e-4Adam算法优化器求解 train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy) # 返回准确结果,是bool correct_prediction = tf.equal(tf.argmax(y_conv,1), tf.argmax(y_,1)) # bool转float求平均 accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float")) # 初始化所有变量 sess.run(tf.global_variables_initializer()) for i in range(20000): batch = mnist.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, training 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.test.images, y_: mnist.test.labels, keep_prob: 1.0})) # GPU内存不够因而,在测试集上分20次,每次50个数据计算准确率 sum = 0 for i in range(20): testSet = mnist.test.next_batch(50) test_accuracy = accuracy.eval(feed_dict={x: testSet[0], y_: testSet[1], keep_prob: 1.0}) sum += test_accuracy # 输出准确率 print("test accuracy %g" % (sum / 20))
输出如下:
准确率99.4%