第J3周:DenseNet121算法实现01(Pytorch版)

发布于:2025-03-22 ⋅ 阅读:(18) ⋅ 点赞:(0)

目标

具体实现

(一)环境

语言环境:Python 3.10
编 译 器: PyCharm
框 架: Pytorch

(二)具体步骤
1. DenseNet121.py
import torch  
import torch.nn as nn  
import torch.nn.functional as F  
import math  
  
  
# 实现DenseLayer(密集连接层)  
class DenseLayer(nn.Module):  
    def __init__(self, num_input_features, growth_rate, bn_size, drop_rate):  
        super(DenseLayer, self).__init__()  
        # BN -> ReLU -> Conv(1x1) -> BN -> ReLU -> Conv(3x3)  
        self.norm1 = nn.BatchNorm2d(num_input_features)  # 第一个批归一化层  
        self.relu1 = nn.ReLU(inplace=True)  # 第一个ReLU激活函数  
        self.conv1 = nn.Conv2d(num_input_features, bn_size * growth_rate,  
                               kernel_size=1, stride=1, bias=False)  # 1x1卷积层  
  
        self.norm2 = nn.BatchNorm2d(bn_size * growth_rate)  # 第二个批归一化层  
        self.relu2 = nn.ReLU(inplace=True)  # 第二个ReLU激活函数  
        self.conv2 = nn.Conv2d(bn_size * growth_rate, growth_rate,  
                               kernel_size=3, stride=1, padding=1, bias=False)  # 3x3卷积层  
  
        self.drop_rate = drop_rate  # Dropout率  
  
    def forward(self, x):  
        # 保存输入特征,用于后续的密集连接  
        new_features = self.norm1(x)  
        new_features = self.relu1(new_features)  
        new_features = self.conv1(new_features)  
  
        new_features = self.norm2(new_features)  
        new_features = self.relu2(new_features)  
        new_features = self.conv2(new_features)  
  
        # 如果设置了dropout,则应用dropout  
        if self.drop_rate > 0:  
            new_features = F.dropout(new_features, p=self.drop_rate, training=self.training)  
  
        # 将新特征与输入特征进行拼接,实现密集连接  
        return torch.cat([x, new_features], 1)  
  
  
# 实现DenseBlock(密集块)  
class DenseBlock(nn.Module):  
    def __init__(self, num_layers, num_input_features, bn_size, growth_rate, drop_rate):  
        super(DenseBlock, self).__init__()  
        # 创建指定数量的DenseLayer,每一层的输入特征数量都会增加  
        self.layers = nn.ModuleList()  
        for i in range(num_layers):  
            layer = DenseLayer(  
                num_input_features + i * growth_rate,  
                growth_rate=growth_rate,  
                bn_size=bn_size,  
                drop_rate=drop_rate  
            )  
            self.layers.append(layer)  
  
    def forward(self, x):  
        # 依次通过所有的DenseLayer  
        features = x  
        for layer in self.layers:  
            features = layer(features)  
        return features  
  
  
# 实现TransitionLayer(过渡层)  
class TransitionLayer(nn.Module):  
    def __init__(self, num_input_features, num_output_features):  
        super(TransitionLayer, self).__init__()  
        # BN -> Conv(1x1) -> AvgPool(2x2)  
        self.norm = nn.BatchNorm2d(num_input_features)  # 批归一化层  
        self.relu = nn.ReLU(inplace=True)  # ReLU激活函数  
        self.conv = nn.Conv2d(num_input_features, num_output_features,  
                              kernel_size=1, stride=1, bias=False)  # 1x1卷积层  
        self.pool = nn.AvgPool2d(kernel_size=2, stride=2)  # 平均池化层  
  
    def forward(self, x):  
        x = self.norm(x)  
        x = self.relu(x)  
        x = self.conv(x)  
        x = self.pool(x)  
        return x  
  
  
# 实现完整的DenseNet121模型  
class DenseNet121(nn.Module):  
    def __init__(self, growth_rate=32, block_config=(6, 12, 24, 16),  
                 num_init_features=64, bn_size=4, drop_rate=0, num_classes=1000):  
        super(DenseNet121, self).__init__()  
  
        # 首先是一个7x7的卷积层,步长为2  
        self.features = nn.Sequential()  
        self.features.add_module('conv0',  
                                 nn.Conv2d(3, num_init_features, kernel_size=7, stride=2, padding=3, bias=False))  # 初始卷积层  
        self.features.add_module('norm0', nn.BatchNorm2d(num_init_features))  # 批归一化层  
        self.features.add_module('relu0', nn.ReLU(inplace=True))  # ReLU激活函数  
        self.features.add_module('pool0', nn.MaxPool2d(kernel_size=3, stride=2, padding=1))  # 最大池化层  
  
        # 依次添加DenseBlock和TransitionLayer  
        num_features = num_init_features  
        for i, num_layers in enumerate(block_config):  
            # 添加DenseBlock  
            block = DenseBlock(  
                num_layers=num_layers,  
                num_input_features=num_features,  
                bn_size=bn_size,  
                growth_rate=growth_rate,  
                drop_rate=drop_rate  
            )  
            self.features.add_module(f'denseblock{i + 1}', block)  
            num_features = num_features + num_layers * growth_rate  
  
            # 如果不是最后一个block,则添加TransitionLayer  
            if i != len(block_config) - 1:  
                # 过渡层将特征图数量减半  
                trans = TransitionLayer(  
                    num_input_features=num_features,  
                    num_output_features=num_features // 2  
                )  
                self.features.add_module(f'transition{i + 1}', trans)  
                num_features = num_features // 2  
  
        # 最后添加一个BatchNorm  
        self.features.add_module('norm5', nn.BatchNorm2d(num_features))  # 最终的批归一化层  
  
        # 全局平均池化和分类器  
        self.classifier = nn.Linear(num_features, num_classes)  # 全连接分类器  
  
        # 初始化权重  
        for m in self.modules():  
            if isinstance(m, nn.Conv2d):  
                nn.init.kaiming_normal_(m.weight)  # 使用Kaiming初始化卷积层权重  
            elif isinstance(m, nn.BatchNorm2d):  
                nn.init.constant_(m.weight, 1)  # 初始化批归一化层的权重为1  
                nn.init.constant_(m.bias, 0)  # 初始化批归一化层的偏置为0  
            elif isinstance(m, nn.Linear):  
                nn.init.constant_(m.bias, 0)  # 初始化全连接层的偏置为0  
  
    def forward(self, x):  
        features = self.features(x)  # 提取特征  
        out = F.relu(features, inplace=True)  # 应用ReLU激活函数  
        out = F.adaptive_avg_pool2d(out, (1, 1))  # 全局平均池化  
        out = torch.flatten(out, 1)  # 展平特征  
        out = self.classifier(out)  # 分类  
        return out  
  
  
# 创建DenseNet121模型实例  
def create_densenet121(num_classes=1000, pretrained=False):  
    model = DenseNet121(num_classes=num_classes)  
    return model  
  
  
# 使用示例  
if __name__ == "__main__":  
    # 创建模型  
    model = create_densenet121()  
    print(model)  
  
    # 创建随机输入张量 (batch_size, channels, height, width)    x = torch.randn(1, 3, 224, 224)  
  
    # 前向传播  
    output = model(x)  
    print(f"Input shape: {x.shape}")  
    print(f"Output shape: {output.shape}")

image.png