ResNet50V2
- 🍨 本文为🔗365天深度学习训练营 中的学习记录博客
- 🍖 原作者:K同学啊
一、ResNetV1和ResNetV2的区别
ResNetV2
和 ResNetV1
都是深度残差网络(ResNet)的变体,它们的主要区别在于残差块的设计和批归一化(Batch Normalization, BN)的使用方式。ResNetV2
是在 ResNetV1
的基础上进行改进的一种版本,旨在提高模型的性能和稳定性。以下是它们之间的一些关键区别:
1. 残差块中的批归一化位置
ResNetV1:
在 ResNetV1
中,批归一化层位于每个卷积层的后面,ReLU 激活函数在批归一化之后。具体来说,每个残差块的顺序是:
卷积层 -> 批归一化 -> ReLU -> 卷积层 -> 批归一化 -> 加和 -> ReLU
ResNetV2:
在 ResNetV2
中,批归一化和 ReLU 激活函数在每个卷积层之前进行。这种改变使得信息在模型中传播得更加顺畅,减轻了梯度消失的问题。具体来说,每个残差块的顺序是:
批归一化 -> ReLU -> 卷积层 -> 批归一化 -> ReLU -> 卷积层 -> 加和
2. 预激活残差块
ResNetV2
引入了“预激活残差块”(Pre-activation Residual Block)的概念,即在每个残差块中的卷积操作之前进行批归一化和激活。这种设计有助于信息流动,特别是在深层网络中。
3. 全局平均池化和分类层
在 ResNetV1
中,最后一个残差模块的输出经过批归一化和 ReLU 激活之后,再通过全局平均池化层和全连接层进行分类。
在 ResNetV2
中,全局平均池化层和分类层之间没有额外的激活函数和归一化操作,直接对预激活的输出进行池化和分类。
4. 网络的深度和参数数量
ResNetV2
通常会采用更多的参数以提高性能,这包括在更深层次上引入更多的卷积层和更复杂的架构设计。
二、ResNetV2代码实现(PyTorch)
import torch
import torch .nn as nn
import torch.nn.functional as F
# BasicBlock用于ResNet-18和ResNet-34
class BasicBlockV2(nn.Module):expansion = 1def __init__(self, in_channels, out_channels, stride=1, downsample=None):super(BasicBlockV2, self).__init__()# 在卷积层之前进行批归一化和 ReLU 激活,这是 ResNetV2 的主要区别之一self.bn1 = nn.BatchNorm2d(in_channels)self.relu = nn.ReLU(inplace=True)self.conv1 = nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=stride, padding=1, bias=False)self.bn2 = nn.BatchNorm2d(out_channels)self.relu = nn.ReLU(inplace=True)self.conv2 = nn.Conv2d(out_channels, out_channels, kernel_size=3, padding=1, bias=False)self.downsample = downsampledef forward(self, x):identity = x# 在卷积层之前进行批归一化和 ReLU 激活out = self.bn1(x)out = self.relu(out)out = self.conv1(out)out = self.bn2(out)out = self.relu(out)out = self.conv2(out)if self.downsample is not None:identity = self.downsample(x)out += identityreturn out
# Bottleneck用于ResNet-50, ResNet-101和ResNet-152
class BottleneckV2(nn.Module):expansion = 4 # 定义扩展因子def __init__(self, in_channels, out_channels, stride=1, downsample=None):super(BottleneckV2, self).__init__()# 在卷积层之前进行批归一化和 ReLU 激活,这是 ResNetV2 的主要区别之一self.bn1 = nn.BatchNorm2d(in_channels)self.relu = nn.ReLU(inplace=True)self.conv1 = nn.Conv2d(in_channels, out_channels, kernel_size=1, bias=False)self.bn2 = nn.BatchNorm2d(out_channels)self.conv2 = nn.Conv2d(out_channels, out_channels, kernel_size=3, stride=stride, padding=1, bias=False)self.bn3 = nn.BatchNorm2d(out_channels)self.conv3 = nn.Conv2d(out_channels, out_channels * self.expansion, kernel_size=1, bias=False)self.downsample = downsampledef forward(self, x):identity = x# 在卷积层之前进行批归一化和 ReLU 激活out = self.bn1(x)out = self.relu(out)out = self.conv1(out)out = self.bn2(out)out = self.relu(out)out = self.conv2(out)out = self.bn3(out)out = self.relu(out)out = self.conv3(out)if self.downsample is not None:identity = self.downsample(x)out += identityreturn out
class ResNetV2(nn.Module):def __init__(self, block, layers, num_classes=1000):"""初始化ResNetV2模型参数:block: 使用的残差块类型(BasicBlockV2 或 BottleneckV2)layers: 每个残差模块中的残差块数量列表,例如[3, 4, 6, 3]num_classes: 分类任务的类别数, 默认为1000(适用于ImageNet数据集)"""super(ResNetV2, self).__init__()self.in_channels = 64# 初始卷积层,7x7卷积,步幅2,填充3self.conv1 = nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3, bias=False)self.bn1 = nn.BatchNorm2d(64)self.relu = nn.ReLU(inplace=True)self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)# 创建四个残差模块self.layer1 = self._make_layer(block, 64, layers[0])self.layer2 = self._make_layer(block, 128, layers[1], stride=2)self.layer3 = self._make_layer(block, 256, layers[2], stride=2)self.layer4 = self._make_layer(block, 512, layers[3], stride=2)# 最后一个批归一化层,ResNetV2 的特点self.bn_last = nn.BatchNorm2d(512 * block.expansion)# 平均池化层和全连接层self.avgpool = nn.AdaptiveAvgPool2d((1, 1))self.fc = nn.Linear(512 * block.expansion, num_classes)def _make_layer(self, block, out_channels, blocks, stride=1):"""构建残差模块参数:block: 使用的残差块类型(BasicBlockV2 或 BottleneckV2)out_channels: 残差块的输出通道数blocks: 残差块数量stride: 第一个残差块的步幅, 默认为1返回: 残差模块序列"""downsample = None# 如果步幅不为1或输入通道数不匹配,则进行下采样if stride != 1 or self.in_channels != out_channels * block.expansion:downsample = nn.Sequential(nn.Conv2d(self.in_channels, out_channels * block.expansion, kernel_size=1, stride=stride, bias=False),nn.BatchNorm2d(out_channels * block.expansion),)layers = []# 第一个残差块,可能需要下采样layers.append(block(self.in_channels, out_channels, stride, downsample))self.in_channels = out_channels * block.expansion# 其余残差块for _ in range(1, blocks):layers.append(block(self.in_channels, out_channels))return nn.Sequential(*layers)def forward(self, x):x = self.conv1(x)x = self.bn1(x)x = self.relu(x)x = self.maxpool(x)x = self.layer1(x)x = self.layer2(x)x = self.layer3(x)x = self.layer4(x)# 最后的批归一化和 ReLU 激活x = self.bn_last(x)x = self.relu(x)# 全局平均池化和全连接层x = self.avgpool(x)x = torch.flatten(x, 1)x = self.fc(x)return x
def resnet18_v2(num_classes=1000):"""构建ResNet-18模型"""return ResNetV2(BasicBlockV2, [2, 2, 2, 2], num_classes)def resnet34_v2(num_classes=1000):"""构建ResNet-34模型"""return ResNetV2(BasicBlockV2, [3, 4, 6, 3], num_classes)def resnet50_v2(num_classes=1000):"""构建ResNet-50模型"""return ResNetV2(BottleneckV2, [3, 4, 6, 3], num_classes)def resnet101_v2(num_classes=1000):"""构建ResNet-101模型"""return ResNetV2(BottleneckV2, [3, 4, 23, 3], num_classes)def resnet152_v2(num_classes=1000):"""构建ResNet-152模型"""return ResNetV2(BottleneckV2, [3, 8, 36, 3], num_classes)
from torchinfo import summarymodel = resnet50_v2(num_classes=1000)
summary(model)
三、个人小结
通过对比 ResNetV1 和 ResNetV2,我们可以看出 ResNetV2 通过将批归一化和 ReLU 激活函数移动到卷积层之前,提出了预激活残差块的概念。这一改进不仅简化了梯度流动,减轻了梯度消失的问题,还提高了模型的训练稳定性和性能。本文还通过具体的代码实现,展示了如何在 PyTorch 中构建和训练 ResNetV2 模型,包括 ResNet-18, ResNet-34, ResNet-50, ResNet-101, 和 ResNet-152 各种变体。
相关文章:

ResNet50V2
🍨 本文为🔗365天深度学习训练营 中的学习记录博客🍖 原作者:K同学啊 一、ResNetV1和ResNetV2的区别 ResNetV2 和 ResNetV1 都是深度残差网络(ResNet)的变体,它们的主要区别在于残差块的设计和…...
基于深度学习的虚拟换装
基于深度学习的虚拟换装技术旨在通过计算机视觉和图像处理技术,将不同的服装虚拟地穿在用户身上,实现快速的试穿和展示。这项技术在电商、时尚和虚拟现实领域具有广泛的应用,能够提升用户体验,增加互动性。以下是关于这一领域的系…...

单段时间最优S型速度规划算法
一,背景 在做机械臂轨迹规划的单段路径的速度规划时,除了参考《Trajectory Planning for Automatic Machines and Robots》等文献之外,还在知乎找到了这位大佬 韩冰 写的在线规划方法: https://zhuanlan.zhihu.com/p/585253101/e…...
pom文件-微服务项目结构
一、微服务项目结构 my-microservices-project/ ├── pom.xml <!-- 父模块的pom.xml --> ├── ry-system/ │ ├── pom.xml <!-- 子模块ry-system的pom.xml --> │ └── src/main/java/com/example/rysystem/ │ └── RySystemApplication.…...
解析Kotlin中的Nothing【笔记摘要】
1.Nothing的本质 Nothing 的源码很简单: public class Nothing private constructor()可以看到它是个class,但它的构造函数是 private 的,这就导致我们没法创建它的实例,并且在源码里 Kotlin 也没有帮我们创建它的实例。 基于这…...
toRefs 和 toRef
文章目录 toRefs 和 toReftoRefstoRef toRefs 和 toRef toRefs toRefs 把一个由reactive对象的值变为一个一个ref的响应式的值 import { ref, reactive, toRefs, toRef } from vue; let person reactive({name: 张三,age: 18, }); // toRefs 把一个由reactive对象的值变为一…...

Vision Transformer论文阅读笔记
目录 An Image is Worth 16x16 Words: Transformers for Image Recognition at Scale -- Vision Transformer摘要Introduction—简介RELATED WORK—相关工作METHOD—方法VISION TRANSFORMER (VIT)—视觉Transformer(ViT) 分析与评估PRE-TRAINING DATA REQUIREMENTS—预训练数据…...
MapReduce的执行流程排序
MapReduce 是一种用于处理大规模数据集的分布式计算模型。它将作业分成多个阶段,以并行处理和分布式存储的方式来提高计算效率。以下是 MapReduce 的执行流程以及各个阶段的详细解释: 1. 作业提交(Job Submission) 用户通过客户端…...
雅思词汇及发音积累 2024.7.3
银行 check (美)支票 cheque /tʃek/ (英)支票 ATM 自动取款机 cashier 收银员 teller /ˈtelə(r)/ (银行)出纳员 loan 贷款 draw/withdraw money 提款 pin number/passsword/code …...

Vue2和Vue3的区别Vue3的组合式API
一、Vue2和Vue3的区别 1、创建方式的不同: (1)、vue2:是一个构造函数,通过该构造函数创建一个Vue实例 new Vue({})(2)、Vue3:是一个对象。并通过该对象的createApp()方法,创建一个vue实例。 Vue…...
ML307R OpenCPU HTTP使用
一、函数介绍 二、示例代码 三、代码下载地址 一、函数介绍 具体函数可以参考cm_http.h文件,这里给出几个我用到的函数 1、创建客户端实例 /*** @brief 创建客户端实例** @param [in] url 服务器地址(服务器地址url需要填写完整,例如(服务器url仅为格式示…...
【状态估计】线性高斯系统的状态估计——离散时间的递归滤波
前两篇文章介绍了离散时间的批量估计、离散时间的递归平滑,本文着重介绍离散时间的递归滤波。 前两篇位置:【状态估计】线性高斯系统的状态估计——离散时间的批量估计、【状态估计】线性高斯系统的状态估计——离散时间的递归平滑。 离散时间的递归滤波…...

架构设计上中的master三种架构,单节点,主从节点,多节点分析
文章目录 背景单节点优点缺点 主从节点优点缺点 多节点优点缺点 多节点,多backup设计优点缺点 总结 背景 在很多分布式系统里会有master,work这种结构。 master 节点负责管理资源,分发任务。下面着重讨论下master 数量不同带来的影响 单节点 优点 1.设…...

如何在 SQL 中删除一条记录?
如何在 SQL 中删除一条记录? 在 SQL 中,您可以使用DELETE查询和WHERE子句删除表中的一条记录。在本文中,我将向您介绍如何使用DELETE查询和WHERE子句删除记录。我还将向您展示如何一次从表中删除多条记录 如何在 SQL 中使用 DELETE 这是使…...

JavaSE (Java基础):面向对象(上)
8 面向对象 面向对象编程的本质就是:以类的方法组织代码,以对象的组织(封装)数据。 8.1 方法的回顾 package com.oop.demo01;// Demo01 类 public class Demo01 {// main方法public static void main(String[] args) {int c 10…...

flink使用StatementSet降低资源浪费
背景 项目中有很多ods层(mysql 通过cannal)kafka,需要对这些ods kakfa做一些etl操作后写入下一层的kafka(dwd层)。 一开始采用的是executeSql方式来执行每个ods→dwd层操作,即类似: def main(…...

FineDataLink4.1.9支持Kettle调用
FDL更新至4.1.9后,新增kettle调用功能,支持不增加额外负担的情况下,将现有的Kettle任务平滑迁移到FineDataLink。 一、更新版本前存在的问题与痛点 在此次功能更新前,用户可能会遇到以下问题: 1.对于仅使用kettle的…...

SwanLinkOS首批实现与HarmonyOS NEXT互联互通,软通动力子公司鸿湖万联助力鸿蒙生态统一互联
在刚刚落下帷幕的华为开发者大会2024上,伴随全场景智能操作系统HarmonyOS Next的盛大发布,作为基于OpenHarmony的同根同源系统生态,软通动力子公司鸿湖万联全域智能操作系统SwanLinkOS首批实现与HarmonyOS NEXT互联互通,率先攻克基…...

Win11禁止右键菜单折叠的方法
背景 在使用windows11的时候,会发现默认情况下,右键菜单折叠了。以至于在使用一些软件的右键菜单时总是要点击“显示更多选项”菜单展开所有菜单,然后再点击。而且每次在显示菜单时先是全部展示,再隐藏一下,看着着实难…...

Maven列出所有的依赖树
在 IntelliJ IDEA 中,你可以使用 Maven 插件来列出项目的依赖树。Maven 插件提供了一个名为dependency:tree的目标,可以帮助你获取项目的依赖树详细信息。 要列出项目的依赖树,可以执行以下步骤: 打开 IntelliJ IDEA,…...

eNSP-Cloud(实现本地电脑与eNSP内设备之间通信)
说明: 想象一下,你正在用eNSP搭建一个虚拟的网络世界,里面有虚拟的路由器、交换机、电脑(PC)等等。这些设备都在你的电脑里面“运行”,它们之间可以互相通信,就像一个封闭的小王国。 但是&#…...

手游刚开服就被攻击怎么办?如何防御DDoS?
开服初期是手游最脆弱的阶段,极易成为DDoS攻击的目标。一旦遭遇攻击,可能导致服务器瘫痪、玩家流失,甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案,帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...
day52 ResNet18 CBAM
在深度学习的旅程中,我们不断探索如何提升模型的性能。今天,我将分享我在 ResNet18 模型中插入 CBAM(Convolutional Block Attention Module)模块,并采用分阶段微调策略的实践过程。通过这个过程,我不仅提升…...
多场景 OkHttpClient 管理器 - Android 网络通信解决方案
下面是一个完整的 Android 实现,展示如何创建和管理多个 OkHttpClient 实例,分别用于长连接、普通 HTTP 请求和文件下载场景。 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas…...

IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)
文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...
OpenLayers 分屏对比(地图联动)
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能,和卷帘图层不一样的是,分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...
CMake控制VS2022项目文件分组
我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...

3-11单元格区域边界定位(End属性)学习笔记
返回一个Range 对象,只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意:它移动的位置必须是相连的有内容的单元格…...
docker 部署发现spring.profiles.active 问题
报错: org.springframework.boot.context.config.InvalidConfigDataPropertyException: Property spring.profiles.active imported from location class path resource [application-test.yml] is invalid in a profile specific resource [origin: class path re…...

LINUX 69 FTP 客服管理系统 man 5 /etc/vsftpd/vsftpd.conf
FTP 客服管理系统 实现kefu123登录,不允许匿名访问,kefu只能访问/data/kefu目录,不能查看其他目录 创建账号密码 useradd kefu echo 123|passwd -stdin kefu [rootcode caozx26420]# echo 123|passwd --stdin kefu 更改用户 kefu 的密码…...