图像分类学习笔记(六)——ResNeXt

news2025/1/23 3:56:06

一、要点

ResNeXt是ResNet的小幅升级,更新了block

 左边(ResNet的block/50/101/152层):

对于输入通道为256的特征矩阵,首先使用64个1×1的卷积核进行降维,再通过64个3×3的卷积核处理,再通过256个1×1的卷积核升维输出,将输出与输入进行相加,得到最终的输出。

使用右边的结构替代左边的结构:下面解释。

(一)论文中的性能参数指标

 (二)关于ResNet和ResNeXt在ImageNet上top-1 的错误率(计算量相同)

(三)组卷积 (Group Convolution)

当分组的个数与输入特征矩阵的channel是一致的,并且输入特征矩阵的channel也和输出特征矩阵的channel一致的话,就相当于对我们输入特征矩阵的每一个channel分配了一个channel为1的卷积核进行卷积。即DW卷积。

(四)ResNeXt的block结构

(c)(最简形式):输入通道为256维,首先通过128个1×1的卷积核降维处理,再通过group卷积(卷积核3×3,group数为32),得到的特征矩阵的通道是128维,再通过256个1×1的卷积核升维得到输出。再将输出和输入的特征矩阵进行相加得到最终的输出。

(b)和(c)等价

 (a)和(b)等价

 举例:假设path为2,对每个path采用1×1的卷积核来进行卷积

(五) 网络结构

二、使用pytorch搭建

代码是包括ResNet和ResNeXt的

import torch.nn as nn
import torch

# 18层/34层 对应的残差结构(既要有实线残差结构的功能,又要有虚线残差结构的功能)
class BasicBlock(nn.Module):
    expansion = 1  #残差结构的主分支卷积核的个数有无发生变化

    def __init__(self, in_channel, out_channel, stride=1, downsample=None, **kwargs): # downsample对应残差结构的虚线(shortcut分支)
        super(BasicBlock, self).__init__()
        # stride=1,对应着实线的残差结构,因为并没有改变输入特征矩阵的高和宽
        # output = (input -3 + 2 * 1) / 1 + 1 = input
        # stride=2,对应着虚线的残差结构,在第一个卷积层需要将特征矩阵的高和宽缩减为原来的一半
        # output = (input -3 + 2 * 1) / 2 + 1 = input / 2 + 0.5 = input / 2 (向下取整)
        self.conv1 = nn.Conv2d(in_channels=in_channel, out_channels=out_channel,
                               kernel_size=3, stride=stride, padding=1, bias=False)  # bias=False,不使用偏置项,因为下面用到BatchNormalization
        self.bn1 = nn.BatchNorm2d(out_channel)
        self.relu = nn.ReLU()
        self.conv2 = nn.Conv2d(in_channels=out_channel, out_channels=out_channel,
                               kernel_size=3, stride=1, padding=1, bias=False)
        self.bn2 = nn.BatchNorm2d(out_channel)
        self.downsample = downsample

    def forward(self, x):
        identity = x # shorcut上的输出值
        if self.downsample is not None:
            identity = self.downsample(x)

        out = self.conv1(x)
        out = self.bn1(out)
        out = self.relu(out)

        out = self.conv2(out)
        out = self.bn2(out)

        out += identity
        out = self.relu(out)

        return out

# 50层/101层/152层 对应的残差结构
class Bottleneck(nn.Module):
    """
    注意:原论文中,在虚线残差结构的主分支上,第一个1x1卷积层的步距是2,第二个3x3卷积层步距是1。
    但在pytorch官方实现过程中是第一个1x1卷积层的步距是1,第二个3x3卷积层步距是2,
    这么做的好处是能够在top1上提升大概0.5%的准确率。
    可参考Resnet v1.5 https://ngc.nvidia.com/catalog/model-scripts/nvidia:resnet_50_v1_5_for_pytorch
    """
    expansion = 4  #每个残差结构的最后一层卷积核的个数都是前两层的4倍

    def __init__(self, in_channel, out_channel, stride=1, downsample=None,
                 groups=1, width_per_group=64):
        super(Bottleneck, self).__init__()

        width = int(out_channel * (width_per_group / 64.)) * groups

        self.conv1 = nn.Conv2d(in_channels=in_channel, out_channels=width,
                               kernel_size=1, stride=1, bias=False)  # squeeze channels
        self.bn1 = nn.BatchNorm2d(width)
        # -----------------------------------------
        self.conv2 = nn.Conv2d(in_channels=width, out_channels=width, groups=groups,
                               kernel_size=3, stride=stride, bias=False, padding=1)
        self.bn2 = nn.BatchNorm2d(width)
        # -----------------------------------------
        self.conv3 = nn.Conv2d(in_channels=width, out_channels=out_channel*self.expansion,
                               kernel_size=1, stride=1, bias=False)  # unsqueeze channels
        self.bn3 = nn.BatchNorm2d(out_channel*self.expansion)
        self.relu = nn.ReLU(inplace=True)
        self.downsample = downsample

    def forward(self, x):
        identity = x
        if self.downsample is not None:
            identity = self.downsample(x)

        out = self.conv1(x)
        out = self.bn1(out)
        out = self.relu(out)

        out = self.conv2(out)
        out = self.bn2(out)
        out = self.relu(out)

        out = self.conv3(out)
        out = self.bn3(out)

        out += identity
        out = self.relu(out)

        return out


class ResNet(nn.Module):

    def __init__(self,
                 block, # 对应18/34层或者50/101/152层的残差结构
                 blocks_num, # 残差结构的个数,是个列表,以34层为例,就是[3,4,6,3]
                 num_classes=1000, # 训练集的分类个数
                 include_top=True, # 方便以后在ResNet网络上去搭建更复杂的网络
                 groups=1,
                 width_per_group=64):
        super(ResNet, self).__init__()
        self.include_top = include_top
        self.in_channel = 64

        self.groups = groups
        self.width_per_group = width_per_group

        self.conv1 = nn.Conv2d(3, self.in_channel, kernel_size=7, stride=2,
                               padding=3, bias=False)# 为了让特征矩阵的宽和高缩减为原来的一半,所以这里padding=3
        self.bn1 = nn.BatchNorm2d(self.in_channel)
        self.relu = nn.ReLU(inplace=True)
        self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)# 为了让特征矩阵的宽和高缩减为原来的一半,所以这里padding=1
        self.layer1 = self._make_layer(block, 64, blocks_num[0]) # conv2_x 对于50/101/152层来说,第一个残差结构的第一层只改变特征矩阵的深度,没有改变宽高,所以没有传入stride,默认为1
        self.layer2 = self._make_layer(block, 128, blocks_num[1], stride=2) # conv3_x
        self.layer3 = self._make_layer(block, 256, blocks_num[2], stride=2) # conv4_x
        self.layer4 = self._make_layer(block, 512, blocks_num[3], stride=2) # conv5_x
        if self.include_top:
            self.avgpool = nn.AdaptiveAvgPool2d((1, 1))  # output size = (1, 1)
            self.fc = nn.Linear(512 * block.expansion, num_classes)

        for m in self.modules():
            if isinstance(m, nn.Conv2d):
                nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')

    def _make_layer(self, block, channel, block_num, stride=1):
        downsample = None
        # 对于18/34层第一个残差结构,跳过这句
        if stride != 1 or self.in_channel != channel * block.expansion:
            downsample = nn.Sequential(
                nn.Conv2d(self.in_channel, channel * block.expansion, kernel_size=1, stride=stride, bias=False),
                nn.BatchNorm2d(channel * block.expansion))

        layers = []
        # 残差结构的第一层(虚线残差结构)
        layers.append(block(self.in_channel,
                            channel,
                            downsample=downsample,
                            stride=stride,
                            groups=self.groups,
                            width_per_group=self.width_per_group))
        self.in_channel = channel * block.expansion

        for _ in range(1, block_num):
            layers.append(block(self.in_channel,
                                channel,
                                groups=self.groups,
                                width_per_group=self.width_per_group))

        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)

        if self.include_top:
            x = self.avgpool(x)
            x = torch.flatten(x, 1)
            x = self.fc(x)

        return x


def resnet34(num_classes=1000, include_top=True):
    # https://download.pytorch.org/models/resnet34-333f7ec4.pth
    return ResNet(BasicBlock, [3, 4, 6, 3], num_classes=num_classes, include_top=include_top)


def resnet50(num_classes=1000, include_top=True):
    # https://download.pytorch.org/models/resnet50-19c8e357.pth
    return ResNet(Bottleneck, [3, 4, 6, 3], num_classes=num_classes, include_top=include_top)


def resnet101(num_classes=1000, include_top=True):
    # https://download.pytorch.org/models/resnet101-5d3b4d8f.pth
    return ResNet(Bottleneck, [3, 4, 23, 3], num_classes=num_classes, include_top=include_top)


def resnext50_32x4d(num_classes=1000, include_top=True):
    # https://download.pytorch.org/models/resnext50_32x4d-7cdf4587.pth
    groups = 32
    width_per_group = 4
    return ResNet(Bottleneck, [3, 4, 6, 3],
                  num_classes=num_classes,
                  include_top=include_top,
                  groups=groups,
                  width_per_group=width_per_group)


def resnext101_32x8d(num_classes=1000, include_top=True):
    # https://download.pytorch.org/models/resnext101_32x8d-8ba56ff5.pth
    groups = 32
    width_per_group = 8
    return ResNet(Bottleneck, [3, 4, 23, 3],
                  num_classes=num_classes,
                  include_top=include_top,
                  groups=groups,
                  width_per_group=width_per_group)

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

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

相关文章

volatile考点分析

今天我们学习并发编程中另一个重要的关键字volatile,虽然面试中它的占比低于synchronized,但依旧是不可忽略的内容。 关于volatile,我收集到了8个常见考点,围绕应用,特点和实现原理。 volatile有什么作用&#xff1f…

第六章:数据结构与算法-part2:数据的存储结构

文章目录 一、一般线性表存储1.1、线性表顺序存储1.2、线性表的链式存储1.2.1、 单链表1、单链表的存储2、单链表的基本操作的实现 1.2.2、双向链表 二、栈的存储结构2.1 顺序栈2.1.1、顺序栈的操作1、 初始化空栈2、插入3、删除操作pop4、获取栈顶元素 2.2 链栈 三、队列的存储…

精进面试技巧:如何在程序员面试中脱颖而出

🌷🍁 博主猫头虎 带您 Go to New World.✨🍁 🦄 博客首页——猫头虎的博客🎐 🐳《面试题大全专栏》 文章图文并茂🦕生动形象🦖简单易学!欢迎大家来踩踩~🌺 &a…

Docker harbor 私有仓库的部署和管理

目录 一、什么是Harbor 二、Harbor的特性 三、Harbor的构成 四、部署配置Docker Harbor 1. 首先需要安装 Docker-Compose 服务 2.部署 Harbor 服务 3.使用harbor仓库 (1)项目管理 (2)用户管理 一、什么是Harbor Harbor …

面试前的准备:程序员应该如何备战面试

🌷🍁 博主猫头虎 带您 Go to New World.✨🍁 🦄 博客首页——猫头虎的博客🎐 🐳《面试题大全专栏》 文章图文并茂🦕生动形象🦖简单易学!欢迎大家来踩踩~🌺 &a…

JavaScript 开发的asp网页获取RFID读卡器以http协议Request提交的访问文件,Response回应驱动设备显示文字

本示例使用的设备&#xff1a; 液显WIFI无线网络HTTP协议RFID云读卡器可编程实时可控开关TTS语-淘宝网 (taobao.com) <%LANGUAGE"JavaScript" CODEPAGE"65001"%><% //格式化显示系统日期时钟 function formatDate(time){var date new Date(time…

HAproxy(四十七)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 目录 前言 一、概述 1.1 简介 1.2 核心功能 1.3 关键特性 1.4 应用场景 二、安装 1.内核配置 2.编译安装 ​3. 建立配置文件 4. 添加为系统服务 5. 添加3和5运行级别下自启动…

数据恢复软件EasyRecovery16最新版本下载安装激活教程

EasyRecovery16作为一款专业的数据电脑恢复软件&#xff0c;除了有着优秀的数据恢复能力外&#xff0c;还有许多便捷的操作技巧。即便是对于计算机很是白目的使用者来说&#xff0c;Ontack EasyRecovery也是值得入手的&#xff0c;使用者不必大费周章去备份重要的文件&#xff…

通达信股票接口怎么设计委托撤单模块?(通达信接口开发)

在股市里运用到的设计委托撤单模块的主要目标是实现通过通达信股票接口提交委托和撤单操作。以下是设计委托撤单模块的一般步骤&#xff1a; 1. 连接通达信接口&#xff1a;首先需要使用通达信股票接口连接到通达信系统软件&#xff0c;以便能够与交易系统进行通信。这通常涉及…

SpringBoot项目(jar)部署,启动脚本

需求 SpringBoot项目&#xff08;jar&#xff09;部署&#xff0c;需要先关闭原来启动的项目&#xff0c;再启动新的项目。直接输入命令&#xff0c;费时费力&#xff0c;还容易出错。所以&#xff0c;使用脚本启动。 脚本 脚本名&#xff1a;start.sh 此脚本需要放置在jar包…

三维模型OBJ格式轻量化压缩并行计算处理方法浅析

三维模型OBJ格式轻量化压缩并行计算处理方法浅析 三维模型的轻量化是指通过一系列技术和算法来减小三维模型的文件大小&#xff0c;以提高模型在计算机中的加载、渲染和传输效率。并行计算是利用多个计算单元同时执行任务&#xff0c;以加速计算过程的一种技术。在三维模型的O…

Dubbo指标埋点

1. 指标接入说明 2. 指标体系设计 Dubbo的指标体系&#xff0c;总共涉及三块&#xff0c;指标收集、本地聚合、指标推送 指标收集&#xff1a;将Dubbo内部需要监控的指标推送至统一的Collector中进行存储本地聚合&#xff1a;指标收集获取的均为基础指标&#xff0c;而一些分…

OpenAI推出ChatGPT企业版,提供更高安全和隐私保障

&#x1f989; AI新闻 &#x1f680; OpenAI推出ChatGPT企业版&#xff0c;提供更高安全和隐私保障 摘要&#xff1a;OpenAI发布了面向企业用户的ChatGPT企业版&#xff0c;用户可以无限制地访问强大的GPT-4模型&#xff0c;进行更深入的数据分析&#xff0c;并且拥有完全控制…

2023.8.24 关于 Selenium 的简单示例

目录 Selenium 是什么 Selenium 特点 Selenium 工作原理 流程图 使用 Selenium 实现一个简单自动化测试用例 Selenium 是什么 Selenium 是用来测试 Web 应用程序的功能和用户界面的 开源自动化测试工具 Selenium 特点 支持各种浏览器&#xff08;Chrome、Firefox、Safari&…

白皮书发布丨《多渠道协同,银行业数字化营销实践新范式》

数字化时代&#xff0c;银行业步入存量竞争阶段&#xff0c;各家银行在寻找新的市场增长点的同时&#xff0c;更重视现有客户的管理和挖掘&#xff0c;实现客户价值最大化。多渠道协同客群经营已经成为存量时代银行发展的核心竞争力。 神策数据今日发布《多渠道协同&#xff0c…

什么是伪类链(Pseudo-class Chaining)?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ Pseudo-class Chaining⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅&#xff01;这个专栏是为那些对Web开发感兴趣、刚刚…

Docker consul容器服务自动发现和更新

目录 一、什么是服务注册与发现 二、Docker-consul集群 1.Docker-consul 2.registrator 3.Consul-template 三、Docker-consul实现过程 四、Docker-consul集群配置 1.下载consul服务 2.web服务器启动多例nginx容器&#xff0c;使用registrator自动发现 3.使用…

CVE-2023-21839 Weblogic未授权RCE

https://github.com/4ra1n/CVE-2023-21839下载之后 生成CVE-2023-21389.exe 先试试dnslog&#xff1a; CVE-2023-21839.exe -ip 116.xx.xx.xx -port 7001 -ldap ldap://whoami.eduvck.dnslog.cn/aa然后使用JNDIExploit-1.4-SNAPSHOT.jar进行攻击 另一个终端上 首先开启监听 …

【c语言】结构体内存对齐,位段,枚举,联合

之前学完结构体&#xff0c;有没有对结构体的大小会很疑惑呢&#xff1f;&#xff1f;其实结构体在内存中存储时会存在内存对齐&#xff0c;捎带讲讲位段&#xff0c;枚举&#xff0c;和联合&#xff0c;跟着小张一起学习吧 结构体内存对齐 结构体的对齐规则: 第一个成员在与结…

2023.8.25 关于 Selenium 常用 API 详解

目录 引言 打开页面 查找页面元素 输入文本 点击操作 提交操作 清除文本 获取文本和属性值 ​编辑 选择多个元素 获取页面标题和URL 等待操作 浏览器操作 多层框架定位 窗口操作 屏幕截图 下拉框元素选择操作 ​编辑 执行脚本 文件上传 引言 本文讲的所有…