请大家指点一下卷积运算该怎么思考,一维卷积运算有点能明白,二维的不知道该怎么计算,网上也没找到很好的资料,谢谢大家
不知道你这个问题是否已经解决, 如果还没有解决的话:对于一维卷积,它是将一个长度为n的向量和一个长度为m的向量通过滑动点积的方式得到一个长度为n-m+1的向量,即:
length_n = n
length_m = m
res = []
for i in range(length_n - length_m + 1):
temp = 0
for j in range(length_m):
temp += vector1[i+j]*vector2[j]
res.append(temp)
而对于二维卷积,它是将一个大小为nxm的矩阵(或者称为特征图)和一个大小为pxq的矩阵(或者称为卷积核)通过滑动点积的方式得到一个大小为(n-p+1)x(m-q+1)的矩阵(或者称为输出特征图),即:
import numpy as np
def conv2d(image, kernel, stride=[1,1], padding='VALID'):
if padding == 'VALID':
padding_size = [0, 0]
elif padding == 'SAME':
padding_height = ((image.shape[1] - 1) * stride[0] + kernel.shape[0] - image.shape[0])
padding_width = ((image.shape[2] - 1) * stride[1] + kernel.shape[1] - image.shape[1])
padding_height = int(padding_height/2)
padding_width = int(padding_width/2)
padding_size = [padding_height, padding_width]
else:
raise ValueError('padding must be either VALID or SAME.')
padded_image = np.pad(image, ((0, 0), (padding_size[0], padding_size[0]), (padding_size[1], padding_size[1]), (0, 0)), mode='constant', constant_values=0)
output_height = int((padded_image.shape[1] - kernel.shape[0]) / stride[0] + 1)
output_width = int((padded_image.shape[2] - kernel.shape[1]) / stride[1] + 1)
output = np.zeros((padded_image.shape[0], output_height, output_width, kernel.shape[3]))
kernel = np.flipud(np.fliplr(kernel))
for y in range(output_height):
for x in range(output_width):
output[:, y, x, :] = (kernel * padded_image[:, y * stride[0]:y * stride[0] + kernel.shape[0], x * stride[1]:x * stride[1] + kernel.shape[1], :]).sum(axis=(1, 2))
return output
其中,padding参数指定是否需要对边缘进行填充,当为VALID时不进行填充,输出大小为(n-p+1)x(m-q+1);当为SAME时进行填充,填充后输出大小为nxm。stride参数指定卷积时的步长。padding_size表示 padding高度和宽度。
需要注意的是,卷积核也是一个张量,且有多个通道,一般用于提取图像不同方向或者频率的特征。因此,在二维卷积中,应该遍历卷积核的所有通道,并按通道进行滑动点积。可用以下代码实现:
output = np.zeros((padded_image.shape[0], output_height, output_width, kernel.shape[3]))
for i in range(kernel.shape[3]):
for y in range(output_height):
for x in range(output_width):
output[:, y, x, i] = (kernel[:, :, :, i] * padded_image[:, y * stride[0]:y * stride[0] + kernel.shape[0], x * stride[1]:x * stride[1] + kernel.shape[1], :]).sum(axis=(1, 2, 3))
这里,输出矩阵output的第四维是卷积核的通道数。针对每一个通道,提取图像不同方向或者频率的特征。