前面聊了3期全连接层,下面先扔下它,看看卷积神经网络的另外一个重量级组成部分——卷积层。
关于卷积层的具体计算方式在这里就不多说了,和全连接层类似,由线性部分和非线性部分组成,一会儿直接看代码就好。关于卷积层的计算方法,现在一般来说大家的实现方式都是用“相关”这个操作来进行的,为什么呢?当然是为了计算方便,减少一次把卷积核转一圈的计算。
以下是“卷积层”操作的基本代码,我们后面会做进一步地“升级”的:
- import numpy as np
- import matplotlib.pyplot as plt
- def conv2(X, k):
- x_row, x_col = X.shape
- k_row, k_col = k.shape
- ret_row, ret_col = x_row - k_row + 1, x_col - k_col + 1
- ret = np.empty((ret_row, ret_col))
- for y in range(ret_row):
- for x in range(ret_col):
- sub = X[y : y + k_row, x : x + k_col]
- ret[y,x] = np.sum(sub * k)
- return ret
- class ConvLayer:
- def __init__(self, in_channel, out_channel, kernel_size):
- self.w = np.random.randn(in_channel, out_channel, kernel_size, kernel_size)
- self.b = np.zeros((out_channel))
- def _relu(self, x):
- x[x < 0] = 0
- return x
- def forward(self, in_data):
- # assume the first index is channel index
- in_channel, in_row, in_col = in_data.shape
- out_channel, kernel_row, kernel_col = self.w.shape[1], self.w.shape[2], self.w.shape[3]
- self.top_val = np.zeros((out_channel, in_row - kernel_row + 1, in_col - kernel_col + 1))
- for j in range(out_channel):
- for i in range(in_channel):
- self.top_val[j] += conv2(in_data[i], self.w[i, j])
- self.top_val[j] += self.b[j]
- self.top_val[j] = self._relu(self.topval[j])
- return self.top_val
到这里卷积层就介绍完了,谢谢……
卷积层内心OS:玩儿去,怎么可以戏份这么少……
其实在卷积神经网络这个模型大火之前,卷积这个概念早已深入许多图像处理的小伙伴的内心了。在图像处理中,我们有大批图像滤波算法,其中很多都是像卷积层这样的线性卷积核。为了更清楚地介绍这些核,我们拿一张OCR的训练数据做例子:
- import cv2
- mat = cv2.imread('conv1.png',0)
- row,col = mat.shape
- in_data = mat.reshape(1,row,col)
- in_data = in_data.astype(np.float) / 255
- plt.imshow(in_data[0], cmap='Greys_r')
这个字显示出来是这个样子:
首先是mean kernel,也就是均值滤波:
- meanConv = ConvLayer(1,1,5)
- meanConv.w[0,0] = np.ones((5,5)) / (5 * 5)
- mean_out = meanConv.forward(in_data)
- plt.imshow(mean_out[0], cmap='Greys_r')
结果如下所示:
均值滤波在图像处理中可以起到对模糊图像的作用,当然由于卷积核比较小,所以效果不是很明显。