《动手学深度学习 Pytorch版》 7.7 稠密连接网络

news2024/11/18 21:51:55

7.7.1 从 ResNet 到 DenseNet

DenseNet 可以视为 ResNet 的逻辑扩展。

ResNet 将函数展开为 f ( x ) = x + g ( x ) f(\boldsymbol{x})=x+g(\boldsymbol{x}) f(x)=x+g(x),即一个简单的线性项和一个复杂的非线性项。

若将 f f f 拓展成超过两部分,则 DenseNet 便是其中一种方案。这即是 DenseNet 和 ResNet 的主要区别。

在这里插入图片描述

DenseNet 这个名字由变量之间的“稠密连接”而得来。主要由两部分构成:

  • 稠密块:定义如何连接输入和输出。

  • 过渡层:控制通道数量,使其不会太复杂。

何为稠密连接?即最后一层与之前的所有层紧密相连,DenseNet 输出是连接执行从 x \boldsymbol{x} x 到其展开式的映射:

x → [ x , f 1 ( x ) , f 2 ( [ x , f 1 ( x ) ] ) , f 3 ( [ x , f 1 ( x ) , f 2 ( [ x , f 1 ( x ) ] ) ] , …   ) ] \boldsymbol{x}\to \left[\boldsymbol{x},f_1(\boldsymbol{x}),f_2([\boldsymbol{x},f_1(\boldsymbol{x})]),f_3([\boldsymbol{x},f_1(x),f_2([\boldsymbol{x},f_1(x)])],\dots)\right] x[x,f1(x),f2([x,f1(x)]),f3([x,f1(x),f2([x,f1(x)])],)]

在这里插入图片描述

7.7.2 稠密块体

import torch
from torch import nn
from d2l import torch as d2l
def conv_block(input_channels, num_channels):
    return nn.Sequential(
        nn.BatchNorm2d(input_channels), nn.ReLU(),
        nn.Conv2d(input_channels, num_channels, kernel_size=3, padding=1))
class DenseBlock(nn.Module):
    def __init__(self, num_convs, input_channels, 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):
        for blk in self.net:
            Y = blk(X)
            X = torch.cat((X, Y), dim=1)  # 连接通道维度上每个块的输入和输出
        return X
blk = DenseBlock(2, 3, 10)  # 会得到 3+2*10=23 通道数的输出
X = torch.randn(4, 3, 8, 8)
Y = blk(X)
Y.shape
torch.Size([4, 23, 8, 8])

7.7.3 过渡层

由于每个稠密块都会带来通道数的增加,由此会导致模型复杂化。可以使用过渡层来控制模型复杂度,它通过 1 × 1 1\times 1 1×1 的卷积层来减小通道数,并使用步幅为2的平均汇聚层加班班高度和宽度,从而降低模型复杂度。

def transition_block(input_channels, num_channels):
    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))
blk = transition_block(23, 10)  # 通道数缩减为10
blk(Y).shape
torch.Size([4, 10, 4, 4])

7.7.4 DenseNet 模型

b1 = nn.Sequential(  # b1 层和前面一样的
    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_convs_in_dense_blocks = [4, 4, 4, 4]  # 使用4个稠密块,每个稠密块内使用4个卷积层
num_channels, growth_rate = 64, 32  # 增长率为32则每个稠密块增加4*32=128个通道
blks = []
for i, num_convs in enumerate(num_convs_in_dense_blocks):
    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))

7.7.5 训练模型

lr, num_epochs, batch_size = 0.1, 10, 256
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size, resize=96)
d2l.train_ch6(net, train_iter, test_iter, num_epochs, lr, d2l.try_gpu())  # 大约需要十五分钟,慎跑
loss 0.140, train acc 0.948, test acc 0.914
865.0 examples/sec on cuda:0

在这里插入图片描述

练习

(1)为什么我们在过渡层使用平均汇聚层而不是最大汇聚层?

我觉得平均汇聚就像考虑所有特征,而最大汇聚就像只考虑最明显的特征。

过渡层如果只考虑最明显特征可能就会有特征损失掉。

不过实测差别似乎不大 。


(2)DenseNet 的优点之一是其模型参数比 ResNet 小。为什么呢?

X = torch.rand(size=(1, 1, 224, 224), device=d2l.try_gpu())
for layer in net:
    X = layer(X)
    print(layer.__class__.__name__,'output shape:\t', X.shape)
Sequential output shape:	 torch.Size([1, 64, 56, 56])
DenseBlock output shape:	 torch.Size([1, 192, 56, 56])
Sequential output shape:	 torch.Size([1, 96, 28, 28])
DenseBlock output shape:	 torch.Size([1, 224, 28, 28])
Sequential output shape:	 torch.Size([1, 112, 14, 14])
DenseBlock output shape:	 torch.Size([1, 240, 14, 14])
Sequential output shape:	 torch.Size([1, 120, 7, 7])
DenseBlock output shape:	 torch.Size([1, 248, 7, 7])
BatchNorm2d output shape:	 torch.Size([1, 248, 7, 7])
ReLU output shape:	 torch.Size([1, 248, 7, 7])
AdaptiveAvgPool2d output shape:	 torch.Size([1, 248, 1, 1])
Flatten output shape:	 torch.Size([1, 248])
Linear output shape:	 torch.Size([1, 10])

可以看到过渡层的存在很好的抑制了输出通道数,同样的卷积层数,FenseNet 的层数始终没有超过256。


(3)DenseNet 一个诟病的问题是内存或显存消耗过多。

a. 真的是这样吗?可以把输入形状换成 $224\times 224$,来看看实际的显存消耗。

b. 还有其他方法来减少显存消耗吗?需要改变框架么?
net2 = nn.Sequential(
    b1, *blks,
    nn.BatchNorm2d(num_channels), nn.ReLU(),
    nn.AdaptiveAvgPool2d((1, 1)),  # 最终使用全局汇聚层和全连接层输出结果
    nn.Flatten(),
    nn.Linear(num_channels, 10))

lr, num_epochs, batch_size = 0.1, 10, 256
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size, resize=224)
# d2l.train_ch6(net2, train_iter, test_iter, num_epochs, lr, d2l.try_gpu())
# 别跑,一跑显存直接爆炸
# CUDA out of memory. Tried to allocate 294.00 MiB (GPU 0; 4.00 GiB total capacity; 2.48 GiB already allocated; 109.80 MiB free; 2.61 GiB reserved in total by PyTorch) If reserved memory is >> allocated memory try setting max_split_size_mb to avoid fragmentation.  See documentation for Memory Management and PYTORCH_CUDA_ALLOC_CONF

(4)实现 DenseNet 论文表 1 所示的不同 DenseNet 版本。

在这里插入图片描述

def conv_block_121(input_channels, num_channels):
    return nn.Sequential(
        nn.BatchNorm2d(input_channels), nn.ReLU(),
        nn.Conv2d(input_channels, 4 * input_channels, kernel_size=1),  # 按原作加个BottleNeck
        nn.BatchNorm2d(4 * input_channels), nn.ReLU(),
        nn.Conv2d(4 * input_channels, num_channels, kernel_size=3, padding=1))

class DenseBlock_121(nn.Module):
    def __init__(self, num_convs, input_channels, num_channels):
        super(DenseBlock_121, self).__init__()
        layer = []
        for i in range(num_convs):
            layer.append(conv_block_121(
                num_channels * i + input_channels, num_channels))
        self.net = nn.Sequential(*layer)

    def forward(self, X):
        for blk in self.net:
            Y = blk(X)
            X = torch.cat((X, Y), dim=1)
        return X

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_convs_in_dense_blocks_121 = [6, 12, 23, 16]
num_channels, growth_rate = 64, 32
blks_121 = []
for i, num_convs in enumerate(num_convs_in_dense_blocks_121):
    blks_121.append(DenseBlock_121(num_convs, num_channels, growth_rate))
    num_channels += num_convs * growth_rate
    if i != len(num_convs_in_dense_blocks_121) - 1:
        blks_121.append(conv_block_121(num_channels, num_channels // 2))
        num_channels = num_channels // 2

net3 = nn.Sequential(
    b1, *blks_121,
    nn.BatchNorm2d(num_channels), nn.ReLU(),
    nn.AdaptiveAvgPool2d((1, 1)),
    nn.Flatten(),
    nn.Linear(num_channels, 10))

lr, num_epochs, batch_size = 0.1, 10, 64
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size, resize=96)
# d2l.train_ch6(net3, train_iter, test_iter, num_epochs, lr, d2l.try_gpu())
# 跑不了一点,batch_size都调到 64 了,还是爆显存,看看 shape 得了
# CUDA out of memory. Tried to allocate 90.00 MiB (GPU 0; 4.00 GiB total capacity; 2.49 GiB already allocated; 19.80 MiB free; 2.74 GiB reserved in total by PyTorch) If reserved memory is >> allocated memory try setting max_split_size_mb to avoid fragmentation.  See documentation for Memory Management and PYTORCH_CUDA_ALLOC_CONF

X = torch.rand(size=(1, 1, 224, 224))  # 好吧,看个 shape 都得 6.5 秒
for layer in net3:
    X = layer(X)
    print(layer.__class__.__name__,'output shape:\t', X.shape)
Sequential output shape:	 torch.Size([1, 64, 56, 56])
DenseBlock_121 output shape:	 torch.Size([1, 256, 56, 56])
Sequential output shape:	 torch.Size([1, 128, 56, 56])
DenseBlock_121 output shape:	 torch.Size([1, 512, 56, 56])
Sequential output shape:	 torch.Size([1, 256, 56, 56])
DenseBlock_121 output shape:	 torch.Size([1, 992, 56, 56])
Sequential output shape:	 torch.Size([1, 496, 56, 56])
DenseBlock_121 output shape:	 torch.Size([1, 1008, 56, 56])
BatchNorm2d output shape:	 torch.Size([1, 1008, 56, 56])
ReLU output shape:	 torch.Size([1, 1008, 56, 56])
AdaptiveAvgPool2d output shape:	 torch.Size([1, 1008, 1, 1])
Flatten output shape:	 torch.Size([1, 1008])
Linear output shape:	 torch.Size([1, 10])

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1035921.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

CRM客户管理系统英文专业版

外资公司日常沟通的语言以英文为主,业务往来也是涉及到国内外,专业的英文版CRM系统很适合这样的业务团队,尤其CRM供应商是国际化企业,在海外也有分公司、办事处。 多语言 ZOHO支持多语种如英语、汉语、日语等28种语言&#xff0…

Next.js 13.5 正式发布,速度大幅提升!

9 月 19 日,Next.js 13.5 正式发布,该版本通过以下方式提高了本地开发性能和可靠性: 本地服务器启动速度提高 22%:使用App和Pages Router可以更快地进行迭代 HMR(快速刷新)速度提高 29%:在保存…

C++之指向引用的指针和指向指针的引用总结(二百三十四)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 人生格言: 人生…

【计算机视觉】图像的获取和表示——图像传感器技术|主要参数解析、成像原理剖析、传感器处理

博主简介:努力学习的22级计算机科学与技术本科生🌸博主主页: 是瑶瑶子啦每日一言🌼: 每一个不曾起舞的日子,都是对生命的辜负。——尼采 前言 文章目录 前言一、图像传感器技术1.0:前言1.1:两种…

自定义类型详解(上)

结构体 1 结构体的声明 1.1 结构的基础知识 结构是一些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量。 1.2 结构的声明 struct tag//struct是结构体的标志,tag是标签;名字。 {member-list;//成员变量 }variable-list;//变量列…

Nginx 关闭/屏蔽 PUT、DELETE、OPTIONS 请求

1、修改 nginx 配置 在 nginx 配置文件中,增加如下配置内容: if ($request_method !~* GET|POST|HEAD) {return 403; }修改效果如下: 2、重启 nginx 服务 systemctl restart nginx或者 service nginx restart3、功能验证 使用如下方式…

【计算机网络】互联网公司的网络架构和业务场景

互联网公司的网络架构和业务场景 1. 互联网公司网络的组成1.1 网络的物理组成1.2 骨干网组成1.3 数据中心网络组成 2.互联网公司网络服务场景2.1 通用服务场景2.1.1 客户端到服务端请求真实网络过程2.1.2 客户端到服务端请求抽象网络过程2.1.3 负载均衡网络模型 2.2 边缘服务场…

Xilinx FPGA 程序固化重新上电程序不运行的问题

问题描述 FPGA直接下载bit文件,功能正常。 FPGA擦除FLASH,烧写FLASH,正常。 电源断电,重新上电,FALSH里面的程序没有启动,FPGA程序没有跑起来。–FLASH启动不正常。 解决办法 在XDC约束文件里边增加约束: ## Configuration options, can be used for all designs se…

京东获得JD商品详情 API 返回值说明

京东商品详情API接口可以获得JD商品详情原数据。 这个API接口有两种参数,公共参数和请求参数。 公共参数有以下几个: apikey:这是您自己的API密钥,可以在京东开发者中心获取。 请求参数有以下几个: num_iid&#…

11 FPGA_简易电压表设计与验证(附代码)

1. 模数转换理论 模数转换器又称(A/D转换器),通常是指一个将模拟信号转变为数字信号的电子元件或电路。常见的转换方式使将模拟量与基准量比对得到便于传输的二进制信号。生活中常见的模拟量有温湿度、图像、声音等。模拟信号与数字信号的转换…

Spring学习笔记4 Bean的作用域

Spring学习笔记3 Spring对IOC的实现_biubiubiu0706的博客-CSDN博客 新建模块 spring-004 引入依赖 <dependencies><!--Spring依赖--><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId>&…

企业申报“专精特新”,对知识产权有哪些要求?

深科信从深圳市中小企业服务局发布的公开数据中了解到&#xff0c;2022年深圳市专精特新中小企业申报8000余家&#xff0c;通过4800余家。2023年深圳市专精特新企业认定火热申报中&#xff0c;10月15日截止。 成为“专精特新”企业有什么好处? 1.国家级资质强力背书&#xff…

WordPress主题DUX v8.2源码下载

新增产品分类左侧多级分类折叠显示 新增网站默认字体对 MiSans 和 HarmonyOS Sans 的支持 新增顶部左上角显示登录注册的模块开关&#xff0c;且支持原生登录方式 新增手机端导航菜单的关闭按钮 新增文章内容中标题二的强化展示 新增全站禁止复制、右键和选择的操作 新增文章内…

fastjson反序列化漏洞(CVE-2017-18349)

文章目录 fastjson序列化FastJson 序列化操作反序列化漏洞原理漏洞复现&#xff08;CVE-2017-18349&#xff09; fastjson fastjson 是阿里巴巴开发的 java语言编写的高性能 JSON 库,用于将数据在 Json 和 Java Object之间相互转换。它没有用java的序列化机制,而是自定义了一套…

分类预测 | MATLAB实现WOA-CNN-BiGRU-Attention数据分类预测(SE注意力机制)

分类预测 | MATLAB实现WOA-CNN-BiGRU-Attention数据分类预测&#xff08;SE注意力机制&#xff09; 目录 分类预测 | MATLAB实现WOA-CNN-BiGRU-Attention数据分类预测&#xff08;SE注意力机制&#xff09;分类效果基本描述模型描述程序设计参考资料 分类效果 基本描述 1.MATLA…

Quartus出租车计费器verilog计价器

名称&#xff1a;出租车计费器verilog计价器 软件&#xff1a;Quartus 语言&#xff1a;Verilog 要求&#xff1a; 出租车计费器&#xff0c;起步价10元&#xff0c;3公里内起步价&#xff0c;可以切换白天和夜晚计费&#xff0c;白天时超过3公里后2.4元每公里&#xff0c;停…

RabbitMQ实现秒杀场景示例

本文章通过MQ队列来实现秒杀场景 整体的设计如下图&#xff0c;整个流程中对于发送发MQ失败和发送到死信队列的数据未做后续处理 1、首先先创建MQ的配置文件 Configuration public class RabbitConfig {public static final String DEAD_LETTER_EXCHANGE "deadLetterE…

springcloud3 分布式事务-seata的四种模式总结以及异地容灾

一 seata四种模式比较 1.1 seata的4种模式比较 二 seata的高可用 2.1架构 1.建TC服务集群非常简单&#xff0c;启动多个TC服务&#xff0c;注册到nacos即可。 2.做异地多机房容灾&#xff0c;比如一个TC集群在上海&#xff0c;另一个TC集群在杭州&#xff0c; 3.微服务基…

趣解设计模式之《小王的糖果售卖机》

〇、小故事 小王最近一直在寻找商机&#xff0c;他发现商场儿童乐园或者中小学校周围&#xff0c;会有很多小朋友喜欢吃糖果&#xff0c;那么他想设计一款糖果售卖机&#xff0c;让后将这些糖果售卖机布置到商场和学校旁边&#xff0c;这样就能获得源源不断的收益了。 想到这里…

20 个实例玩转 Java 8 Stream

20 个实例玩转 Java 8 Stream 1、Stream概述 Java 8 是一个非常成功的版本&#xff0c;这个版本新增的 Stream&#xff0c;配合同版本出现的 Lambda&#xff0c;给我们操作集合 Collection 提供了极大的便利。 那么什么是 Stream&#xff1f; Stream 将要处理的元素集合看作…