直接上代码
前置内容可以参考:conv1d简单实现
def myconv2d(infeat, convkernel, padding=0, stride=1):
b, c, h, w = len(infeat), len(infeat[0]), len(infeat[0][0]), len(infeat[0][0][0])
out_c, in_c, kh, kw = len(convkernel), len(convkernel[0]), len(convkernel[0][0]), len(convkernel[0][0][0])
# 不使用分组卷积,c = in_c
# 卷积核为正方形,kh = kw
res = [[[[0] * (w-kw+1) for _ in range(h-kh+1)] for _ in range(out_c)] for _ in range(b)]
# 最终输出形状:b*out_c*(h-kh+1)*(w-kw+1)
# print(len(res), len(res[0]), len(res[0][0]), len(res[0][0][0]))
for i in range(b):
# 关于batch,目前只能串行完成
for j in range(out_c):
# 计算每一组的结果
for m in range(c):
for n in range(h-kh+1):
for g in range(w-kw+1):
# 计算每一个位置的值
ans = 0
for k1 in range(kh):
for k2 in range(kw):
ans += infeat[i][m][n+k1][g+k2] * convkernel[j][m][k1][k2]
res[i][j][n][g] += ans
return res
# 我的卷积
infeat = [[[[1,0,2,2,2], [0,0,0,0,0], [2,0,2,2,2], [1,0,0,0,0], [1,0,0,2,1]],
[[1,0,1,0,1], [0,0,0,0,1], [0,0,2,0,0], [2,0,0,0,0], [0,0,1,0,0]],
[[0,2,2,0,0], [0,0,0,0,1], [1,1,2,0,2], [2,0,0,0,0], [0,1,1,0,1]]]]
convkernel = [[[[1,0,0], [-1,0,0], [0,-1,1]],
[[-1,-1,0], [-1,-1,1], [1,0,0]],
[[1,1,0], [0,-1,1], [1,1,1]]],
[[[1,-1,0], [-1,0,0], [0,1,-1]],
[[0,1,-1], [0,0,0], [0,1,1]],
[[0,-1,0], [1,1,-1], [-1,0,1]]]]
outfeat = myconv2d(infeat, convkernel)
print(outfeat)
# pytorch源码计算结果
from torch.nn.functional import conv2d
import torch
import numpy
infeat = torch.tensor(numpy.array(infeat))
convkernel = torch.tensor(numpy.array(convkernel))
outfeat_pytorch = conv2d(infeat, convkernel)
print(outfeat_pytorch)
输出结果如下,和官方的计算结果相同:
[[[[8, 6, 11], [5, -4, -2], [3, 5, 4]], [[-1, -2, -2], [-4, 3, -3], [2, -4, 1]]]]
tensor([[[[ 8, 6, 11],
[ 5, -4, -2],
[ 3, 5, 4]],
[[-1, -2, -2],
[-4, 3, -3],
[ 2, -4, 1]]]], dtype=torch.int32)
思考
pytorch中是直接按照滑动窗口点乘相加的,与传统的卷积定义(反褶,移位,相乘,相加)不同,没有反褶的操作