多通道的输入输出

深入理解多通道卷积操作原理,掌握多输入多输出卷积层的实现方法和1×1卷积的应用技巧

发布于 2025-08-08 更新于 2025-08-081,442 字 4 分钟
多通道的输入输出的文章封面
展开文章目录
  1. 1. 多通道输入
  2. 1.1 计算过程
  3. 1.2 代码实现
  4. 2. 多通道输出
  5. 2.1 网络演化规律
  6. 2.2 协同优化
  7. 2.3 代码示例
  8. 3. 1×1 卷积层
  9. 3.1 1×1 卷积的主要作用
  10. 3.2 代码实现
  11. 参考资料

在之前的案例中,我们只使用了单通道演示卷积操作,但在实际应用中,更多情况是以 RGB 的色彩模式处理图像数据。因此,我们需要考虑数据维度为 (cin,h,w)(c_{in}, h, w) 的多通道情况。

1. 多通道输入

1.1 计算过程

以双通道输入为例:

双通道输入的卷积操作示意图

1.2 代码实现

下面的实现复用了互相关运算中的 corr2d() 函数来演示多通道卷积:

import torch

def corr2d(X, K):
    """二维互相关运算"""
    h, w = K.shape
    Y = torch.zeros((X.shape[0] - h + 1, X.shape[1] - w + 1))
    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()
    return Y

# 双通道输入数据
i = torch.tensor([[[0., 1., 2.],
                   [3., 4., 5.],
                   [6., 7., 8.]],
                  [[1., 2., 3.],
                   [4., 5., 6.],
                   [7., 8., 9.]]])  # (2, 3, 3)

# 双通道卷积核
k = torch.tensor([[[0., 1.],
                   [2., 3.]],
                  [[1., 2.],
                   [3., 4.]]])  # (2, 2, 2)

# 多通道卷积计算
temp = torch.stack([corr2d(c_i, c_k) for c_i, c_k in zip(i, k)])  # 三维中间结果
result = temp.sum(dim=0)  # 二维特征图

print(f'输入形状: {i.shape}')
print(f'卷积核形状: {k.shape}')
print(f'中间结果形状: {temp.shape}')
print(f'最终输出形状: {result.shape}')
print(f'\n输出结果:\n{result}')
查看输出结果
输入形状: torch.Size([2, 3, 3])
卷积核形状: torch.Size([2, 2, 2])
中间结果形状: torch.Size([2, 2, 2])
最终输出形状: torch.Size([2, 2])

输出结果:
tensor([[ 56.,  72.],
        [104., 120.]])

2. 多通道输出

实际上,每个卷积层中的 coutc_{out} 个卷积核(形状为 (cin,kh,kw)(c_{in}, k_h, k_w))以堆栈 (stack) 的方式组织成一个大的卷积核(形状为 (cout,cin,kh,kw)(c_{out}, c_{in}, k_h, k_w))。

2.1 网络演化规律

2.2 协同优化

在网络训练的过程中,卷积层与卷积层之间、卷积层内部各个卷积核之间的参数更新是以整体网络性能的提升而协同优化的。

2.3 代码示例

import torch

# 双通道输入数据(与之前相同)
i = torch.tensor([[[0., 1., 2.],
                   [3., 4., 5.],
                   [6., 7., 8.]],
                  [[1., 2., 3.],
                   [4., 5., 6.],
                   [7., 8., 9.]]])  # (2, 3, 3)

# 定义三个不同的卷积核
k0 = torch.tensor([[[0., 1.],
                    [2., 3.]],
                   [[1., 2.],
                    [3., 4.]]])  # (2, 2, 2)
k1 = k0 + 1  # 每个元素加1
k2 = k0 + 2  # 每个元素加2

# 将三个卷积核堆叠为多输出通道
k_stack = torch.stack((k0, k1, k2))  # (3, 2, 2, 2)

# 计算多输出通道的卷积
def multi_in_out_corr2d(X, K):
    """多输入多输出卷积"""
    return torch.stack([torch.stack([corr2d(c_x, c_k) for c_x, c_k in zip(X, k)]).sum(dim=0) 
                       for k in K])

result = multi_in_out_corr2d(i, k_stack)

print(f'输出通道数: {result.shape[0]}')
print(f'输出形状: {result.shape}')
print(f'输出结果:\n{result}')
查看输出结果
输出通道数: 3
输出形状: torch.Size([3, 2, 2])
输出结果:
tensor([[[ 56.,  72.],
         [104., 120.]],

        [[ 76., 100.],
         [148., 172.]],

        [[ 96., 128.],
         [192., 224.]]])

3. 1×1 卷积层

以 3 通道输入、2 通道输出的 1×1 卷积层为例:

3通道输入2通道输出的1×1卷积层计算示意图

3.1 1×1 卷积的主要作用

1x1卷积作用

降维与升维

在不改变输出的空间维度前提下,调整卷积核数量改变输出通道数,实现降维与升维。可以在处理较大卷积核时作为”瓶颈层”,减小计算量或提高模型的表达能力。

线性组合通道信息

通过对每个像素位置的通道值加权求和,(与全连接层类似)实现通道间的线性组合。

增加非线性特征的表达能力

与非线性激活函数(如 ReLU)联用后,能增加网络的非线性特征表达能力。

3.2 代码实现

1×1 卷积层可以直接用 torch.nn.Conv2d 实现:

import torch
import torch.nn as nn

# 创建输入数据:(batch_size, channels, height, width)
input_data = torch.randn(1, 3, 32, 32)

# 定义1×1卷积层:3个输入通道 -> 64个输出通道
conv_1x1 = nn.Conv2d(in_channels=3, out_channels=64, kernel_size=1)

# 前向传播
output = conv_1x1(input_data)

print(f'输入形状: {input_data.shape}')
print(f'输入通道数: {input_data.shape[1]}')
print(f'输出形状: {output.shape}')
print(f'输出通道数: {output.shape[1]}')
查看输出结果
输入形状: torch.Size([1, 3, 32, 32])
输入通道数: 3
输出形状: torch.Size([1, 64, 32, 32])
输出通道数: 64

参考资料

如果这篇记录对你有帮助,可以留下一句回应。

前往留言

DISCUSSION

讨论与回应

欢迎补充细节、指出问题,或分享与这篇文章有关的经验。

昵称与邮箱为必填项,邮箱仅用于头像和回复通知,不会公开。网址可以留空。

正在准备留言区…

演示赞赏界面

谢谢你愿意支持长期写作。

第一阶段不会发起支付或收集任何信息。接入真实赞赏渠道后,这里会展示清楚的金额、渠道和完成状态。

输入关键词开始搜索 · 按 Esc 关闭
打开完整搜索页 →