当前位置: 首页 > article >正文

深度学习:ResNet每一层的输出形状

在这里插入图片描述其中

/**在输出通道数为64、步幅为2的7 × 7卷积层后,接步幅为2的3 × 3的最大汇聚层,与GoogLeNet区别是每个卷积层后增加了批量规范层**/
b1 = nn.Sequential(nn.Conv2d(1, 64, kernel_size=7, stride=2, padding=3),
                   nn.BatchNorm2d(64), nn.ReLU(),
                   nn.MaxPool2d(kernel_size=3, stride=2, padding=1))

/**ResNet在后面接了由4个残差块组成的模块,每个模块使用若干个同样输出通道数的残差块,本例每个模块使用2个残差块
**/
b2 = nn.Sequential(*resnet_block(64, 64, 2, first_block=True))
b3 = nn.Sequential(*resnet_block(64, 128, 2))
b4 = nn.Sequential(*resnet_block(128, 256, 2))
b5 = nn.Sequential(*resnet_block(256, 512, 2))
net = nn.Sequential(b1, b2, b3, b4, b5,
                    nn.AdaptiveAvgPool2d((1, 1)),
                    nn.Flatten(), nn.Linear(512, 10))
##模块的构成
def resnet_block(input_channels, num_channels, num_residuals, first_block=False):
    blk = []
    for i in range(num_residuals):
        if i == 0 and not first_block:
            blk.append(Residual(input_channels, num_channels,
                                use_1x1conv=True, strides=2))
        else:
            blk.append(Residual(num_channels, num_channels))
            
    return blk

##残差块的构成(详细解释在下面)
class Residual(nn.Module):
    def __init__(self, input_channels, num_channels, use_1x1conv=False, strides=1):
        super().__init__()
        self.conv1 = nn.Conv2d(input_channels, num_channels, kernel_size=3, padding=1, stride=strides)
        self.conv2 = nn.Conv2d(num_channels, num_channels, kernel_size=3, padding=1)
        
        if use_1x1conv:
            self.conv3 = nn.Conv2d(input_channels, num_channels, kernel_size=1, stride=strides)
        else:
            self.conv3 = None
        self.bn1 = nn.BatchNorm2d(num_channels)
        self.bn2 = nn.BatchNorm2d(num_channels)
        
    def forward(self, X):
        Y = F.relu(self.bn1(self.conv1(X)))
        Y = self.bn2(self.conv2(Y))
        
        if self.conv3:
            X = self.conv3(X)
            
        Y += X
        return F.relu(Y)

残差块里首先有2个有相同输出通道数的3 × 3卷积层。每个卷积层后接一个批量规范化层和ReLU激活函数。然后我们通过跨层数据通路,跳过这2个卷积运算,将输入直接加在最后的ReLU激活函数前。这样的设计要求2个卷积层的输出与输入形状一样,从而使它们可以相加。如果想改变通道数,就需要引入一个额外的1 × 1卷积层来将输入变换成需要的形状后再做相加运算。

接下来通过一个实例来展示下ResNet的每一层的输出形状

X = torch.rand(size=(1, 1, 224, 224))
for layer in net:
    X = layer(X)
    print(layer.__class__.__name__, 'output shape:\t', X.shape)

输出结果为
Sequential output shape: torch.Size([1, 64, 56, 56])
Sequential output shape: torch.Size([1, 64, 56, 56])
Sequential output shape: torch.Size([1, 128, 28, 28])
Sequential output shape: torch.Size([1, 256, 14, 14])
Sequential output shape: torch.Size([1, 512, 7, 7])
AdaptiveAvgPool2d output shape: torch.Size([1, 512, 1, 1])
Flatten output shape: torch.Size([1, 512])
Linear output shape: torch.Size([1, 10])

解释每一层的输出形状

  1. b1
    输入形状:torch.Size([1, 1, 224, 224])

    输出形状:torch.Size([1, 64, 56, 56])

    nn.Conv2d(1, 64, kernel_size=7, stride=2, padding=3):将输入的 1 个通道扩展为 64 个通道,特征图的尺寸从 224x224 变为 112x112。

    卷积层的输出特征图的尺寸可以通过以下公式计算: Output Size=(Input Size−Kernel
    Size+2×Padding)/Stride+1 本例即Output Size=(224−7+2×3)/2​+1 = 112

    nn.BatchNorm2d(64):对 64 个通道进行批量归一化。
    nn.ReLU():应用 ReLU 激活函数。
    nn.MaxPool2d(kernel_size=3, stride=2, padding=1):最大池化层将特征图的尺寸从 112x112 变为 56x56。

    最大池化的输出特征图的尺寸可以通过以下公式计算: Output Size=(Input Size−Kernel
    Size+2×Padding)/2Stride+1 本例即Output Size=(112−3+2×1)/2​+1=56

  2. b2:

    输入形状:torch.Size([1, 64, 56, 56])

    输出形状:torch.Size([1, 64, 56, 56])

    解释:resnet_block(64, 64, 2, first_block=True):包含两个残差块,输入和输出通道数均为 64,特征图的尺寸保持不变(56x56)。

  3. b3:

    输入形状:torch.Size([1, 64, 56, 56])

    输出形状:torch.Size([1, 128, 28, 28])

    解释:resnet_block(64, 128, 2):包含两个残差块,输入通道数为 64,输出通道数为 128,特征图的尺寸减半(56x56 -> 28x28)。

    是通过在第一个残差块中使用步幅为 2 的卷积操作来实现的。特征图尺寸减半的原因是为了在增加网络深度的同时,减小特征图的尺寸,从而减少计算量和参数数量,同时增加感受野,提高网络的性能和效率。

  4. b4:

    输入形状:torch.Size([1, 128, 28, 28])

    输出形状:torch.Size([1, 256, 14, 14])

    解释:resnet_block(128, 256, 2):包含两个残差块,输入通道数为 128,输出通道数为 256,特征图的尺寸减半(28x28 -> 14x14)。

  5. b5:

    输入形状:torch.Size([1, 256, 14, 14])

    输出形状:torch.Size([1, 512, 7, 7])

    解释:resnet_block(256, 512, 2):包含两个残差块,输入通道数为 256,输出通道数为 512,特征图的尺寸减半(14x14 -> 7x7)。

  6. AdaptiveAvgPool2d:

    输入形状:torch.Size([1, 512, 7, 7])

    输出形状:torch.Size([1, 512, 1, 1])

    解释:自适应平均池化层将特征图的尺寸调整为 1x1,通道数保持不变。

  7. Flatten:

    输入形状:torch.Size([1, 512, 1, 1])

    输出形状:torch.Size([1, 512])

    解释:展平层将多维特征图展平成一维向量,总元素数为 512。

  8. Linear:

    输入形状:torch.Size([1, 512])

    输出形状:torch.Size([1, 10])

    解释:全连接层将输入的 512 个元素映射到 10 个元素,输出 10 个类别的概率分布。


http://www.kler.cn/a/403879.html

相关文章:

  • 为什么VScode不能连服务器,MobaXterm可以连
  • [Realtek sdk-3.4.14b] RTL8197FH-VG新增jffs2分区操作说明
  • 05_Spring JdbcTemplate
  • 案例精选 | 某知名教育集团基于安全运营平台的全域威胁溯源实践
  • Java Swing-1.基本概念及组件
  • 列出D3的所有交互方法,并给出示例
  • vue3项目执行npm install下载依赖报错问题排查方法
  • [WPF] RichTextBox如何显示省略号?
  • 学习ASP.NET Core的身份认证(基于Cookie的身份认证1)
  • Comfy UI 工作流(三)高清修复 - 低显存放大
  • 实验室管理效率提升:Spring Boot技术的力量
  • MySQL高可用方案之PXC(Percona XtraDB Cluster)
  • 13 go语言(golang) - 函数
  • Excel常用技巧分享
  • Android 网络请求(二)OKHttp网络通信
  • 公安、监管等政务部门实现数字化转型的解决方案
  • 【WPF】Prism学习(三)
  • Github 2024-11-17 php开源项目日报 Top10
  • ffplay音频SDL播放处理
  • MySQL之联合查询
  • Mysql的InnoDB存储引擎中的锁机制
  • 三十八、Python(pytest框架-上)
  • 商品管理系统引领时尚零售智能化升级 降价商品量锐减30%
  • Linux-第2集-打包压缩 zip、tar WindowsLinux互传
  • 速盾:海外服务器使用CDN加速有什么好处?
  • Python JSON 数据解析教程:从基础到高级