1.卷积神经网络介绍

**卷积神经网络(Convolutional Neural Network,CNN)**是一种前馈神经网络,它的人工神经元可以响应一部分覆盖范围内的周围单元,对于大型图像处理有出色表现。
虽然上图中显示的全连接神经网络结构和卷积神经网络的结构直观上差异比较大,但他们的整体架构是非常相似的。从上图可以看出,卷积神经网络也是通过一层一层的节点组织起来的。和全连接神经网络一样,卷积神经网络中的每一个节点都是一个神经元。在全链接神经网络中,每相邻两层之间的节点都全部相连,于是一般会将每一层全连接层中的节点组织成一列,这样方便显示连接结构。而对于卷积神经网络,相邻两层之间只有部分相连接,为了展示每一层的神经元的维度,一般会将每一层卷积层的节点组织成一个三维矩阵。

除了结构相似,卷积神经网络的输入和输出以及训练流程与全连接神经网络也基本一致。以图象为例,卷积神经网络的输入层就是图像的原始像素,而输出层的每一个节点代表了不同类别的可信度。这和全链接神经网络的输入输出是一致的。卷积神经网络和全连接神经网络的的唯一区别就在于神经网络中相邻两层的连接方式。
上图给出了一个更加具体的卷积神经网络架构图。

在神经网络前几层中,每一层的节点都被组织成一个三维矩阵,从图中可以看出卷积神经网络前几层中每一个节点之和上一层中部分节点相连。一个卷积神经网络主要由以下5种结构组成。

  1. 输入层。输入层是整个神经网络的输入,在处理图像的卷积神经网络中,它一般代表了一张图片的像素矩阵。
  2. 卷积层。从名字就可以看出,卷积层是一个卷积神经网络中最重要的部分。和传统的全连接层不容,卷积层中每一个介蒂安的输入只是上一层神经网络的一小块。这个小块常用的大小为33或者5。卷积层试图将神经网络中每一个小块进行更加深入的分析从而得到抽象程度更高的特征。一般来说,通过卷积层处理过的节点矩阵会变得更深。
  3. 池化层(Pooling)。池化层神经网络不会改变三维矩阵的深度,但是它可以缩小矩阵的大小。池化操作可以认为使将一张分辨率较高的图片转换为一张分辨率较低的图片。通过池化层,可以进一步缩小最后全连接层结点的个数,从而达到减少整个神经网络中参数的目的。
  4. 全连接层。在经过多轮卷积层和池化层的处理之后,在卷积神经网络的最后一般是由一到两个全连接层来给出最后的分类结果。经过几轮卷积层和池化层的处理之后,可以认为图像中的信息已经被抽象成了信息含量更高的特征。我们可以将卷积层和池化层看成自动图像特征提取的过程。在特质提取完成之后,仍然需要使用全连接层来完成分类任务。
  5. Softmax层。Softmax主要用于分类问题。通过Softmax层,可以得到当前样例属于不同种类的概率分布情况。

2. 过滤器

(1)分解图像

CNN的第一步是将图像分解成较小的碎片。我们通过选择定义过滤器的宽度和高度来做到这一点。
然后,我们可以简单地水平或垂直滑动此滤镜以聚焦在另一幅图像上。

过滤器滑动的量称为“步幅”。跨度是我们可以调整的超参数。通过减少每一层观察到的总面片数量,增加步幅可减小模型的大小。但是,这通常会降低准确性。

让我们看一个例子。在这张放大的狗的图像中,我们首先以红色概述的补丁开始。滤镜的宽度和高度定义了该正方形的大小。
然后,我们将正方形向右移动给定的步幅(在本例中为2)以获得另一个图片。

(2)过滤器深度

通常有多个过滤器。不同的过滤器选择不同质量的部分。例如,一个过滤器可能查找特定的颜色,而另一个可能查找特定形状的对象。卷积层中过滤器的数量称为 过滤器深度

过滤器尺寸是指的过滤器的输入节点矩阵的大小,深度指的hi输出单位节点矩阵的深度。

假设使用wx,y,ziw_{x,y,z}^iwx,y,zi​来表示对于输出单位节点矩阵中的第iii个节点,过滤器输入节点(x,y,z)( x,y,z)(x,y,z) 的权重,使用bib^ibi表示第iii个输出节点对应的偏置项参数,那么单位矩阵中的第iii个节点的取值g(i)g(i)g(i)为:
g(i)=f(∑x=12∑y=12∑z=13ax,y,z×wx,y,zi+bi)g(i)=f(\sum_{x=1}^{2}\sum_{y=1}^{2}\sum_{z=1}^{3}a_{x,y,z}\times w_{x,y,z}^{i}+b^i)g(i)=f(x=1∑2​y=1∑2​z=1∑3​ax,y,z​×wx,y,zi​+bi)

其中ax,y,za_{x,y,z}ax,y,z​为过滤器中节点(x,y,z)(x,y,z)(x,y,z)的取值, fff为激活函数。下图展示了在给定a,w0a, w^0a,w0和b0b^0b0的情况下,使用ReLU 作为激活函数时g(0)g(0)g(0)的计算过程。在图6-9 的左侧给出了a,w0a, w^0a,w0的取值,这里通过3 个二维矩阵来表示一个三维矩阵的取值,其中每一个二维矩阵表示三维矩阵在某一个深度上的取值。下图中⋅·⋅ 符号表示点积,也就是矩阵中对应元素乘积的和。图6-9 的右侧显示了g(0)g(0 )g(0)的计算过程。如果给出w1w^1w1到w4w^4w4 和b1b^1b1 到b4b^4b4 , 那么也可以类似地计算出g(1)g(1)g(1)到g(4)g(4)g(4)的取值。如果将aaa 和wiw^iwi组织成两个向量,那么一个过滤器的计算过程完全可以通过向量乘法来完成。

当过滤器的大小不为l × l 时, 卷积层前向传播得到的矩阵的尺寸要小于当前层矩阵的尺寸。如下图所示, 当前层矩阵的大小为3 × 3 (左侧矩阵〉,而通过卷积层前向传播算法之后,得到的矩阵大小为2 × 2 (右侧矩阵〉。为了避免尺寸的变化,可以在当前层矩阵的边界上加入全0填充(zero -padding)。这样可以使得卷积层前向传播结果矩阵的大小和当前层矩阵保持一致。

以下公式给出了同时使用全0填充的结果矩阵的大小。

outlength=[inlength/srtidelength]out_{length}=[in_{length}/srtide_{length}]outlength​=[inlength​/srtidelength​]
outwidth=[inwidth/srtidewidth]out_{width}=[in_{width}/srtide_{width}]outwidth​=[inwidth​/srtidewidth​]
如果不使用全0填充,以下公式给出了结果矩阵的大小。
outlength=[(inlength−filterlength+1)/srtidelength]out_{length}=[(in_{length}-filter_{length}+1)/srtide_{length}]outlength​=[(inlength​−filterlength​+1)/srtidelength​]
outwidth=[(inwidth−filterwidth+1)/srtidewidth]out_{width}=[(in_{width}-filter_{width}+1)/srtide_{width}]outwidth​=[(inwidth​−filterwidth​+1)/srtidewidth​]

TensorFlow 对卷积神经网络提供了非常好的支持,以下程序实现了一个卷积层的前向传播过程。从以下代码可以看出,通过TensorFlow 实现卷积层是非常方便的。

filter_weight = tf.get_variable ('weights',[5, 5, 3, 16], initializer=tf .truncated_normal_initializer(stddev=0.1))biases = tf.get_variable('biases', [16], initializer=tf.constant_initializer ( 0 .1) )conv = tf.nn.conv2d(input , filter_weight, strides=[1, 1, 1, 1], padding ='SAME')bias= tf.nn.bias add(conv, biases)actived_conv = tf.nn.relu(bias)

3.卷积层

TensorFlow提供tf.nn.conv2d()tf.nn.bias_add()功能来创建卷积层。

# 输出深度
k_output = 64# 图像属性
image_width = 10
image_height = 10
color_channels = 3# 卷积过滤器
filter_size_width = 5
filter_size_height = 5# 输入图片
input = tf.placeholder(tf.float32,shape=[None, image_height, image_width, color_channels])# 权重和偏置
weight = tf.Variable(tf.truncated_normal([filter_size_height, filter_size_width, color_channels, k_output]))
bias = tf.Variable(tf.zeros(k_output))# 应用卷积
conv_layer = tf.nn.conv2d(input, weight, strides=[1, 2, 2, 1], padding='SAME')
# 添加偏置
conv_layer = tf.nn.bias_add(conv_layer, bias)
# 应用激活函数
conv_layer = tf.nn.relu(conv_layer)

上面的代码使用tf.nn.conv2d()函数来计算以权重为过滤器的卷积,并使用[1,2,2,1]来计算步幅。TensorFlow对每个输入维度使用一个stride[batch, input_height, input_width, input_channels]。我们通常总是将batchinput_channels(即strides组中的第一个和第四个元素)的步长设置为1。

更改input_heightinput_width,同时将batchinput_channels设置为1。input_heightinput_widthstrides用于跨越input的过滤器。此示例代码在输入上使用了带有5x5过滤器的2步。

tf.nn.bias_add()函数在矩阵的最后一个维度上添加一维偏置。

例如,卷积第三层输出:

4.池化层

在卷积层之间往往会加上一个池化层( pooling layer )。池化层可以非常有效地缩小矩阵的尺寸 ,从而减少最后全连接层中的参数。使用池化层既可以加快计算速度也有防止过拟合问题的作用。

池化层前向传播的过程也是通过移动一个类似过滤器的结构完成的。不过池化层过滤器中的计算不是节点的加权和,而是采用更加简单的最大值或者平均值运算。使用最大值操作的池化层被称之为最大池化层( max pooling ), 这是被使用得最多的池化层结构。使用平均值操作的池化层被称之为平均池化层(average pooling )。

与卷积层的过滤器类似,池化层的过滤器也需要人工设定过滤器的尺寸、是否使用全0填充以及过滤器移动的步长等设置,而且这些设置的意义也是一样的。卷积层和池化层中过滤器移动的方式是相似的,唯一的区别在于卷积层使用的过滤器是横跨整个深度的,而池化层使用的过滤器只影响一个深度上的节点。所以池化层的过滤器除了在长和宽两个维度移动,它还需要在深度这个维度移动。

不同颜色或者不同线段(虚线或者实线)代表了不同的池化层过滤器。从上图中可以轩出,池化层的过滤器除了在长和宽的维度上移动,它还需要在深度的维
度上移动。以下TensorFlow 程序实现了最大池化层的前向传播算法。

# tf.nn.max pool 实现了最大池化层的前向传播过程,它的参数和tf.nn.conv2d 函数类似。
# ksize 提供了过滤器的尺寸, strides 提供了步长信息, padding 提供了是否使用全0 填充。
pool= tf.nn.max pool(actived_conv, ksize=[1, 3 , 3, 1], strides=[l , 2, 2, 1), padding='SAME')

对比池化层和卷积层前向传播在TensorFlow 中的实现,可以发现函数的参数形式是相似的。在tf.nn.max_pool函数中, 首先需要传入当前层的节点矩阵,这个矩阵是一个四维矩阵,格式和tf.nn.conv2d函数中的第一个参数一致。第二个参数为过滤器的尺寸。虽然给出的是一个长度为4 的一维数组,但是这个数组的第一个和最后一个数必须为1 。这意味着池化层的过滤器是不可以跨不同输入样例或者节点矩阵深度的。在实际应用中使用得最多的池化层过滤器尺寸为[1,2,2,1][ 1, 2, 2 ,1][1,2,2,1]或者[1,3,3,1][ 1, 3, 3, 1][1,3,3,1]。

tf.nn.max pool 函数的第三个参数为步长,它和tf.nn.conv2d 函数中步长的意义是一样的,而且第一维和最后一维也只能为1。这意味着在Tensor Flow 中,池化层不能减少节点矩阵的深度或者输入样例的个数。tf.nn.max_pool 函数的最后一个参数指定了是否使用全0填充。这个参数也凡有两种取值一VALID 或者SAME ,其中VALID 表示不使用全0 填充,SAME 表示使用全0 填充。TensorFlow 还提供了tf.nn.avg_pool 来实现平均池化层。tf.nn.avg_pool函数的调用格式和tf.nn.max_pool 函数是一致的。

最近,池层已不再受欢迎。原因如下:

  • 最近的数据集如此庞大和复杂,我们更加担心拟合不足。
  • dropout是一个更好的正则化器。
  • 合并会导致信息丢失。以最大池化操作为例。我们只保留n个数字中的最大值,从而完全忽略n-1个数字。

5.程序

from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets(".", one_hot=True, reshape=False)import tensorflow as tf# gpu参数
gpu_options = tf.GPUOptions(per_process_gpu_memory_fraction=0.333)# 参数
learning_rate = 0.00001
epochs = 10
batch_size = 128# 计算验证和准确性样本的数量
# 如果计算精度的内存不足,请减少此值
test_valid_size = 256# 网络参数
n_classes = 10  # MNIST的全部类别 (0-9 digits)
dropout = 0.75  # Dropout, 保持单位的概率# 存储层的权重和偏置
weights = {'wc1': tf.Variable(tf.random_normal([5, 5, 1, 32])),'wc2': tf.Variable(tf.random_normal([5, 5, 32, 64])),'wd1': tf.Variable(tf.random_normal([7*7*64, 1024])),'out': tf.Variable(tf.random_normal([1024, n_classes]))}biases = {'bc1': tf.Variable(tf.random_normal([32])),'bc2': tf.Variable(tf.random_normal([64])),'bd1': tf.Variable(tf.random_normal([1024])),'out': tf.Variable(tf.random_normal([n_classes]))}def conv2d(x, W, b, strides=1):x = tf.nn.conv2d(x, W, strides=[1, strides, strides, 1], padding='SAME')x = tf.nn.bias_add(x, b)return tf.nn.relu(x)def maxpool2d(x, k=2):return tf.nn.max_pool(x, ksize=[1, k, k, 1], strides=[1, k, k, 1], padding='SAME')def conv_net(x, weights, biases, dropout):# Layer 1 - 28*28*1 to 14*14*32conv1 = conv2d(x, weights['wc1'], biases['bc1'])conv1 = maxpool2d(conv1, k=2)# Layer 2 - 14*14*32 to 7*7*64conv2 = conv2d(conv1, weights['wc2'], biases['bc2'])conv2 = maxpool2d(conv2, k=2)# Fully connected layer - 7*7*64 to 1024fc1 = tf.reshape(conv2, [-1, weights['wd1'].get_shape().as_list()[0]])fc1 = tf.add(tf.matmul(fc1, weights['wd1']), biases['bd1'])fc1 = tf.nn.relu(fc1)fc1 = tf.nn.dropout(fc1, dropout)# Output Layer - class prediction - 1024 to 10out = tf.add(tf.matmul(fc1, weights['out']), biases['out'])return out# tf 计算图输入
x = tf.placeholder(tf.float32, [None, 28, 28, 1])
y = tf.placeholder(tf.float32, [None, n_classes])
keep_prob = tf.placeholder(tf.float32)# 模型
logits = conv_net(x, weights, biases, keep_prob)# 定义损失和优化
cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=logits, labels=y))
optimizer = tf.train.GradientDescentOptimizer(learning_rate=learning_rate).minimize(cost)# 准确率
correct_pred = tf.equal(tf.argmax(logits, 1), tf.argmax(y, 1))
accuracy = tf.reduce_mean(tf.cast(correct_pred, tf.float32))# 初始化变量
init = tf.global_variables_initializer()# 启动计算图
with tf.Session(config=tf.ConfigProto(gpu_options=gpu_options)) as sess:sess.run(init)for epoch in range(epochs):for batch in range(mnist.train.num_examples//batch_size):batch_x, batch_y = mnist.train.next_batch(batch_size)sess.run(optimizer, feed_dict={x: batch_x, y: batch_y, keep_prob: dropout})# 计算一个batch的损失和准确性loss = sess.run(cost, feed_dict={x: batch_x, y: batch_y, keep_prob: 1.})valid_acc = sess.run(accuracy, feed_dict={x: mnist.validation.images[:test_valid_size],y: mnist.validation.labels[:test_valid_size],keep_prob: 1.})print('Epoch {:>2}, Batch {:>3} - Loss: {:>10.4f} Validation Accuracy: {:.6f}'.format(epoch + 1,batch + 1,loss,valid_acc))# 计算测试精度test_acc = sess.run(accuracy, feed_dict={x: mnist.test.images[:test_valid_size],y: mnist.test.labels[:test_valid_size],keep_prob: 1.})print('Testing Accuracy: {}'.format(test_acc))

输出如下:

Epoch  1, Batch   1 - Loss: 42201.4062 Validation Accuracy: 0.113281
Epoch  1, Batch   2 - Loss: 38468.5820 Validation Accuracy: 0.125000
...
Epoch 10, Batch 428 - Loss:   177.6433 Validation Accuracy: 0.835938
Epoch 10, Batch 429 - Loss:   194.3704 Validation Accuracy: 0.835938
Testing Accuracy: 0.84765625

其中:

# gpu参数
gpu_options = tf.GPUOptions(per_process_gpu_memory_fraction=0.333)
...
with tf.Session(config=tf.ConfigProto(gpu_options=gpu_options)) as sess:
...

这两行是因为我使用了gpu训练模型才加上的,如果不使用gpu可以不加。

在下个笔记将介绍Fashion-MNIST,将使用卷积神经网络对十种不同得服饰进行区分。

Udacity机器人软件工程师课程笔记(二十七) - 卷积神经网络(CNN)相关推荐

  1. Udacity机器人软件工程师课程笔记(五)-样本搜索和找回-基于漫游者号模拟器-自主驾驶

    9.自主驾驶 在接下来的环节中,我们要实现漫游者号的自动驾驶功能. 完成这个功能我们需要四个程序,第一个为感知程序,其对摄像头输入的图片进行变换处理和坐标变换使用.第二个程序为决策程序,功能是帮助漫游 ...

  2. Udacity机器人软件工程师课程笔记(七)-ROS介绍和Turtlesim包的使用

    Robotics Software engineer笔记 1.ROS简介与虚拟机配置 (1)ROS简介 ROS是一款机器人软件框架,即机器人操作系统(Robot Operating System). ...

  3. Udacity机器人软件工程师课程笔记(二十四) - 控制(其二) - PID优化,梯度下降算法,带噪声的PID控制

    7.非理想情况 (1)积分饱和 到目前为止,我们一直使用的"理想"形式的PID控制器很少用于工业中."时间常数"形式更为常见. 当前说明了理想形式的一些重大缺陷 ...

  4. Udacity机器人软件工程师课程笔记(三十二) - 卡尔曼滤波器 - 一维卡尔曼滤波器 - 多维卡尔曼滤波器 - 拓展卡尔曼滤波器(EKF)

    卡尔曼滤波器 一.概述 二.一维高斯分布 均值和方差 三.一维卡尔曼滤波器 变量命名约定 卡尔曼滤波循环 1.测量值更新 (1)平均值计算 (2)程序实现 2.位置预测 位置预测公式 3.一维卡尔曼滤 ...

  5. Udacity机器人软件工程师课程笔记(二十一) - 对点云进行集群可视化 - 聚类的分割 - K-means|K均值聚类, DBSCAN算法

    聚类的分割 1.K-均值聚类 (1)K-均值聚类介绍 k均值聚类算法(k-means clustering algorithm)是一种迭代求解的聚类分析算法,其步骤是随机选取K个对象作为初始的聚类中心 ...

  6. Udacity机器人软件工程师课程笔记(二十) - 感知 - 校准,过滤, 分段, RANSAC

    校准,过滤, 分段, RANSAC 首先,我们将讨论传感器校准,也就是说,从几何形状,失真和噪声方面校准相机如何看待周围的世界.了解相机的校准对于了解测量数据如何代表实际物理环境至关重要. 之后,我们 ...

  7. Udacity机器人软件工程师课程笔记(二)-样本搜索和找回-基于漫游者号模拟器

    Robotics Software engineer编程笔记(二) 5.确定漫游者号的行进方向 (1)漫游者号如何确定自己的行进方向? 我们已经有了一个由前置摄像头得到的图像,然后可以通过对图像进行处 ...

  8. Udacity机器人软件工程师课程笔记(二十五) - 使用PID控制四轴飞行器 - 四轴飞行器(四旋翼)模拟器

    1.四轴飞行器运动学和动力学模型 在讨论四轴飞行器时,明确定义两个参考坐标系会很有帮助:一个固定的世界坐标系W{W}W和一个牢固地附着到四轴飞行器的质心(CoM)的运动坐标系B{B}B. 假设运动坐标 ...

  9. Udacity机器人软件工程师课程笔记(二十三) - 控制(其一)- PID控制及其python实现

    控制(Controls) 1.PID控制简介 在工程实际中,应用最为广泛的调节器控制规律为比例.积分.微分控制,简称PID控制,又称PID调节.PID控制器问世至今已有近70年历史,它 以其结构简单. ...

最新文章

  1. Sql Server之旅——第十一站 简单说说sqlserver的执行计划
  2. 第一个通过HCIEv3.0的咱的学员
  3. 线性结构 -- 连续存储(数组), 1个简单的c语言代码实现.
  4. 基于java的社交网站毕业设计_软件工程毕业设计_社交网站.pdf
  5. 微信屏蔽百度红包活动页面,谁在焦虑?
  6. 技术总监谈好的程序员如何写代码[转]
  7. 汉王考勤 连接mysql_汉王考勤管理软件打开时出现:连接数据错误,请确认数据库服务器信息是否有误。这样该怎样解决?...
  8. woocommerce修改商品详情页
  9. 学习java一般多久
  10. 不同证券的资产收益率统计(2012-2020年)
  11. 史上最全各种简历模板,自荐信模板和面试技巧
  12. 什么是iBeacon?
  13. 验证码短信收不到的原因及解决办法
  14. 解决:Excel 下拉项数据报 输入内容不能大于255个字符
  15. 【Android】虚拟环绕声
  16. oracle 伪列访问序列,Oracle同义词与序列基础教程
  17. 使用当前主流的github管理项目代码(记我的第一次项目创建)
  18. java就是我的幸福,我的幸福我的人生
  19. 回顾2012年重大安全事件
  20. oracle erp和金蝶,什么是erp系统,集体和个人选择时有哪些不同

热门文章

  1. java.util.Collections.synchronizedSet()方法的使用
  2. 管理员技术(六): 硬盘分区及格式化、 新建一个逻辑卷、调整现有磁盘的分区、扩展逻辑卷的大小、添加一个swap分区...
  3. CentOS7部署ELK5.2
  4. 写给自己的web开发资源
  5. 把mysql 中的字符gb2312 改为gbk的方法
  6. DataGrid和GridView单击背景变色双击颜色还原
  7. 成功将BlogEngine 1.5 升级到了BlogEngine 2.0
  8. SQL Server 中print Datetime类型问题
  9. ASP.NET 2.0 ajax中gridView的刷新问题!
  10. fcm算法的MATLAB实现,FCM算法的matlab程序(初步)