学习内容:
参考:https://www.jianshu.com/p/f4f3b3790509
卷积神经网络(ConvolutionalNeural Network,CNN)是人工神经网络的一种。当前已经成为图像和语音识别领域有十分广泛的应用,特别是在识别位移、缩放及其他形式扭曲不变性的二维图形方面有十分优异的表现,已经成为一个十分重要的研究方向。
CNN是较早提出的一种神经网络,直到近年来才变得火热,可以说是计算机视觉领域中应用最多的网络。一些工具箱中已经很好地实现CNN模型,相关的库函数已经完全编译好,开发人员只需调用现有的模块即可完成模型的搭建,避免了实现的复杂性。但实际上,这样会使得开发人员不知道其中具体的实现细节。有些时候,数据科学家必须通过一些细节来提升模型的性能,但这些细节是工具箱不具备的。在这种情况下,唯一的解决方案就是自己编程实现一个类似的模型,这样你对实现的模型会有最高级别的控制权,同时也能更好地理解模型每步的处理过程。
1.读取输入图像
以下代码将从skimage Python库中读取已经存在的图像,并将其转换为灰度图:
1. import skimage.data
2. # Reading the image
3. img = skimage.data.chelsea()
4. # Converting the image into gray.
5. img = skimage.color.rgb2gray(img)js
2.准备滤波器
以下代码为第一个卷积层Conv准备滤波器组(Layer 1,缩写为l1,下同):
1. l1_filter = numpy.zeros((2,3,3))
根据滤波器的数目和每个滤波器的大小来创建零数组。上述代码创建了2个3x3大小的滤波器,(2,3,3)中的元素数字分别表示2:滤波器的数目(num_filters)、3:表示滤波器的列数、3:表示滤波器的行数。由于输入图像是灰度图,读取后变成2维图像矩阵,因此滤波器的尺寸选择为2维阵列,舍去了深度。如果图像是彩色图(具有3个通道,分别为RGB),则滤波器的大小必须为(3,3,3),最后一个3表示深度,上述代码也要更改,变成(2,3,3,3)。
滤波器组的大小由自己指定,但没有给定滤波器中具体的数值,一般采用随机初始化。下列一组值可以用来检查垂直和水平边缘:
3.卷积层(Conv Layer)
构建好滤波器后,接下来就是与输入图像进行卷积操作。下面代码使用conv函数将输入图像与滤波器组进行卷积:
1. l1_feature_map = conv(img, l1_filter)
conv函数只接受两个参数,分别为输入图像、滤波器组
该函数首先确保每个滤波器的深度等于图像通道的数目,代码如下。if语句首先检查图像与滤波器是否有一个深度通道,若存在,则检查其通道数是否相等,如果匹配不成功,则报错。
1. if len(img.shape) > 2 or len(conv_filter.shape) > 3: # Check if number of image channels matches the filter depth.
2. if img.shape[-1] != conv_filter.shape[-1]:
3. print("Error: Number of channels in both image and filter must match.")
此外,滤波器的大小应该是奇数,且每个滤波器的大小是相等的。这是根据下面两个if条件语块来检查的。如果条件不满足,则程序报错并退出。
1. if conv_filter.shape[1] != conv_filter.shape[2]: # Check if filter dimensions are equal.
2. print('Error: Filter must be a square matrix. I.e. number of rows and columns must match.')
3. sys.exit()
4. if conv_filter.shape[1]%2==0: # Check if filter diemnsions are odd.
5. print('Error: Filter must have an odd size. I.e. number of rows and columns must be odd.')
6. sys.exit()
上述条件都满足后,通过初始化一个数组来作为滤波器的值,通过下面代码来指定滤波器的值:
1. # An empty feature map to hold the output of convolving the filter(s) with the image. 2. feature_maps = numpy.zeros((img.shape[0]-conv_filter.shape[1]+1,
3. img.shape[1]-conv_filter.shape[1]+1,
4. conv_filter.shape[0]))
由于没有设置步幅(stride)或填充(padding),默认为步幅设置为1,无填充。那么卷积操作后得到的特征图大小为(img_rows-filter_rows+1, image_columns-filter_columns+1, num_filters),即输入图像的尺寸减去滤波器的尺寸后再加1。注意到,每个滤波器都会输出一个特征图。
循环遍历滤波器组中的每个滤波器后,通过下面代码更新滤波器的状态:
1. curr_filter = conv_filter[filter_num, :] # getting a filter from the bank.
如果输入图像不止一个通道,则滤波器必须具有同样的通道数目。只有这样,卷积过程才能正常进行。最后将每个滤波器的输出求和作为输出特征图。下面的代码检测输入图像的通道数,如果图像只有一个通道,那么一次卷积即可完成整个过程:
1. if len(curr_filter.shape) > 2:
2. conv_map = conv_(img[:, :, 0], curr_filter[:, :, 0]) # Array holding the sum of all feature map
3. for ch_num in range(1, curr_filter.shape[-1]): # Convolving each channel with the image and summing the results.
4. conv_map = conv_map + conv_(img[:, :, ch_num],
5. curr_filter[:, :, ch_num])
6. else: # There is just a single channel in the filter.
7. conv_map = conv_(img, curr_filter)
4.ReLU激活函数层
ReLU层将ReLU激活函数应用于conv层输出的每个特征图上,根据以下代码行调用ReLU激活函数:
l1_feature_map_relu= relu(l1_feature_map)