pytorch学习笔记(15)

#稠密连接网络

如图所示,ResNet和DenseNet的关键区别在于,DenseNet输出是连接(用图中的[,]表示)而不是如ResNet的简单相加。


def conv_block(input_channels, num_channels):
    return nn.Sequential(
        nn.BatchNorm2d(input_channels), nn.ReLU(),  # 这是卷积块的第一部分,包括批量归一化层(nn.BatchNorm2d)和ReLU激活函数。
        nn.Conv2d(input_channels, num_channels, kernel_size=3, padding=1))  # 这是卷积块的第二部分,包括一个卷积层(nn.Conv2d)。卷积层用于对特征图进行卷积操作,其中参数包括输入通道数(input_channels)、输出通道数(num_channels)、卷积核大小(kernel_size,这里是3x3)、以及填充(padding,这里是1)。

一个稠密块由多个卷积块组成,每个卷积块使用相同数量的输出通道。 然而,在前向传播中,我们将每个卷积块的输入和输出在通道维上连结。

class DenseBlock(nn.Module):
    def __init__(self, num_convs, input_channels, num_channels):  # num_convs:指定了稠密块中包含多少个卷积块,input_channels:输入通道数,表示输入特征图的通道数。num_channels:输出通道数,表示每个卷积块的输出通道数。
        super(DenseBlock, self).__init__()
        layer = []  # 创建一个名为layer的空列表,用于存储稠密块中的每个卷积块。
        for i in range(num_convs):
            layer.append(conv_block(
                num_channels * i + input_channels, num_channels))  # 每个卷积块使用conv_block函数来创建,其中输入通道数是num_channels * i + input_channels,其中i表示当前卷积块的索引。初始时,i为0,因此输入通道数为input_channels。
        self.net = nn.Sequential(*layer)  # 在这里,我们使用nn.Sequential容器将所有卷积块组合在一起,形成一个包含多个卷积块的子网络。这个子网络被存储在self.net中。

    def forward(self, X):
        for blk in self.net:
            Y = blk(X) # 
            # 连接通道维度上每个块的输入和输出
            X = torch.cat((X, Y), dim=1)
        return X  # 在前向传播过程中,我们遍历稠密块中的每个卷积块(blk),将输入X通过卷积块 blk 进行前向传播,得到输出 Y。然后,我们将输入 X 和输出 Y 在通道维度上连接起来,形成新的输入 X,以便在下一个卷积块中使用。这个过程重复了num_convs次。

稠密块没有改变图像的空间尺寸(高度和宽度),但增加了输出通道的数量,使每个卷积块的输出被连接到了最终输出。这种设计使得每个卷积块都能访问之前卷积块的输出,从而加强了特征的重用和模型的深度。

由于每个稠密块都会带来通道数的增加,使用过多则会过于复杂化模型。 而过渡层可以用来控制模型复杂度。 它通过1×1卷积层来减小通道数,并使用步幅为2的平均汇聚层减半高和宽,从而进一步降低模型复杂度。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值