卷积操作转换为矩阵乘法

卷积操作转换为矩阵乘法

flyfish

示例代码

import torch
import torch.nn as nn
import numpy as np

# 定义输入图像
input_image = torch.tensor([
    [1, 2, 3, 0, 1],
    [0, 1, 2, 3, 4],
    [2, 3, 0, 1, 2],
    [1, 2, 3, 4, 0],
    [0, 1, 2, 3, 4]
], dtype=torch.float32).unsqueeze(0).unsqueeze(0)  # 添加批次和通道维度

# 定义卷积核
conv_kernel = torch.tensor([
    [1, 0, -1],
    [1, 0, -1],
    [1, 0, -1]
], dtype=torch.float32).unsqueeze(0).unsqueeze(0)  # 添加输入和输出通道维度

# 创建卷积层
conv_layer = nn.Conv2d(in_channels=1, out_channels=1, kernel_size=3, stride=1, padding=0, bias=False)

# 将卷积核的权重设置为自定义值
with torch.no_grad():
    conv_layer.weight = nn.Parameter(conv_kernel)

# 进行卷积操作
output_tensor = conv_layer(input_image)

# 打印输出结果
print("卷积操作输出结果:")
print(output_tensor.squeeze().detach().numpy())

# 使用 im2col 展开输入图像
def im2col(input_data, kernel_size, stride=1, padding=0):
    # 添加填充
    input_data = np.pad(input_data, ((padding, padding), (padding, padding)), 'constant')
    H, W = input_data.shape
    out_h = (H - kernel_size) // stride + 1
    out_w = (W - kernel_size) // stride + 1
    
    col = np.zeros((out_h * out_w, kernel_size * kernel_size))
    out = 0
    for y in range(0, H - kernel_size + 1, stride):
        for x in range(0, W - kernel_size + 1, stride):
            patch = input_data[y:y + kernel_size, x:x + kernel_size].flatten()
            col[out, :] = patch
            out += 1
    return col

# 转换输入图像为 numpy 数组
input_image_np = input_image.squeeze().numpy()

# 展开输入图像
input_col = im2col(input_image_np, 3)

# 展开卷积核
kernel_col = conv_kernel.squeeze().flatten().numpy()

# 进行矩阵乘法
output_col = np.dot(input_col, kernel_col)

# 变形输出以匹配卷积结果形状
output_matrix = output_col.reshape(3, 3)

print("矩阵操作输出结果:")
print(output_matrix)
卷积操作输出结果:
[[-2.  2. -2.]
 [-2. -2. -1.]
 [-2. -2. -1.]]
矩阵操作输出结果:
[[-2.  2. -2.]
 [-2. -2. -1.]
 [-2. -2. -1.]]

卷积操作可以转换为矩阵乘法,这是通过一种称为“im2col”的方法实现的。im2col方法将卷积操作展开成矩阵乘法。接下来,我们将手动计算的卷积操作转换成矩阵乘法,并使用PyTorch代码进行验证。

手动卷积计算转换成矩阵操作

首先,我们将输入图像和卷积核转换成适合矩阵乘法的形式。

输入图像和卷积核

输入图像 I I I:
[ 1 2 3 0 1 0 1 2 3 4 2 3 0 1 2 1 2 3 4 0 0 1 2 3 4 ] \begin{bmatrix} 1 & 2 & 3 & 0 & 1 \\ 0 & 1 & 2 & 3 & 4 \\ 2 & 3 & 0 & 1 & 2 \\ 1 & 2 & 3 & 4 & 0 \\ 0 & 1 & 2 & 3 & 4 \\ \end{bmatrix} 1021021321320320314314204
卷积核 K K K:
[ 1 0 − 1 1 0 − 1 1 0 − 1 ] \begin{bmatrix} 1 & 0 & -1 \\ 1 & 0 & -1 \\ 1 & 0 & -1 \\ \end{bmatrix} 111000111

使用 im2col 展开输入图像

为了方便进行矩阵乘法操作,我们将输入图像展开为一个矩阵,其中每一行表示卷积核在输入图像上每个可能位置的局部感受野。

展开后的矩阵 I c o l I_{col} Icol
[ 1 2 3 0 1 2 3 0 1 0 1 2 3 4 1 2 3 4 2 3 0 1 2 3 0 1 2 1 2 3 0 1 2 3 4 0 0 1 2 3 4 1 2 3 4 2 3 0 1 2 3 0 1 2 1 2 3 0 1 2 3 4 0 0 1 2 3 4 1 2 3 4 ] \begin{bmatrix} 1 & 2 & 3 & 0 & 1 & 2 & 3 & 0 & 1 \\ 0 & 1 & 2 & 3 & 4 & 1 & 2 & 3 & 4 \\ 2 & 3 & 0 & 1 & 2 & 3 & 0 & 1 & 2 \\ 1 & 2 & 3 & 0 & 1 & 2 & 3 & 4 & 0 \\ 0 & 1 & 2 & 3 & 4 & 1 & 2 & 3 & 4 \\ 2 & 3 & 0 & 1 & 2 & 3 & 0 & 1 & 2 \\ 1 & 2 & 3 & 0 & 1 & 2 & 3 & 4 & 0 \\ 0 & 1 & 2 & 3 & 4 & 1 & 2 & 3 & 4 \\ \end{bmatrix} 102102102132132132032032031031031421421421321321320320320314314314204204
卷积核展开为行向量 K r o w K_{row} Krow
[ 1 0 − 1 1 0 − 1 1 0 − 1 ] \begin{bmatrix} 1 & 0 & -1 & 1 & 0 & -1 & 1 & 0 & -1 \end{bmatrix} [101101101]

进行矩阵乘法

我们将 I c o l I_{col} Icol K r o w K_{row} Krow 进行矩阵乘法,得到卷积结果:

O = I c o l ⋅ K r o w T O = I_{col} \cdot K_{row}^T O=IcolKrowT

im2col 是一种将图像块展平为列的技术,用于将卷积操作转换为矩阵乘法。这个过程特别常用于实现卷积神经网络中的高效卷积操作。im2col 的核心思想是将输入图像的每个局部感受野(与卷积核相同大小的子矩阵)展开为一个列向量,然后将这些列向量拼接成一个大矩阵。通过这种方式,卷积操作可以简化为矩阵乘法。

im2col 说明

上面使用im2col这里做一个说明

假设我们有一个输入图像 I I I 和一个卷积核 K K K。我们希望使用卷积核在输入图像上进行卷积操作。卷积核在图像上滑动,每次计算一个局部区域(感受野)与卷积核的点积,生成一个输出值。

为了实现这一点,im2col 将输入图像中的每个局部感受野展平成一个列向量,然后将所有这些列向量堆叠在一起,形成一个矩阵。这样,卷积操作就变成了矩阵乘法。

im2col 实例

假设输入图像 I I I 4 × 4 4 \times 4 4×4 矩阵,卷积核 K K K 2 × 2 2 \times 2 2×2 矩阵,步长为 1,填充为 0。

输入图像 I I I
[ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ] \begin{bmatrix} 1 & 2 & 3 & 4 \\ 5 & 6 & 7 & 8 \\ 9 & 10 & 11 & 12 \\ 13 & 14 & 15 & 16 \\ \end{bmatrix} 15913261014371115481216
卷积核 K K K
[ 1 0 0 − 1 ] \begin{bmatrix} 1 & 0 \\ 0 & -1 \\ \end{bmatrix} [1001]

使用 im2col 展开输入图像

我们将每个 2 × 2 2 \times 2 2×2 的局部感受野展平成一个列向量,并将这些列向量堆叠成一个矩阵。展开后的矩阵 I c o l I_{col} Icol
[ 1 2 5 6 2 3 6 7 3 4 7 8 5 6 9 10 6 7 10 11 7 8 11 12 9 10 13 14 10 11 14 15 11 12 15 16 ] \begin{bmatrix} 1 & 2 & 5 & 6 \\ 2 & 3 & 6 & 7 \\ 3 & 4 & 7 & 8 \\ 5 & 6 & 9 & 10 \\ 6 & 7 & 10 & 11 \\ 7 & 8 & 11 & 12 \\ 9 & 10 & 13 & 14 \\ 10 & 11 & 14 & 15 \\ 11 & 12 & 15 & 16 \\ \end{bmatrix} 1235679101123467810111256791011131415678101112141516
卷积核 K K K 展开为行向量 K r o w K_{row} Krow
[ 1 0 0 − 1 ] \begin{bmatrix} 1 & 0 & 0 & -1 \end{bmatrix} [1001]

进行矩阵乘法

O = I c o l ⋅ K r o w T O = I_{col} \cdot K_{row}^T O=IcolKrowT
结果 O O O 将是一个列向量:
O = [ 1 ⋅ 1 + 2 ⋅ 0 + 5 ⋅ 0 + 6 ⋅ ( − 1 ) 2 ⋅ 1 + 3 ⋅ 0 + 6 ⋅ 0 + 7 ⋅ ( − 1 ) 3 ⋅ 1 + 4 ⋅ 0 + 7 ⋅ 0 + 8 ⋅ ( − 1 ) 5 ⋅ 1 + 6 ⋅ 0 + 9 ⋅ 0 + 10 ⋅ ( − 1 ) 6 ⋅ 1 + 7 ⋅ 0 + 10 ⋅ 0 + 11 ⋅ ( − 1 ) 7 ⋅ 1 + 8 ⋅ 0 + 11 ⋅ 0 + 12 ⋅ ( − 1 ) 9 ⋅ 1 + 10 ⋅ 0 + 13 ⋅ 0 + 14 ⋅ ( − 1 ) 10 ⋅ 1 + 11 ⋅ 0 + 14 ⋅ 0 + 15 ⋅ ( − 1 ) 11 ⋅ 1 + 12 ⋅ 0 + 15 ⋅ 0 + 16 ⋅ ( − 1 ) ] = [ 1 − 6 2 − 7 3 − 8 5 − 10 6 − 11 7 − 12 9 − 14 10 − 15 11 − 16 ] = [ − 5 − 5 − 5 − 5 − 5 − 5 − 5 − 5 − 5 ] O = \begin{bmatrix} 1 \cdot 1 + 2 \cdot 0 + 5 \cdot 0 + 6 \cdot (-1) \\ 2 \cdot 1 + 3 \cdot 0 + 6 \cdot 0 + 7 \cdot (-1) \\ 3 \cdot 1 + 4 \cdot 0 + 7 \cdot 0 + 8 \cdot (-1) \\ 5 \cdot 1 + 6 \cdot 0 + 9 \cdot 0 + 10 \cdot (-1) \\ 6 \cdot 1 + 7 \cdot 0 + 10 \cdot 0 + 11 \cdot (-1) \\ 7 \cdot 1 + 8 \cdot 0 + 11 \cdot 0 + 12 \cdot (-1) \\ 9 \cdot 1 + 10 \cdot 0 + 13 \cdot 0 + 14 \cdot (-1) \\ 10 \cdot 1 + 11 \cdot 0 + 14 \cdot 0 + 15 \cdot (-1) \\ 11 \cdot 1 + 12 \cdot 0 + 15 \cdot 0 + 16 \cdot (-1) \\ \end{bmatrix} =\begin{bmatrix} 1 - 6 \\ 2 - 7 \\ 3 - 8 \\ 5 - 10 \\ 6 - 11 \\ 7 - 12 \\ 9 - 14 \\ 10 - 15 \\ 11 - 16 \\ \end{bmatrix} =\begin{bmatrix} -5 \\ -5 \\ -5 \\ -5 \\ -5 \\ -5 \\ -5 \\ -5 \\ -5 \\ \end{bmatrix} O= 11+20+50+6(1)21+30+60+7(1)31+40+70+8(1)51+60+90+10(1)61+70+100+11(1)71+80+110+12(1)91+100+130+14(1)101+110+140+15(1)111+120+150+16(1) = 16273851061171291410151116 = 555555555

  • 15
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

西笑生

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值