稠密连接网络(DenseNet)

文章目录

简介

DenseNet的核心思想是改进网络中特征的传递方式,通过在每个层之间建立直接的连接(即稠密连接),来提高信息流动和梯度传播的效率,从而解决深度神经网络中的梯度消失和梯度爆炸问题。

稠密连接:

在DenseNet中,每一层都与前面的所有层相连。具体来说,层的输入包括前面所有层的输出。这意味着网络中的每个层都接收到来自前面所有层的特征图(feature maps)。由于稠密连接,后面的层可以重用前面层学到的特征,这有助于减少参数数量,同时提高特征的利用效率。

import torch
import torch.nn as nn
from torch.nn import functional as F

def conv_block(input_channels, num_channels):
    '''
    这个函数创建了一个卷积块,
    包含批归一化层(BatchNorm2d)、
    ReLU激活函数和3x3卷积层。这个块用于每个稠密块(DenseBlock)中的卷积层。
    :param input_channels: 输入通道
    :param num_channels:  输出通道
    :return: 卷积块
    '''
    return nn.Sequential(
        nn.BatchNorm2d(input_channels), nn.ReLU(),
        nn.Conv2d(input_channels, num_channels, kernel_size=3, padding=1))

def transition_block(input_channels, num_channels):
    '''
    这个函数创建了一个转换块,包含批归一化层、ReLU激活函数和1x1卷积层,
    以及平均池化层。转换块用于在稠密块之间减少通道数,同时降低特征图的空间维度。
    :param input_channels: 输入通道
    :param num_channels: 输出通道
    :return:转换块
    '''
    return nn.Sequential(
        nn.BatchNorm2d(input_channels), nn.ReLU(),
        nn.Conv2d(input_channels, num_channels, kernel_size=1),
        nn.AvgPool2d(kernel_size=2, stride=2))


class DenseBlock(nn.Module):
    '''
    这个类定义了DenseNet中的稠密块。
    '''
    def __init__(self, num_convs, input_channels, num_channels):
        '''
        在构造函数中,循环创建指定数量的卷积块,并将它们添加到一个序列中。
        :param num_convs: 卷积块的数量
        :param input_channels: 当前的通道数
        :param num_channels: 每个卷积块增加通道数的倍数
        '''
        super(DenseBlock, self).__init__()
        layer = []
        for i in range(num_convs):
            layer.append(conv_block(
                num_channels * i + input_channels, num_channels))
        self.net = nn.Sequential(*layer)

    def forward(self, X):
        '''
        forward 方法定义了稠密块的前向传播过程,将每个卷积块的输出与输入在通道维度上连接起来。
        :param X:输入
        :return:
        '''
        for blk in self.net:
            Y = blk(X)
            # 连接通道维度上每个块的输入和输出
            X = torch.cat((X, Y), dim=1)
        return X

'''
这是一个序列,包含网络的第一个卷积块,包括一个7x7的卷积层、批归一化层、ReLU激活函数和最大池化层。
这个序列用于网络的初始特征提取。
'''
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))



'''
稠密块和转换层的构建
'''
num_channels, growth_rate = 64, 32 # num_channels为当前的通道数
num_convs_in_dense_blocks = [4, 4, 4, 4]
blks = []
'''
代码中使用了一个循环来构建一系列稠密块和转换层。
每个稠密块由DenseBlock类创建,转换层由transition_block函数创建。
'''
for i, num_convs in enumerate(num_convs_in_dense_blocks):
    # 建立num_convs个卷积网络,他的通道数数num_channels,增长的通道倍数growth_rate
    blks.append(DenseBlock(num_convs, num_channels, growth_rate))
    # 上一个稠密块的输出通道数
    num_channels += num_convs * growth_rate
    # 在稠密块之间添加一个转换层,使通道数量减半
    if i != len(num_convs_in_dense_blocks) - 1:
        blks.append(transition_block(num_channels, num_channels // 2))
        num_channels = num_channels // 2


net = nn.Sequential(
    b1, *blks,
    nn.BatchNorm2d(num_channels), nn.ReLU(),
    nn.AdaptiveAvgPool2d((1, 1)),
    nn.Flatten(),
    nn.Linear(num_channels, 10))
print(net)



def forward(self, X): 里面写了每一层都与前面的所有层相连。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值