阅读笔记9——DenseNet

DenseNet通过DenseBlock和BottleNeck模块实现特征的直接concat,缓解梯度消失问题,减少参数量并提高计算效率。每个DenseBlock内特征图尺寸不变,使用Transition层在不同DenseBlock间调整尺寸。BottleNeck包含1×1和3×3卷积,GrowthRate控制通道数增长。
摘要由CSDN通过智能技术生成

一、DenseNet

  DenseNet的网络结构如图1-1所示,其核心是Dense Block模块,Dense Block中的一个黑点就代表一个卷积模块(不是一个卷积层,而是DenseNet提出的一个BottleNeck模块,后文有讲解),每条黑线都代表着数据的流动。
在这里插入图片描述

图1-1 DenseNet网络结构
  • DenseNet的每一个Dense Block内保持特征图的尺寸一致,目的是为了直接进行Concat操作,因此,DenseNet被分成了多个Dense Block(每个Dense Block内不能改变特征图大小,但整个DenseNet为了提取特征,需要减小特征图尺寸,即每个Dense Block内特征图尺寸一致,不同Dense Block内特征图尺寸不一致),Dense Block的数量一般为4。
  • 两个相邻的Dense Block之间的部分被称为Transition层,具体包括BN、ReLU、1×1卷积、2×2平均池化。其中,1×1卷积的作用是降维,2×2平均池化的作用是降低特征图的尺寸。

二、Dense Block

  Dense Block的实现细节如图2-1所示,每一个Dense Block由若干个BottleNeck卷积模块组成,BottleNeck由BN、ReLU、1×1卷积、BN、ReLU、3×3卷积顺序组成。

在这里插入图片描述

图2-1 Dense Block结构
  • 每一个BottleNeck的输出通道数是相同的(每个BottleNeck模块最后3×3卷积的输出通道数相同),例如图2-1中的32,每经过一次Concat,特征图的通道数就增加32,因此这里的32也被称为GrowthRate。(假设对于一个Dense Block来说,输入通道数为 c i n c_{in} cin,输出通道数为 c o u t c_{out} cout,该Dense Block内有 n n n个BottleNeck,则 c o u t = c i n + n × G r o w t h R a t e c_{out}= c_{in} + n\times GrowthRate cout=cin+n×GrowthRate,图2-1可看作 192 = 64 + 4 × 32 192=64+4\times 32 192=64+4×32

  • 1×1卷积的作用是固定输出通道数,避免因网络结构过深而导致特征图的通道数急剧增加(每次Concat后,通道数都会增加GrowthRate,若不使用1×1卷积降维,后续3×3卷积的参数量会急剧增加)。1×1卷积的通道数通常是GrowthRate的4倍。

三、DenseNet优势

  • 密集连接的特殊网络,使得每一层都会接受其后所有层的梯度,而不是像普通卷积链式的反向传播,因此一定程度上解决了梯度消失的问题。
  • 通过Concat操作使得大量特征被复用,每个曾独有的特征图的通道是较少的,因此比ResNet的参数更少且计算更高效。
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
以下是使用Pytorch实现基于DenseNet的11 * 11一通道图像分类的示例代码: ```python import torch import torch.nn as nn import torch.optim as optim from torch.utils.data import DataLoader, Dataset from torch.optim.lr_scheduler import MultiStepLR # Define hyperparameters num_epochs = 50 batch_size = 128 learning_rate = 0.01 num_classes = 10 num_layers_per_block = 4 growth_rate = 32 compression_factor = 0.5 # Define custom dataset class CustomDataset(Dataset): def __init__(self, data, transform=None): self.data = data self.transform = transform def __len__(self): return len(self.data) def __getitem__(self, index): img = self.data[index][0] if self.transform: img = self.transform(img) return img, self.data[index][1] # Define DenseNet block class DenseNetBlock(nn.Module): def __init__(self, in_channels, growth_rate, num_layers): super(DenseNetBlock, self).__init__() self.layers = nn.ModuleList() for i in range(num_layers): self.layers.append(nn.Sequential( nn.BatchNorm2d(in_channels + i * growth_rate), nn.ReLU(inplace=True), nn.Conv2d(in_channels + i * growth_rate, growth_rate, kernel_size=1, bias=False), nn.BatchNorm2d(growth_rate), nn.ReLU(inplace=True), nn.Conv2d(growth_rate, growth_rate, kernel_size=3, padding=1, bias=False) )) def forward(self, x): for layer in self.layers: out = layer(x) x = torch.cat([x, out], 1) return x # Define DenseNet model class DenseNet(nn.Module): def __init__(self, num_classes, num_layers_per_block, growth_rate, compression_factor): super(DenseNet, self).__init__() self.features = nn.Sequential( nn.Conv2d(1, 2*growth_rate, kernel_size=3, padding=1, bias=False), nn.BatchNorm2d(2*growth_rate), nn.ReLU(inplace=True), nn.MaxPool2d(kernel_size=2, stride=2) ) num_channels = 2 * growth_rate self.num_blocks = len(num_layers_per_block) for i, num_layers in enumerate(num_layers_per_block): block = DenseNetBlock(num_channels, growth_rate, num_layers) self.features.add_module("denseblock%d" % (i + 1), block) num_channels += num_layers * growth_rate if i != self.num_blocks - 1: num_channels = int(num_channels * compression_factor) trans = nn.Sequential( nn.Conv2d(num_channels, num_channels, kernel_size=1, bias=False), nn.BatchNorm2d(num_channels), nn.ReLU(inplace=True), nn.AvgPool2d(kernel_size=2, stride=2) ) self.features.add_module("transition%d" % (i + 1), trans) self.classifier = nn.Linear(num_channels, num_classes) def forward(self, x): x = self.features(x) x = nn.functional.avg_pool2d(x, kernel_size=(x.size(2), x.size(3))) x = x.view(x.size(0), -1) x = self.classifier(x) return x # Initialize model and optimizer model = DenseNet(num_classes, num_layers_per_block, growth_rate, compression_factor) optimizer = optim.SGD(model.parameters(), lr=learning_rate, momentum=0.9, weight_decay=1e-4) scheduler = MultiStepLR(optimizer, milestones=[int(num_epochs*0.5), int(num_epochs*0.75)], gamma=0.1) # Load data train_data = torch.load('./train_data.pt') test_data = torch.load('./test_data.pt') train_dataset = CustomDataset(train_data) test_dataset = CustomDataset(test_data) train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True) test_loader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False) # Train model model.train() for epoch in range(num_epochs): for i, (images, labels) in enumerate(train_loader): # Forward pass outputs = model(images) loss = nn.functional.cross_entropy(outputs, labels) # Backward and optimize optimizer.zero_grad() loss.backward() optimizer.step() # Print training progress print('Epoch [{}/{}], Loss: {:.4f}'.format(epoch+1, num_epochs, loss.item())) # Update learning rate scheduler.step() # Test model model.eval() with torch.no_grad(): correct = 0 total = 0 for images, labels in test_loader: outputs = model(images) _, predicted = torch.max(outputs.data, 1) total += labels.size(0) correct += (predicted == labels).sum().item() # Print test accuracy print('Test Accuracy of the model on the 10000 test images: {} %'.format(100 * correct / total)) ``` 这个示例代码基于DenseNet的思想,使用了一个堆叠的DenseNet块来构建网络。每个块由多个DenseNet层组成,每个层都通过连接前面所有层的方式进行连接,以最大化信息流动。这个代码还包括数据加载、训练和测试等常用的功能。由于输入图像是灰度图像,所以在模型定义中将输入通道数设置为1。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

晓shuo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值