多输入多输出通道
# 多输入通道互相关运算
import torch.nn
import torch
def corr2d(X,K):
Y = torch.zeros(X.shape[0]-K.shape[0]+1,X.shape[1]-K.shape[1]+1)
h,w = K.shape
for i in range(Y.shape[0]):
for j in range(Y.shape[1]):
Y[i,j] += (X[i:i+h,j:j+w]*K).sum()
# print((X[i:i+h,j:j+w]*K),torch.matmul(X[i:i+h,j:j+w],K))
return Y
验证互相关运算的输出
def corr2d_multi_in(X,K):
return sum(corr2d(x,k) for x,k in zip(X,K))
X = torch.tensor([[[0.0, 1.0, 2.0], [3.0, 4.0, 5.0], [6.0, 7.0, 8.0]],
[[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]]])
K = torch.tensor([[[0.0, 1.0], [2.0, 3.0]], [[1.0, 2.0], [3.0, 4.0]]])
corr2d_multi_in(X, K)
out
tensor([[ 56., 72.],
[104., 120.]])
计算多个通道的输出的互相关函数
def corr2d_multi_in_out(X, K):
return torch.stack( [corr2d_multi_in(X,k) for k in K] ,0)
1x1卷积的本质就是全连接层的计算
def corr2d_multi_in_out_1x1(X, K):
ci,h ,w = X.shape # (3, 3, 3)
co = K.shape[0] # (2, 3, 1, 1)
X = X.reshape((ci,h*w)) # [3, 9]
K = K.reshape((co,ci)) # [2, 3]
Y = torch.matmul(K,X)
return Y.reshape((co,h,w))
X = torch.normal(0, 1, (3, 3, 3))
K = torch.normal(0, 1, (2, 3, 1, 1))
Y1 = corr2d_multi_in_out_1x1(X, K)
Y2 = corr2d_multi_in_out(X, K)
assert float(torch.abs(Y1 - Y2).sum()) < 1e-6
总结来说,对于卷积操作而言,就是通过一个K矩阵和滑动步长Y去提取局部性的特征,对于卷积的细节而言,多输入通道对同一个K矩阵也就是对每一个通道执行一次互相关运算在对其矩阵进行按位sum。
对于1x1卷积而言,他就是将矩阵的元素进行拉伸,并将拉伸之后的矩阵与K矩阵相乘,最终变换为原来的维度大小,因为1x1矩阵并不会更改输入和输出的维度大小,他只体现在通道的变化。