西安网站排名公司,上海工商网查询官网,企业黄页注册,什么样式表一般用于大型网站摘要#xff1a; 现有的Caffe、TensorFlow等工具箱已经很好地实现CNN模型#xff0c;但这些工具箱需要的硬件资源比较多#xff0c;不利于初学者实践和理解。因此#xff0c;本文教大家如何仅使用NumPy来构建卷积神经网络#xff08;Convolutional Neural Network , CNN 现有的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。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。 滤波器组的大小由自己指定但没有给定滤波器中具体的数值一般采用随机初始化。下列一组值可以用来检查垂直和水平边缘1. l1_filter[0, :, :] numpy.array([[[-1, 0, 1],
2. [-1, 0, 1],
3. [-1, 0, 1]]])
4. l1_filter[1, :, :] numpy.array([[[1, 1, 1],
5. [0, 0, 0],
6. [-1, -1, -1]]]) 3.卷积层Conv Layer 构建好滤波器后接下来就是与输入图像进行卷积操作。下面代码使用conv函数将输入图像与滤波器组进行卷积1. l1_feature_map conv(img, l1_filter) conv函数只接受两个参数分别为输入图像、滤波器组1. def conv(img, conv_filter):
2. if len(img.shape) 2 or len(conv_filter.shape) 3: # Check if number of image channels matches the filter depth.
3. if img.shape[-1] ! conv_filter.shape[-1]:
4. print(Error: Number of channels in both image and filter must match.)
5. sys.exit()
6. if conv_filter.shape[1] ! conv_filter.shape[2]: # Check if filter dimensions are equal.
7. print(Error: Filter must be a square matrix. I.e. number of rows and columns must match.)
8. sys.exit()
9. if conv_filter.shape[1]%20: # Check if filter diemnsions are odd.
10. print(Error: Filter must have an odd size. I.e. number of rows and columns must be odd.)
11. sys.exit()
12.
13. # An empty feature map to hold the output of convolving the filter(s) with the image.
14. feature_maps numpy.zeros((img.shape[0]-conv_filter.shape[1]1,
15. img.shape[1]-conv_filter.shape[1]1,
16. conv_filter.shape[0]))
17.
18. # Convolving the image by the filter(s).
19. for filter_num in range(conv_filter.shape[0]):
20. print(Filter , filter_num 1)
21. curr_filter conv_filter[filter_num, :] # getting a filter from the bank.
22.
23. Checking if there are mutliple channels for the single filter.
24. If so, then each channel will convolve the image.
25. The result of all convolutions are summed to return a single feature map.
26.
27. if len(curr_filter.shape) 2:
28. conv_map conv_(img[:, :, 0], curr_filter[:, :, 0]) # Array holding the sum of all feature maps.
29. for ch_num in range(1, curr_filter.shape[-1]): # Convolving each channel with the image and summing the results.
30. conv_map conv_map conv_(img[:, :, ch_num],
31. curr_filter[:, :, ch_num])
32. else: # There is just a single channel in the filter.
33. conv_map conv_(img, curr_filter)
34. feature_maps[:, :, filter_num] conv_map # Holding feature map with the current filter.
35. return feature_maps # Returning all feature maps. 该函数首先确保每个滤波器的深度等于图像通道的数目代码如下。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]%20: # 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_rows1, image_columns-filter_columns1, num_filters即输入图像的尺寸减去滤波器的尺寸后再加1。注意到每个滤波器都会输出一个特征图。1. # Convolving the image by the filter(s).
2. for filter_num in range(conv_filter.shape[0]):
3. print(Filter , filter_num 1)
4. curr_filter conv_filter[filter_num, :] # getting a filter from the bank.
5.
6. Checking if there are mutliple channels for the single filter.
7. If so, then each channel will convolve the image.
8. The result of all convolutions are summed to return a single feature map.
9.
10. if len(curr_filter.shape) 2:
11. conv_map conv_(img[:, :, 0], curr_filter[:, :, 0]) # Array holding the sum of all feature maps.
12. for ch_num in range(1, curr_filter.shape[-1]): # Convolving each channel with the image and summing the results.
13. conv_map conv_map conv_(img[:, :, ch_num],
14. curr_filter[:, :, ch_num])
15. else: # There is just a single channel in the filter.
16. conv_map conv_(img, curr_filter)
17. feature_maps[:, :, filter_num] conv_map # Holding feature map with the current filter. 循环遍历滤波器组中的每个滤波器后通过下面代码更新滤波器的状态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) 上述代码中conv_函数与之前的conv函数不同函数conv只接受输入图像和滤波器组这两个参数本身并不进行卷积操作它只是设置用于conv_函数执行卷积操作的每一组输入滤波器。下面是conv_函数的实现代码1. def conv_(img, conv_filter):
2. filter_size conv_filter.shape[0]
3. result numpy.zeros((img.shape))
4. #Looping through the image to apply the convolution operation.
5. for r in numpy.uint16(numpy.arange(filter_size/2,
6. img.shape[0]-filter_size/2-2)):
7. for c in numpy.uint16(numpy.arange(filter_size/2, img.shape[1]-filter_size/2-2)):
8. #Getting the current region to get multiplied with the filter.
9. curr_region img[r:rfilter_size, c:cfilter_size]
10. #Element-wise multipliplication between the current region and the filter.
11. curr_result curr_region * conv_filter
12. conv_sum numpy.sum(curr_result) #Summing the result of multiplication.
13. result[r, c] conv_sum #Saving the summation in the convolution layer feature map.
14.
15. #Clipping the outliers of the result matrix.
16. final_result result[numpy.uint16(filter_size/2):result.shape[0]-numpy.uint16(filter_size/2),
17. numpy.uint16(filter_size/2):result.shape[1]-numpy.uint16(filter_size/2)]
18. return final_result 每个滤波器在图像上迭代卷积的尺寸相同通过以下代码实现1. curr_region img[r:rfilter_size, c:cfilter_size] 之后在图像区域矩阵和滤波器之间对位相乘并将结果求和以得到单值输出1. #Element-wise multipliplication between the current region and the filter.
2. curr_result curr_region * conv_filter
3. conv_sum numpy.sum(curr_result) #Summing the result of multiplication.
4. result[r, c] conv_sum #Saving the summation in the convolution layer feature map. 输入图像与每个滤波器卷积后通过conv函数返回特征图。下图显示conv层返回的特征图由于l1卷积层的滤波器参数为2,3,3即2个3x3大小的卷积核最终输出2个特征图卷积后图像卷积层的后面一般跟着激活函数层本文采用ReLU激活函数。4.ReLU激活函数层 ReLU层将ReLU激活函数应用于conv层输出的每个特征图上根据以下代码行调用ReLU激活函数l1_feature_map_relu relu(l1_feature_map)ReLU激活函数ReLU的具体实现代码如下1. def relu(feature_map):
2. #Preparing the output of the ReLU activation function.
3. relu_out numpy.zeros(feature_map.shape)
4. for map_num in range(feature_map.shape[-1]):
5. for r in numpy.arange(0,feature_map.shape[0]):
6. for c in numpy.arange(0, feature_map.shape[1]):
7. relu_out[r, c, map_num] numpy.max(feature_map[r, c, map_num], 0) ReLU思想很简单只是将特征图中的每个元素与0进行比较若大于0则保留原始值。否则将其设置为0。ReLU层的输出如下图所示ReLU层输出图像激活函数层后面一般紧跟池化层本文采用最大池化max pooling。5.最大池化层 ReLU层的输出作为最大池化层的输入根据下面的代码行调用最大池化操作1. l1_feature_map_relu_pool pooling(l1_feature_map_relu, 2, 2) 最大池化函数max pooling的具体实现代码如下1. def pooling(feature_map, size2, stride2):
2. #Preparing the output of the pooling operation.
3. pool_out numpy.zeros((numpy.uint16((feature_map.shape[0]-size1)/stride),
4. numpy.uint16((feature_map.shape[1]-size1)/stride),
5. feature_map.shape[-1]))
6. for map_num in range(feature_map.shape[-1]):
7. r2 0
8. for r in numpy.arange(0,feature_map.shape[0]-size-1, stride):
9. c2 0
10. for c in numpy.arange(0, feature_map.shape[1]-size-1, stride):
11. pool_out[r2, c2, map_num] numpy.max(feature_map[r:rsize, c:csize])
12. c2 c2 1
13. r2 r2 1 该函数接受3个参数分别为ReLU层的输出池化掩膜的大小和步幅。首先也是创建一个空数组用来保存该函数的输出。数组大小根据输入特征图的尺寸、掩膜大小以及步幅来确定。1. pool_out numpy.zeros((numpy.uint16((feature_map.shape[0]-size1)/stride),
2. numpy.uint16((feature_map.shape[1]-size1)/stride),
3. feature_map.shape[-1])) 对每个输入特征图通道都进行最大池化操作返回该区域中最大的值代码如下pool_out[r2, c2, map_num] numpy.max(feature_map[r:rsize, c:csize]) 池化层的输出如下图所示这里为了显示让其图像大小看起来一样其实池化操作后图像尺寸远远小于其输入图像。池化层输出图像6.层堆叠 以上内容已经实现CNN结构的基本层——conv、ReLU以及max pooling现在将其进行堆叠使用代码如下1. # Second conv layer
2. l2_filter numpy.random.rand(3, 5, 5, l1_feature_map_relu_pool.shape[-1])
3. print(\n**Working with conv layer 2**)
4. l2_feature_map conv(l1_feature_map_relu_pool, l2_filter)
5. print(\n**ReLU**)
6. l2_feature_map_relu relu(l2_feature_map)
7. print(\n**Pooling**)
8. l2_feature_map_relu_pool pooling(l2_feature_map_relu, 2, 2)
9. print(**End of conv layer 2**\n) 从代码中可以看到l2表示第二个卷积层该卷积层使用的卷积核为3,5,5即3个5x5大小的卷积核滤波器与第一层的输出进行卷积操作得到3个特征图。后续接着进行ReLU激活函数以及最大池化操作。将每个操作的结果可视化如下图所示l2层处理过程可视化图像1. # Third conv layer
2. l3_filter numpy.random.rand(1, 7, 7, l2_feature_map_relu_pool.shape[-1])
3. print(\n**Working with conv layer 3**)
4. l3_feature_map conv(l2_feature_map_relu_pool, l3_filter)
5. print(\n**ReLU**)
6. l3_feature_map_relu relu(l3_feature_map)
7. print(\n**Pooling**)
8. l3_feature_map_relu_pool pooling(l3_feature_map_relu, 2, 2)
9. print(**End of conv layer 3**\n 从代码中可以看到l3表示第三个卷积层该卷积层使用的卷积核为1,7,7即1个7x7大小的卷积核滤波器与第二层的输出进行卷积操作得到1个特征图。后续接着进行ReLU激活函数以及最大池化操作。将每个操作的结果可视化如下图所示l3层处理过程可视化图像 神经网络的基本结构是前一层的输出作为下一层的输入比如l2层接收l1层的输出l3层接收来l2层的输出代码如下1. l2_feature_map conv(l1_feature_map_relu_pool, l2_filter)
2. l3_feature_map conv(l2_feature_map_relu_pool, l3_filter)7.完整代码 全部代码已经上传至Github上每层的可视化是使用Matplotlib库实现。本文由阿里云云栖社区组织翻译。文章原标题《Building Convolutional Neural Network using NumPy from Scratch》原文链接