深度前馈神经网络之卷积神经网络(CNN)总结

文章目录

  • 预览
  • 一、输入层
  • 二、卷积层
  • 三、池化层
  • 四、全连接层
  • 五、Dropout层
  • 六、输出层
  • 七、定义损失、学习率、训练模型方法
  • 七、 模型训练
  • 八、 定义函数常用模版
  • 九、卷积神经网络代码实战

预览

卷积神经网络最主要在图像识别领域有很重要的应用,属于深度前馈神经网络范畴,
卷积神经网络一般结构为输入层–卷积层–池化层–全连接层–输出层
一般步骤
1.定义超参数
2.定义卷积层和全连接权重参数初始化函数
3.导入训练数据
4.用占位符表示输入数据和标签
5.搭建网络模型(卷积层,非线性化relu,池化层,全连接层)
6.定义损失(交叉熵损失+参数的正则化损失)
7.启动队列,开始训练
8.验证模型

一、输入层

输入数据一般为图像,一般代表的是一张图片的像素矩阵,根据通道数的不同,图片像素矩阵有着不同的深度值,黑白图片只有一个通道,就深度为1。而彩色RGB图片有三个通道,就有深度为3。
可以使用随机变换的方法来人为的增加数据集。详见tensorflow图像常用变换方法
读取图像并进行预处理,做为后续评估和训练的输入;

二、卷积层

卷积层进行卷积操作,用卷积核将像素矩阵映射为特征矩阵,减少特征数量,常用的卷积核为 3 ∗ 3 3*3 33或者 5 ∗ 5 5*5 55。卷积操作是一个特殊的线性操作,需要进行去线性化,通常加入整流线性单元(ReLu)去线性化。所以一般大型神经网络,我们将包含卷积操作,非线性变化操作,池化操作等三个操作称为一段卷积层,大型神经网络是由多段卷积层堆积而成。

一个卷积核只能提取某一个特征,多个卷积核就能提取多个丰富的特征,tensorflow中称卷积核为过滤器,过滤器的深度为卷积核的数量。

卷积运算有三个重要特性

  • 稀疏连接
    能够显著的降低参数数量,每一个卷积核只与某一小块的区域的像素相关联,减少权重参数有两个好处,一是降低计算复杂度,二是过多的连接会导致过拟合,减少连接会提高模型的泛化能力。
  • 参数共享
    参数共享也是降低存储参数数量的一个办法。
  • 等变表示
    先进行平移变换和再进行卷积操作所得到的结果和先做卷积再做平移变换得到的结果一样,参数共享是平移等变的一个前提。

代码实现

tf.conv2d(input,filter,strids,padding,us_cudnn_on_gpu_,data_format,name)

参数

  • input:输入图像矩阵,四维表示,第一维代表输入一个batch(包含一定数量的图片),input[1, , , ]表示第二张图片,第二维代表这个batch宽度,第三维代表这个batch的高度,第四维代表这个图片的通道数(深度),当input不是来自输入层时,深度应该为上一层输出的图像矩阵深度
  • filter:卷积核大小,也是四维,第一第二维代表卷积核的大小,第三维为输入矩阵的深度,第四维为本层过滤器的深度(卷积核的数量)
  • padding:SAME与VALID两种选择,SAME时表示全为0填充,VALID时表示不全为0填充,使得卷积后的图像和原始图像一样大小。
  • strids:步长。四维参数,第二维指向长方向移动的步长,第三维指向宽方向移动的步长,第一维和第四维都是1。

代码实例

import tensorflow as tf
import numpy as np

#使用numpy工具初始化一个名为M的数组,形状为2x3,数据类型为float32
#并使用numpy的reshape()函数调整输入的格式
#注意,M不会被TensorFlow识别为张量
M = np.array([[[2],[1],[2],[-1]],[[0],[-1],[3],[0]],
              [[2],[1],[-1],[4]],[[-2],[0],[-3],[4]]],dtype="float32").reshape(1, 4, 4, 1)

#通过get_variable()函数创建过滤器的权重变量,上面介绍了卷积层
#这里声明的参数变量是一个四维矩阵,前面两个维度代表了过滤器的尺寸,
#第三个维度表示当前层的深度,第四个维度表示过滤器的深度。
filter_weight = tf.get_variable("weights",[2, 2, 1, 1],initializer = tf.constant_initializer([[-1, 4],[2, 1]]))

#通过get_variable()函数创建过滤器的偏置项,代码中[1]表示过滤器的深度。
#等于神经网络下一层的深度。
biases = tf.get_variable("biase", [1], initializer = tf.constant_initializer(1))


x = tf.placeholder('float32', [1,None, None,1])

#conv2d()函数实现了卷积层前向传播的算法。
#这个函数的第一个参数为当前层的输入矩阵,注意这个矩阵应该是一个四维矩阵,
#代表第一个维度的参数对应一个输入batch。如果在输入层,input[0, , , ]表示第一张图片,
#input[1, , , ]表示第二张图片,等等。函数第二个参数是卷积层的权重,第三个参数为
#不同维度上的步长。虽然第三个参数提供的是一个长度为4 的数组,
#但是第一个和最后一个数字要求一定是1,这是因为卷积层的步长只对矩阵的长和宽有效。
#最后一个参数是填充(padding的方法,有SAME或VALID 两种选择,
#其中SAME 表示添加全0填充,VALID表示不添加。
#函数原型conv2d(input,filter,strids,padding,us_cudnn_on_gpu_,data_format,name)
conv = tf.nn.conv2d(x, filter_weight, strides=[1, 1, 1, 1], padding="SAME")

#bias_add()函数具有给每一个节点加上偏置项点功能。这里不能直接使用加法的原因是
#矩阵上不同位置上的节点都需要加上同样的偏置项。因为过滤器深度为1,
#故偏置项只有一个数,结果为3x4的矩阵中每一个值都要加上这个偏置项。
#原型bias_add(value,bias,data_format,name)
add_bias = tf.nn.bias_add(conv, biases)

init_op=tf.global_variables_initializer()
with tf.Session() as sess:
    init_op.run()
    M_conv=sess.run(add_bias, feed_dict={x: M})

    #输出结果并不是一个张量,而是数组
    print("M after convolution: \n", M_conv)

三、池化层

池化层能在卷积操作之后对结果进行宽度和高度方向的进一步处理(统计聚合操作),同时能够减少参数,常用池化操作有最大池化(计算区域内的最大值作为该区域的值),平均值池化(计算区域内的平均值作为该区域的值),使用池化函数原因,某一特征会与相邻的特征非常相似,所以保留一个即可。池化核的大小就是池化操作的矩形区域的大小。

tf.nn.max_pool(value,ksize,strides,padding,data_format,name)

参数(和卷积参数类似)

  • value为输入数据,与卷积输入参数一致
  • ksize为池化核尺寸,四维参数,第一维和第四维都为1,第二维和第三维为池化核大小
  • strides为提供了步长信息,与卷积核步长参数一致
  • padding提供了是否使用全0填充

代码实例

import tensorflow as tf
import numpy as np

M = np.array([[[-2],[2],[0],[3]],
              [[1],[2],[-1],[2]],
              [[0],[-1],[1],[0]]],dtype="float32").reshape(1, 3, 4, 1)

filter_weight = tf.get_variable("weights",[2, 2, 1, 1],initializer = tf.constant_initializer([[2, 0],[-1, 1]]))

biases = tf.get_variable('biases', [1], initializer = tf.constant_initializer(1))

x = tf.placeholder('float32', [1, None, None, 1])

conv = tf.nn.conv2d(x, filter_weight, strides=[1, 1, 1, 1], padding="SAME")

add_bias = tf.nn.bias_add(conv, biases)

#max_pool()函数实现了最大池化层的前向传播过程
#原型为max_pool(value,strides,padding,data_format,name)
#参数value为输入数据,strides为提供了步长信息,padding提供了是否使用全0填充。
pool = tf.nn.max_pool(add_bias, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding="SAME")##

with tf.Session() as sess:
    tf.global_variables_initializer().run()
    M_conv = sess.run(add_bias, feed_dict={x: M})
    M_pool = sess.run(pool, feed_dict={x: M})
    print(" after average pooled: \n", M_pool)
    print(" after conv: \n", M_conv)
    '''输出内容
    after average pooled:
    [[[[7.]
       [5.]]
      [[1.]
       [3.]]]]
    '''

四、全连接层

通过卷积层和池化层之后,提取到了图像最基本的特征,为了完成分类任务,还需要添加几个全连接层。都需要定义一个权重初始化函数来方便定义参数,其中 weight_variable为卷积核参数定义函数,bias_variable为偏置定义函数。

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层

可以在每层输出之后,定义一个概率,以一定的概率随机使每层的一部分神经元响应为0,来防止过拟合。测试时概率设置为1,训练时概率为0到1之间值。
dropout介绍

keep_prob = tf.placeholder(tf.float32)
h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)
#h_fc1为具体某层的输出

六、输出层

可以得到输入样本所属类别的概率分布情况,并进行分类,一般用softmax层作最后输出。

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)

七、定义损失、学习率、训练模型方法

损失函数常用交叉熵(分类)和RMSE(回归)。
训练模型方法常用以下几种方法。

tf.train.GradientDescentOptimizer
tf.train.AdagradOptimizer
tf.train.MomentumOptimizer
tf.train.AdamOptimizer
tf.train.FtrlOptimizer
tf.train.RMSPropOptimizer

#以mnist分类为例
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))

七、 模型训练

以mnist为例,每隔100步输出精度,输出测试精度

tf.global_variables_initializer().run()
#初始化
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}))

八、 定义函数常用模版

常用一个函数来包含卷积核参数初始化,卷积操作,非线性Relu操作,池化操作,LRN局部响应归一化操作,方便后续调用。
函数模板:

  with tf.variable_scope('conv1') as scope:
    kernel = _variable_with_weight_decay('weights',
                                         shape=[5, 5, 3, 64],
                                         stddev=5e-2,
                                         wd=0.0)
    conv = tf.nn.conv2d(images, kernel, [1, 1, 1, 1], padding='SAME')
    biases = _variable_on_cpu('biases', [64], tf.constant_initializer(0.0))
    pre_activation = tf.nn.bias_add(conv, biases)
    conv1 = tf.nn.relu(pre_activation, name=scope.name)
    _activation_summary(conv1)
    pool1 = tf.nn.max_pool(conv1, ksize=[1, 3, 3, 1], strides=[1, 2, 2, 1],
                         padding='SAME', name='pool1')
    norm1 = tf.nn.lrn(pool1, 4, bias=1.0, alpha=0.001 / 9.0, beta=0.75,
                    name='norm1')

九、卷积神经网络代码实战

详见github主页

你可能感兴趣的:(深度学习)