assignment2的第二部分的内容,实现一个卷积神经网络。这一部分主要是实现卷积神经网络中的一些所需用到的layer类型:卷积层(convolution)和池化层(这里是实现max-pooling)。这部分的实现是不考虑其运行效率,而在真正的实现应用上,卷积神经网络的运行效率是一个很重要的问题。
卷积层
卷积层是由一个个过滤器(filter),每个过滤器的尺寸为:,这里的的大小与输入的图像或activation map相关;比如,在CIFAR-10中,每张图的大小是:,那么卷积层的过滤器的。而activation map则是卷积层计算后的输出,若后续还有卷积层时,过滤器的设置则与其相关。
下面是卷积层作用的一个例子图:
过滤器会取输入与其大小一样的区域,进行卷积操作(实质是对应相乘再累加)。而过滤器会不断的平移,直至图片被扫描完成;过滤器每次平移的距离成为,有时候图片外围也会使用一些数值进行填充,称为,上述例子就是使用0(zero-padding)来对图片进行填充,而填充的大小为1(padding = 1)。通过卷积层后的activation map大小为:
在实现上,可以对图像按区域进行划分,然后将其和过滤器进行展开,进行内积即可完成卷积层的计算操作,伪代码如下:
for i in range(activation_map_heigh):
for j in range(activation_map_width):
activate_map[:, :, i, j] = np.dot(pad_x[:, :, H_index:H_index + HH, W_index:W_index + WW].reshape(N, HH * WW * C), \
span_filter) + b
W_index += stride
H_index += stride
W_index = 0
卷积层的前向传播主要是:
那么其反向传播可以简单的写成:
而实现的伪代码如下:
span_filter = w.reshape(F, HH * WW * C)
W_index = 0
H_index = 0
for i in range(a_H):
for j in range(a_W):
dw += np.dot(dout[:, :, i, j].T, \
pad_x[:, :, H_index:H_index + HH, W_index:W_index + WW].reshape(N, HH * WW * C))
temp = dpad_x[:, :, H_index:H_index + HH, W_index:W_index + WW].reshape(N, HH * WW * C)
temp += np.dot(dout[:, :, i, j], span_filter)
dpad_x[:, :, H_index:H_index + HH, W_index:W_index + WW] = temp.reshape(N, C, HH, WW)
db += np.sum(dout[:, :, i, j], axis=0)
W_index += stride
H_index += stride
W_index = 0
dw = dw.reshape(F, C, HH, WW)
dx = dpad_x[:, :, 1:H+1, 1:W+1]
个人觉得,在实现上要适当的应用reshape()函数,使得整个过程条理更为清晰。
在实际应用中,卷积层的高效实现是通过img2Col操作来完成。
池化层
池化层,也叫作subsample,其主要作用是对数据进行降维,降低数据的冗余;因为池化层可以缩小数据规模,这样就可减少模型的参数,避免模型的过拟合。
上图左侧展现了池化层的工作,相当于将模型进行压缩;右侧是max-pooling的工作原理,将图形分为各个区域,然后取其中的最大值作为代表,与刚刚卷积层类似,池化后输出的规模为:
小结
上述就是assignment2的卷积神经网络部分,主要是实现卷积神经网络部分中的卷积层与池化层,在作业中,关于两者的实现只是一种较为粗糙的实现,与实际的实现方式有一定差距,重在对其原理了解。
网友评论