现有的Caffe、TensorFlow等工具箱曾经很好地完成CNN模型,但这些工具箱需求的硬件资源比较多,不利于初学者理论和了解。因而,本文教大家如何仅运用NumPy来构建卷积神经网络(Convolutional Neural Network , CNN)模型,细致完成了卷积层、ReLU激活函数层以及最大池化层(max pooling),代码简单,解说细致。 目前网络上存在很多编译好的机器学习、深度学习工具箱,在某些状况下,直接调用曾经搭好的模型可能是十分方便且有效的,好比Caffe、TensorFlow工具箱,但这些工具箱需求的硬件资源比较多,不利于初学者理论和了解。因而,为了更好的了解并控制相关学问,最好是能够自己编程理论下。本文将展示如何运用NumPy来构建卷积神经网络(Convolutional Neural Network , CNN)。 CNN是较早提出的一种神经网络,直到近年来才变得火热,能够说是计算机视觉范畴中应用最多的网络。一些工具箱中曾经很好地完成CNN模型,相关的库函数曾经完整编译好,开发人员只需调用现有的模块即可完成模型的搭建,避免了完成的复杂性。但实践上,这样会使得开发人员不知道其中细致的完成细节。有些时分,数据科学家必须经过一些细节来提升模型的性能,但这些细节是工具箱不具备的。在这种状况下,独一的处置计划就是自己编程完成一个相似的模型,这样你对完成的模型会有最高级别的控制权,同时也能更好天文解模型每步的处置过程。 本文将仅运用NumPy完成CNN网络,创建三个层模块,分别为卷积层(Conv)、ReLu激活函数和最大池化(max pooling)。 一、读取输入图像 以下代码将从skimage Python库中读取曾经存在的图像,并将其转换为灰度图:
读取图像是第一步,下一步的操作取决于输入图像的大小。将图像转换为灰度图如下所示:
二、准备滤波器 以下代码为第一个卷积层Conv准备滤波器组(Layer 1,缩写为l1,下同): 依据滤波器的数目和每个滤波器的大小来创建零数组。上述代码创建了2个3x3大小的滤波器,(2,3,3)中的元素数字分别表示2:滤波器的数目(num_filters)、3:表示滤波器的列数、3:表示滤波器的行数。由于输入图像是灰度图,读取后变成2维图像矩阵,因而滤波器的尺寸选择为2维阵列,舍去了深度。假如图像是彩色图(具有3个通道,分别为RGB),则滤波器的大小必须为(3,3,3),最后一个3表示深度,上述代码也要更改,变成(2,3,3,3)。 滤波器组的大小由自己指定,但没有给定滤波器中细致的数值,普通采用随机初始化。下列一组值能够用来检查垂直和水平边沿:
三、卷积层(Conv Layer) 构建好滤波器后,接下来就是与输入图像中止卷积操作。下面代码运用conv函数将输入图像与滤波器组中止卷积: conv函数只接受两个参数,分别为输入图像、滤波器组:
该函数首先确保每个滤波器的深度等于图像通道的数目,代码如下。if语句首先检查图像与滤波器能否有一个深度通道,若存在,则检查其通道数能否相等,假如匹配不胜利,则报错。
此外,滤波器的大小应该是奇数,且每个滤波器的大小是相等的。这是依据下面两个if条件语块来检查的。假如条件不满足,则程序报错并退出。
上述条件都满足后,经过初始化一个数组来作为滤波器的值,经过下面代码来指定滤波器的值:
由于没有设置步幅(stride)或填充(padding),默许为步幅设置为1,无填充。那么卷积操作后得到的特征图大小为(img_rows-filter_rows+1, image_columns-filter_columns+1, num_filters),即输入图像的尺寸减去滤波器的尺寸后再加1。留意到,每个滤波器都会输出一个特征图。
循环遍历滤波器组中的每个滤波器后,经过下面代码更新滤波器的状态: 假如输入图像不止一个通道,则滤波器必须具有同样的通道数目。只需这样,卷积过程才干正常中止。最后将每个滤波器的输出求和作为输出特征图。下面的代码检测输入图像的通道数,假如图像只需一个通道,那么一次卷积即可完成整个过程:
上述代码中conv_函数与之前的conv函数不同,函数conv只接受输入图像和滤波器组这两个参数,自身并不中止卷积操作,它只是设置用于conv_函数执行卷积操作的每一组输入滤波器。下面是conv_函数的完成代码:
每个滤波器在图像上迭代卷积的尺寸相同,经过以下代码完成: 之后,在图像区域矩阵和滤波器之间对位相乘,并将结果求和以得到单值输出:
输入图像与每个滤波器卷积后,经过conv函数返回特征图。下图显现conv层返回的特征图(由于l1卷积层的滤波器参数为(2,3,3),即2个3x3大小的卷积核,最终输出2个特征图):
卷积后图像 卷积层的后面普通跟着激活函数层,本文采用ReLU激活函数。 四、ReLU激活函数层 ReLU层将ReLU激活函数应用于conv层输出的每个特征图上,依据以下代码行调用ReLU激活函数: ReLU激活函数(ReLU)的细致完成代码如下:
ReLU思想很简单,只是将特征图中的每个元素与0中止比较,若大于0,则保存原始值。否则将其设置为0。ReLU层的输出如下图所示:
ReLU层输出图像 激活函数层后面普通紧跟池化层,本文采用最大池化(max pooling)。 五 、最大池化层 ReLU层的输出作为最大池化层的输入,依据下面的代码行调用最大池化操作: 最大池化函数(max pooling)的细致完成代码如下:
该函数接受3个参数,分别为ReLU层的输出,池化掩膜的大小和步幅。首先也是创建一个空数组,用来保存该函数的输出。数组大小依据输入特征图的尺寸、掩膜大小以及步幅来肯定。
对每个输入特征图通道都中止最大池化操作,返回该区域中最大的值,代码如下: 池化层的输出如下图所示,这里为了显现让其图像大小看起来一样,其实池化操作后图像尺寸远远小于其输入图像。
池化层输出图像 六、层堆叠 以上内容曾经完成CNN结构的基本层——conv、ReLU以及max pooling,往常将其中止堆叠运用,代码如下:
从代码中能够看到,l2表示第二个卷积层,该卷积层运用的卷积核为(3,5,5),即3个5x5大小的卷积核(滤波器)与第一层的输出中止卷积操作,得到3个特征图。后续接着中止ReLU激活函数以及最大池化操作。将每个操作的结果可视化,如下图所示:
l2层处置过程可视化图像
从代码中能够看到,l3表示第三个卷积层,该卷积层运用的卷积核为(1,7,7),即1个7x7大小的卷积核(滤波器)与第二层的输出中止卷积操作,得到1个特征图。后续接着中止ReLU激活函数以及最大池化操作。将每个操作的结果可视化,如下图所示:
l3层处置过程可视化图像 神经网络的基本结构是前一层的输出作为下一层的输入,好比l2层接纳l1层的输出,l3层接纳来l2层的输出,代码如下:
七、完好代码 全部代码曾经上传至Github上,每层的可视化是运用Matplotlib库完成。 地址:https://github.com/ahmedfgad/NumPyCNN?spm=a2c4e.11153940.blogcont585741.15.3c951357xsKixt 译者:海棠,审校:Uncle_LLD。 |