【论文阅读及复现】(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]
相关实践学习
在云上部署ChatGLM2-6B大模型(GPU版)
ChatGLM2-6B是由智谱AI及清华KEG实验室于2023年6月发布的中英双语对话开源大模型。通过本实验,可以学习如何配置AIGC开发环境,如何部署ChatGLM2-6B大模型。
目录
相关文章
|
9月前
|
机器学习/深度学习 JavaScript PyTorch
9个主流GAN损失函数的数学原理和Pytorch代码实现:从经典模型到现代变体
生成对抗网络(GAN)的训练效果高度依赖于损失函数的选择。本文介绍了经典GAN损失函数理论,并用PyTorch实现多种变体,包括原始GAN、LS-GAN、WGAN及WGAN-GP等。通过分析其原理与优劣,如LS-GAN提升训练稳定性、WGAN-GP改善图像质量,展示了不同场景下损失函数的设计思路。代码实现覆盖生成器与判别器的核心逻辑,为实际应用提供了重要参考。未来可探索组合优化与自适应设计以提升性能。
716 7
9个主流GAN损失函数的数学原理和Pytorch代码实现:从经典模型到现代变体
|
4月前
|
PyTorch 算法框架/工具 异构计算
PyTorch 2.0性能优化实战:4种常见代码错误严重拖慢模型
我们将深入探讨图中断(graph breaks)和多图问题对性能的负面影响,并分析PyTorch模型开发中应当避免的常见错误模式。
278 9
|
6月前
|
机器学习/深度学习 PyTorch 算法框架/工具
提升模型泛化能力:PyTorch的L1、L2、ElasticNet正则化技术深度解析与代码实现
本文将深入探讨L1、L2和ElasticNet正则化技术,重点关注其在PyTorch框架中的具体实现。关于这些技术的理论基础,建议读者参考相关理论文献以获得更深入的理解。
186 4
提升模型泛化能力:PyTorch的L1、L2、ElasticNet正则化技术深度解析与代码实现
|
5月前
|
机器学习/深度学习 数据可视化 PyTorch
Flow Matching生成模型:从理论基础到Pytorch代码实现
本文将系统阐述Flow Matching的完整实现过程,包括数学理论推导、模型架构设计、训练流程构建以及速度场学习等关键组件。通过本文的学习,读者将掌握Flow Matching的核心原理,获得一个完整的PyTorch实现,并对生成模型在噪声调度和分数函数之外的发展方向有更深入的理解。
2061 0
Flow Matching生成模型:从理论基础到Pytorch代码实现
|
8月前
|
机器学习/深度学习 数据可视化 机器人
比扩散策略更高效的生成模型:流匹配的理论基础与Pytorch代码实现
扩散模型和流匹配是生成高分辨率数据(如图像和机器人轨迹)的先进技术。扩散模型通过逐步去噪生成数据,其代表应用Stable Diffusion已扩展至机器人学领域形成“扩散策略”。流匹配作为更通用的方法,通过学习时间依赖的速度场将噪声转化为目标分布,适用于图像生成和机器人轨迹生成,且通常以较少资源实现更快生成。 本文深入解析流匹配在图像生成中的应用,核心思想是将图像视为随机变量的实现,并通过速度场将源分布转换为目标分布。文中提供了一维模型训练实例,展示了如何用神经网络学习速度场,以及使用最大均值差异(MMD)改进训练效果。与扩散模型相比,流匹配结构简单,资源需求低,适合多模态分布生成。
614 13
比扩散策略更高效的生成模型:流匹配的理论基础与Pytorch代码实现
|
8月前
|
机器学习/深度学习 编解码 PyTorch
从零实现基于扩散模型的文本到视频生成系统:技术详解与Pytorch代码实现
本文介绍了一种基于扩散模型的文本到视频生成系统,详细展示了模型架构、训练流程及生成效果。通过3D U-Net结构和多头注意力机制,模型能够根据文本提示生成高质量视频。
332 1
从零实现基于扩散模型的文本到视频生成系统:技术详解与Pytorch代码实现
|
10月前
|
机器学习/深度学习 存储 算法
近端策略优化(PPO)算法的理论基础与PyTorch代码详解
近端策略优化(PPO)是深度强化学习中高效的策略优化方法,广泛应用于大语言模型的RLHF训练。PPO通过引入策略更新约束机制,平衡了更新幅度,提升了训练稳定性。其核心思想是在优势演员-评论家方法的基础上,采用裁剪和非裁剪项组成的替代目标函数,限制策略比率在[1-ϵ, 1+ϵ]区间内,防止过大的策略更新。本文详细探讨了PPO的基本原理、损失函数设计及PyTorch实现流程,提供了完整的代码示例。
4334 10
近端策略优化(PPO)算法的理论基础与PyTorch代码详解
|
3月前
|
机器学习/深度学习 数据采集 人工智能
PyTorch学习实战:AI从数学基础到模型优化全流程精解
本文系统讲解人工智能、机器学习与深度学习的层级关系,涵盖PyTorch环境配置、张量操作、数据预处理、神经网络基础及模型训练全流程,结合数学原理与代码实践,深入浅出地介绍激活函数、反向传播等核心概念,助力快速入门深度学习。
211 1
|
7月前
|
机器学习/深度学习 PyTorch API
PyTorch量化感知训练技术:模型压缩与高精度边缘部署实践
本文深入探讨神经网络模型量化技术,重点讲解训练后量化(PTQ)与量化感知训练(QAT)两种主流方法。PTQ通过校准数据集确定量化参数,快速实现模型压缩,但精度损失较大;QAT在训练中引入伪量化操作,使模型适应低精度环境,显著提升量化后性能。文章结合PyTorch实现细节,介绍Eager模式、FX图模式及PyTorch 2导出量化等工具,并分享大语言模型Int4/Int8混合精度实践。最后总结量化最佳策略,包括逐通道量化、混合精度设置及目标硬件适配,助力高效部署深度学习模型。
1077 21
PyTorch量化感知训练技术:模型压缩与高精度边缘部署实践
|
3月前
|
机器学习/深度学习 存储 PyTorch
Neural ODE原理与PyTorch实现:深度学习模型的自适应深度调节
Neural ODE将神经网络与微分方程结合,用连续思维建模数据演化,突破传统离散层的限制,实现自适应深度与高效连续学习。
172 3
Neural ODE原理与PyTorch实现:深度学习模型的自适应深度调节

热门文章

最新文章

推荐镜像

更多