【论文阅读及复现】(2017)Densely Connected Convolutional Networks + Pytorch代码实现

简介: - 最近的工作表明,如果卷积网络在靠近输入的层和靠近输出的层之间包含较短的连接,则它们可以更深、更准确和更有效地训练。- 在本文中,我们接受了这一观察并介绍了密集卷积网络(DenseNet),它以前馈方式将每一层连接到其他每一层。具有 L 层的传统卷积网络有 L 个连接——每层与其后续层之间有一个连接——我们的网络有 L*(L+1) /2 个直接连接。 F 或每一层,所有前面的层的特征图被用作输入,它自己的特征图被用作所有后续层的输入。 - DenseNets 有几个引人注目的优势:它们缓解了梯度消失问题,加强了特征传播,鼓励特征重用,并大大减少了参数的数量。- 我们在四个竞争激烈的对象

@[toc]


论文来源:(2017)Densely Connected Convolutional Networks
作者:Gao Huang 等人

一、摘要

  • 最近的工作表明,如果卷积网络在靠近输入的层和靠近输出的层之间包含较短的连接,则它们可以更深、更准确和更有效地训练。
  • 在本文中,我们接受了这一观察并介绍了密集卷积网络(DenseNet),它以前馈方式将每一层连接到其他每一层。具有 L 层的传统卷积网络有 L 个连接——每层与其后续层之间有一个连接——我们的网络有 L*(L+1) /2 个直接连接。 F 或每一层,所有前面的层的特征图被用作输入,它自己的特征图被用作所有后续层的输入。
  • DenseNets 有几个引人注目的优势:它们缓解了梯度消失问题,加强了特征传播,鼓励特征重用,并大大减少了参数的数量。
  • 我们在四个竞争激烈的对象识别基准任务(CIF AR-10、CIF AR-100、SVHN 和 ImageNet)上评估我们提出的架构。
  • DenseNets 在大多数情况下都比最先进的技术获得了显着改进,同时需要更少的计算来实现高性能。

二、Dense Net 网络结构

在这里插入图片描述
在这里插入图片描述

三、Dense Block

在Dense Block中,每一层都与后面的层有跳连接

为了更好的保存低层网络的特征,DenseNet 使用的是将不同层的输出拼接在一起,而在残差网络中使用的是单位加操作。以上便是DenseNet算法的动机
在这里插入图片描述
在Dsense Block中的每一层,都有1×1和3×3两个卷积核

论文中指出:”虽然每一层只产生 k 个输出特征图,但它通常有更多的输入。可以在每个 3×3 卷积之前引入一个 1×1 卷积作为瓶颈层,以减少输入特征图的数量,从而提高计算效率。我们发现这种设计对 DenseNet 特别有效,我们将我们的网络称为具有这样一个瓶颈层的网络,即 H' 的 BN-ReLU-Conv(1×1)-BN-ReLU-Conv(3×3) 版本“

四、PyTorch-GPU代码实现

MNIST手写数据集的图片大小为28×28,如果采用论文里的结构,在第四层pooling时会出现0×0尺寸的情况,为了避免这个情况,我在第四层前的1×1的conv层设置了padding=(1,1),故下面的代码结构不和论文里完全一致

import torch
import torch.nn as nn
from torchvision import transforms
from torchvision import datasets
from torch.utils.data import DataLoader
import torch.optim as optim
import torch.nn.functional as F


def conv_block(in_channels, out_channels):
    block = nn.Sequential(nn.BatchNorm2d(in_channels),
                        nn.ReLU(),
                        nn.Conv2d(in_channels, out_channels, kernel_size=(3, 3), padding=(1, 1)))
    return block


class DenseBlock(nn.Module):
    def __init__(self, in_channels, out_channels, cnt):
        super(DenseBlock, self).__init__()
        net = []
        for i in range(cnt):
            in_c = in_channels + i * out_channels
            net.append(conv_block(in_c, out_channels))
        self.net = nn.ModuleList(net)
        self.out_channels = in_channels + cnt * out_channels  # 计算输出通道数

    def forward(self, x):
        for blk in self.net:
            y = blk(x)
            x = torch.cat((x, y), dim=1)  # 在通道维上将输入和输出拼接
        return x


class DenselyNet(torch.nn.Module):
    def __init__(self):
        super(DenselyNet, self).__init__()
        self.conv7x7 = nn.Conv2d(1, 16, kernel_size=(7, 7), padding=(3, 3), stride=(2, 2))
        self.conv1x1_1 = nn.Conv2d(112, 16, kernel_size=(1, 1))
        self.conv1x1_2 = nn.Conv2d(208, 16, kernel_size=(1, 1))
        self.conv1x1_3 = nn.Conv2d(400, 16, kernel_size=(1, 1),padding=(1,1))
        self.max_pooling3x3 = nn.MaxPool2d(kernel_size=(3, 3), stride=(2, 2))
        self.avg_pooling2x2 = nn.AvgPool2d(kernel_size=(2, 2), stride=(2, 2))

        self.dense_block1 = DenseBlock(16, 16, 6)
        self.dense_block2 = DenseBlock(16, 16, 12)
        self.dense_block3 = DenseBlock(16, 16, 24)
        self.dense_block4 = DenseBlock(16, 16, 16)

        self.fc = nn.Linear(272, 10)

    def forward(self, x):
        in_size = x.size(0)

        x = torch.relu(self.conv7x7(x))
        x = torch.relu(self.max_pooling3x3(x))
        x = self.dense_block1(x)

        x = torch.relu(self.conv1x1_1(x))
        x = torch.relu(self.avg_pooling2x2(x))
        x = self.dense_block2(x)

        x = torch.relu(self.conv1x1_2(x))
        x = torch.relu(self.avg_pooling2x2(x))
        x = self.dense_block3(x)

        x = torch.relu(self.conv1x1_3(x))
        x = torch.relu(self.avg_pooling2x2(x))
        x = self.dense_block4(x)

        x = torch.relu(F.adaptive_avg_pool2d(x, output_size=(1, 1)))

        x = x.view(in_size, -1)
        x = self.fc(x)
        return x


# 单次训练函数
def train(epoch, criterion):
    running_loss = 0.0
    for batch_idx, data in enumerate(train_loader, 0):
        inputs, target = data
        # 将inputs, target转移到Gpu或者Cpu上
        inputs, target = inputs.to(device), target.to(device)
        optimizer.zero_grad()
        outputs = model(inputs)
        loss = criterion(outputs, target)
        loss.backward()
        optimizer.step()
        running_loss += loss.item()
        if batch_idx % 300 == 299:
            print('[%d, %5d] loss: %.3f' % (epoch + 1, batch_idx + 1, running_loss / 300))
            running_loss = 0.0


# 单次测试函数
def ttt():
    correct = 0.0
    total = 0.0
    with torch.no_grad():
        for data in test_loader:
            images, labels = data
            # 将images, labels转移到Gpu或者Cpu上
            images, labels = images.to(device), labels.to(device)
            outputs = model(images)
            _, predicted = torch.max(outputs.data, dim=1)
            total += labels.size(0)
            correct += (predicted == labels).sum().item()
    print('Accuracy on test set: %d %% [%d/%d]' % (100 * correct / total, correct, total))


if __name__ == '__main__':
    batch_size = 64
    transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081,))])
    train_dataset = datasets.MNIST(root='../dataset/', train=True, download=True, transform=transform)

    train_loader = DataLoader(train_dataset, shuffle=True, batch_size=batch_size)

    test_dataset = datasets.MNIST(root='../dataset/', train=False, download=True, transform=transform)
    test_loader = DataLoader(test_dataset, shuffle=False, batch_size=batch_size)

    device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

    # 声明模型
    model = DenselyNet()
    # 将模型转移道Gpu或者Cpu上
    model.to(device)
    # 定义损失函数
    criterion = torch.nn.CrossEntropyLoss()
    # 定义优化器
    optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.5)

    for epoch in range(10):
        train(epoch, criterion)
        ttt()

输出:

[1,   300] loss: 1.274
[1,   600] loss: 0.321
[1,   900] loss: 0.179
Accuracy on test set: 96 % [9699/10000]
[2,   300] loss: 0.114
[2,   600] loss: 0.115
[2,   900] loss: 0.099
Accuracy on test set: 98 % [9813/10000]
[3,   300] loss: 0.080
[3,   600] loss: 0.068
[3,   900] loss: 0.069
Accuracy on test set: 98 % [9864/10000]
[4,   300] loss: 0.053
[4,   600] loss: 0.056
[4,   900] loss: 0.056
Accuracy on test set: 98 % [9873/10000]
[5,   300] loss: 0.041
[5,   600] loss: 0.044
[5,   900] loss: 0.041
Accuracy on test set: 98 % [9882/10000]
[6,   300] loss: 0.033
[6,   600] loss: 0.035
[6,   900] loss: 0.034
Accuracy on test set: 98 % [9864/10000]
[7,   300] loss: 0.033
[7,   600] loss: 0.028
[7,   900] loss: 0.033
Accuracy on test set: 99 % [9903/10000]
[8,   300] loss: 0.024
[8,   600] loss: 0.027
[8,   900] loss: 0.031
Accuracy on test set: 98 % [9883/10000]
[9,   300] loss: 0.020
[9,   600] loss: 0.022
[9,   900] loss: 0.027
Accuracy on test set: 99 % [9901/10000]
[10,   300] loss: 0.019
[10,   600] loss: 0.022
[10,   900] loss: 0.021
Accuracy on test set: 98 % [9883/10000]
相关实践学习
基于阿里云DeepGPU实例,用AI画唯美国风少女
本实验基于阿里云DeepGPU实例,使用aiacctorch加速stable-diffusion-webui,用AI画唯美国风少女,可提升性能至高至原性能的2.6倍。
目录
相关文章
|
4小时前
|
机器学习/深度学习 算法 PyTorch
RPN(Region Proposal Networks)候选区域网络算法解析(附PyTorch代码)
RPN(Region Proposal Networks)候选区域网络算法解析(附PyTorch代码)
345 1
|
4小时前
|
自然语言处理 PyTorch 算法框架/工具
自然语言生成任务中的5种采样方法介绍和Pytorch代码实现
在自然语言生成任务(NLG)中,采样方法是指从生成模型中获取文本输出的一种技术。本文将介绍常用的5中方法并用Pytorch进行实现。
130 0
|
4小时前
|
机器学习/深度学习 关系型数据库 MySQL
大模型中常用的注意力机制GQA详解以及Pytorch代码实现
GQA是一种结合MQA和MHA优点的注意力机制,旨在保持MQA的速度并提供MHA的精度。它将查询头分成组,每组共享键和值。通过Pytorch和einops库,可以简洁实现这一概念。GQA在保持高效性的同时接近MHA的性能,是高负载系统优化的有力工具。相关论文和非官方Pytorch实现可进一步探究。
118 4
|
4小时前
|
机器学习/深度学习 算法 PyTorch
挑战Transformer的新架构Mamba解析以及Pytorch复现
今天我们来详细研究这篇论文“Mamba:具有选择性状态空间的线性时间序列建模”
866 1
|
4小时前
|
数据挖掘 PyTorch 算法框架/工具
人脸识别中的损失函数ArcFace及其实现过程代码(pytorch)--理解softmax损失函数及Arcface
人脸识别中的损失函数ArcFace及其实现过程代码(pytorch)--理解softmax损失函数及Arcface
178 0
|
4小时前
|
PyTorch 算法框架/工具
使用Pytorch Geometric 进行链接预测代码示例
该代码示例使用PyTorch和`torch_geometric`库实现了一个简单的图卷积网络(GCN)模型,处理Cora数据集。模型包含两层GCNConv,每层后跟ReLU激活和dropout。模型在训练集上进行200轮训练,使用Adam优化器和交叉熵损失函数。最后,计算并打印测试集的准确性。
21 6
|
4小时前
|
机器学习/深度学习 并行计算 PyTorch
【多GPU炼丹-绝对有用】PyTorch多GPU并行训练:深度解析与实战代码指南
本文介绍了PyTorch中利用多GPU进行深度学习的三种策略:数据并行、模型并行和两者结合。通过`DataParallel`实现数据拆分、模型不拆分,将数据批次在不同GPU上处理;数据不拆分、模型拆分则将模型组件分配到不同GPU,适用于复杂模型;数据和模型都拆分,适合大型模型,使用`DistributedDataParallel`结合`torch.distributed`进行分布式训练。代码示例展示了如何在实践中应用这些策略。
122 2
【多GPU炼丹-绝对有用】PyTorch多GPU并行训练:深度解析与实战代码指南
|
4小时前
|
机器学习/深度学习 PyTorch 算法框架/工具
卷积神经元网络中常用卷积核理解及基于Pytorch的实例应用(附完整代码)
卷积神经元网络中常用卷积核理解及基于Pytorch的实例应用(附完整代码)
25 0
|
4小时前
|
PyTorch 算法框架/工具 Python
基于Pytorch的YoLoV4模型代码及作品欣赏
基于Pytorch的YoLoV4模型代码及作品欣赏
30 0
|
4小时前
|
机器学习/深度学习 自然语言处理 PyTorch
使用Transformer 模型进行时间序列预测的Pytorch代码示例
时间序列预测是一个经久不衰的主题,受自然语言处理领域的成功启发,transformer模型也在时间序列预测有了很大的发展。本文可以作为学习使用Transformer 模型的时间序列预测的一个起点。
312 2