计算机系统应用教程网站

网站首页 > 技术文章 正文

深度学习——卷积神经网络(CNN)入门

btikc 2024-10-22 10:28:55 技术文章 6 ℃ 0 评论

今天小编将跟着大家一起学习和研究深度学习的另一个主题——卷积神经网络(Convolutional Neural Network),也就是我们平常眼熟的 CNN。

卷积神经网络作为当前计算机视觉领域的核心技术,发展到如今已是枝繁叶茂。今天这篇文章是从卷积网络的基本原理讲起,将卷积网络的前向传播和反向传播过程讲清楚,以及如何使用 numpytensorflow 实现卷积网络。

然后会从深度卷积网络的发展历程出发,对主要的经典深度网络进行深度剖析,对计算机视觉的三大核心任务:图像分别、目标检测和图像分割等技术算法进行详细学习和讲解。

卷积神经网络相较于深度神经网络,其主要区别就在于卷积层,卷积层的存在使得神经网络具备更强的学习能力。

除了卷积层之外,池化层(Pooling layer)的存在也使得卷积神经网络的鲁棒性更强,最后则是 DNN 中常见的全连接层(Fully Connected layer)。一个典型的卷积神经网络通常包括这三层。



那到底什么是卷积?

从数学来说,卷积可以理解为一种类似于加权运算一样的操作。在图像处理中,针对图像的像素矩阵,卷积操作就是用一个卷积核来逐行逐列地扫描像素矩阵,并与像素矩阵做元素相乘,以此得到新的像素矩阵。

这个过程是为卷积。其中卷积核也叫过滤器或者滤波器,滤波器在输入像素矩阵上扫过的面积称之为感受野。下面更详细的解释下。


且看上面的动图(这里感谢一下 NG 大大给我们提供这么好的教学资料),我们用一个 3x3 滤波器去扫描一个 5x5 的像素矩阵,用滤波器中每一个元素与像素矩阵中感受到的元素进行乘积运算,可得到了一个 3x3 输出像素矩阵,

这个输出的 3x3 像素矩阵能够较大程度地提取原始像素矩阵的图像特征,这也是卷积神经网络之所以有效的原因。为防止有同学不清楚卷积是如何计算的,下面以输出像素矩阵中的第一个元素 4 为例,演示一下计算过程:

1x1 + 1x0 + 1x1 + 0x0 +1x1 + 1x0 + 0x1 +0x0 + 1x1 = 4

当然,这里你可能会问:如何确定经过卷积后的输出矩阵的维度?我们是有计算公式的。假设原始输入像素矩阵的 shape 为 nxn,滤波器的 shape 为 fxf,那么输出像素矩阵的 shape 为 (n-f+1)x(n-f+1)

大体上卷积操作就是这么个过程,但这里我们也需要注意两个问题:

第一个就是滤波器移动的步幅问题,上面的例子中我们的滤波器的移动步长为 1 ,即在像素矩阵上一格一格平移。但如果滤波器是以两个单位或者更多单位平移呢?这里就涉及到卷积过程中 stride 问题。

第二个问题涉及到卷积操作的两个缺点,第一个缺点在于每次做卷积,你的图像就会变小,可能做了几次卷积之后,你的图像就变成 1x1,这就不好办了。

第二个缺点在于原始输入像素矩阵的边缘和角落的像素点只能被滤波器扫到一次,而靠近像素中心点的像素点则会被多次扫到进行卷积。

这就使得边缘和角落里的像素特征提取不足,这就涉及到卷积过程中的 padding 问题。

针对第一个问题,也就是卷积步长问题,其实也很简单,就是按照正常的卷积过程去操作,只不过每次多走一个像素单位而已。且看卷积步幅为 2 的卷积操作示例:


我们用一个 3x3 的滤波器去对原始像素为 7x7 的图像进行卷积操作,设定卷积步长为 2,可看到输出像素矩阵的第二行第一个元素 69 的计算跨越了两个像素格点,计算过程为:

3x3 + 4x4 + 8x4 + 7x1 + 8x0 + 3x2 + 4x-1 + 2x0 + 1x3 = 69

加入步长之后我们的输出像素矩阵的 shape 的计算公式需要更新一下为:
((n-f)/s+1)x((n-f)/s+1) 。其中 s 为步长。

针对第二个问题,卷积神经网络采用一种叫做 padding 的操作,即对原始像素边缘和角落进行0填充,以期能够在卷积过程中充分利用边缘和角落的像素特征。

至于填充多少 0 像素值,一般有两个选择,一是 valid 填充,也就是不填充,所以就不用管它了。我们在意的是有填充,就是第二种,same 填充方法。

即填充后,输入和输出大小是一致的,对于nxn大小的输入像素,如果你用填充了 p 个像素点之后,n 就变成了 n+2p,最后输出像素的 shape 计算公式就变成了 ((n+2p-f)/s+1)x((n+2p-f)/s+1),要想让 n+2p-f+1=n 的话,输入输出大小相等,则 p=(f-1)/2。所以,一般而言,滤波器的大小 f 都会选择为奇数个。

实际操作中,padding 编程写法如下:

def zero_pad(X, pad):
    X_pad = np.pad(X, ((0,0), (pad, pad), (pad, pad), (0, 0)), 'constant')    
    return X_pad

numpy 一行代码即可搞定。测试效果如下:

np.random.seed(1)
x = np.random.randn(4, 3, 3, 2)
x_pad = zero_pad(x, 2)
fig, axarr = plt.subplots(1, 2)
axarr[0].set_title('x')
axarr[0].imshow(x[0,:,:,0])
axarr[1].set_title('x_pad')
axarr[1].imshow(x_pad[0,:,:,0])

原文链接:

https://mp.weixin.qq.com/s/HmRjpwYly6FdsFMrTmlTlA

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表