轻量化模块整理,即插即用

news2025/5/25 1:01:07

轻量化模块整理,即插即用(持续更新)

整理一些轻量化的结构,作为知识储备,可以用到后续的项目和研究中

Mobilenetv3 深度可分离卷积

MobileNetV3 是一个轻量级的深度学习模型,专为移动和边缘设备上的高效推理而设计。MobileNetV3 是在 MobileNetV1 和 MobileNetV2 的基础上进行了进一步的优化,主要包括了网络架构的搜索和修改、硬件感知网络优化、以及使用了轻量级的注意力模块 SE(Squeeze-and-Excitation)和 h-swish 激活函数等

import torch  
import torch.nn as nn  
import torch.nn.functional as F  
  
class h_swish(nn.Module):  
    def forward(self, x):  
        return x * torch.sigmoid(x + 3) / 6  
  
class SEBlock(nn.Module):  
    def __init__(self, in_channels, reduction=4):  
        super(SEBlock, self).__init__()  
        self.avg_pool = nn.AdaptiveAvgPool2d(1)  
        self.fc = nn.Sequential(  
            nn.Linear(in_channels, in_channels // reduction, bias=False),  
            nn.ReLU(inplace=True),  
            nn.Linear(in_channels // reduction, in_channels, bias=False),  
            nn.Sigmoid()  
        )  
  
    def forward(self, x):  
        b, c, _, _ = x.size()  
        y = self.avg_pool(x).view(b, c)  
        y = self.fc(y).view(b, c, 1, 1)  
        return x * y.expand_as(x)  
  
class InvertedResidual(nn.Module):  
    def __init__(self, inp, oup, stride, expand_ratio, use_se=False):  
        super(InvertedResidual, self).__init__()  
        assert stride in [1, 2]  
  
        hidden_dim = int(round(inp * expand_ratio))  
        self.use_res_connect = stride == 1 and inp == oup  
  
        layers = []  
        if expand_ratio != 1:  
            # pw  
            layers.append(nn.Conv2d(inp, hidden_dim, 1, 1, 0, bias=False))  
            layers.append(nn.BatchNorm2d(hidden_dim))  
            layers.append(h_swish())  
  
        # dw  
        layers.append(nn.Conv2d(hidden_dim, hidden_dim, 3, stride, 1, groups=hidden_dim, bias=False))  
        layers.append(nn.BatchNorm2d(hidden_dim))  
        layers.append(h_swish())  
  
        if use_se:  
            layers.append(SEBlock(hidden_dim))  
  
        # pw-linear  
        layers.append(nn.Conv2d(hidden_dim, oup, 1, 1, 0, bias=False))  
        layers.append(nn.BatchNorm2d(oup))  
  
        self.conv = nn.Sequential(*layers)  
  
    def forward(self, x):  
        if self.use_res_connect:  
            return x + self.conv(x)  
        else:  
            return self.conv(x)  
  
# 使用示例  
# 输入通道数、输出通道数、步长、扩展比例、是否使用 SE 模块  
block = InvertedResidual(inp=32, oup=16, stride=2, expand_ratio=6, use_se=True)  
input_tensor = torch.randn(1, 32, 224, 224)  
output_tensor = block(input_tensor)  
print(output_tensor.shape)  # 输出张量的形状

上述代码定义了一个简化的 MobileNetV3 基础模块,包括一个 InvertedResidual(倒置残差)块和一个可选的 SE(Squeeze-and-Excitation)块。InvertedResidual 块是 MobileNetV3 的核心组件,它首先通过 1x1 卷积进行通道扩展,然后通过 3x3 深度可分离卷积进行空间卷积,最后通过 1x1 卷积恢复到目标通道数。SE 块则用于对特征进行自适应的重新加权。h_swish 是一种轻量级的激活函数,用于替换标准的 ReLU 或 swish 激活函数。

在pytorch中简单实现dw卷积

在PyTorch中实现深度可分离卷积(Depthwise Separable Convolution)可以通过两个步骤来完成:首先执行深度卷积(Depthwise Convolution),然后执行逐点卷积(Pointwise Convolution)。

深度卷积对输入的每个通道单独应用一个卷积核,因此输出的通道数与输入的通道数相同。而逐点卷积(也被称为1x1卷积)是对深度卷积的输出进行线性组合,以改变通道数。

以下是一个简单的PyTorch实现示例:

import torch  
import torch.nn as nn  
import torch.nn.functional as F  
  
class DepthwiseSeparableConv(nn.Module):  
    def __init__(self, in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, bias=False):  
        super(DepthwiseSeparableConv, self).__init__()  
        self.depthwise = nn.Conv2d(in_channels, in_channels, kernel_size, stride, padding, dilation, groups=in_channels, bias=bias)  
        self.pointwise = nn.Conv2d(in_channels, out_channels, 1, 1, 0, bias=bias)  
  
    def forward(self, x):  
        out = self.depthwise(x)  
        out = self.pointwise(out)  
        return out  
  
# 使用示例  
# 输入通道数、输出通道数、卷积核大小  
in_channels = 3  
out_channels = 16  
kernel_size = 3  
  
# 实例化深度可分离卷积层  
depthwise_separable_conv = DepthwiseSeparableConv(in_channels, out_channels, kernel_size)  
  
# 创建一个随机的输入张量  
input_tensor = torch.randn(1, in_channels, 32, 32)  
  
# 前向传播  
output_tensor = depthwise_separable_conv(input_tensor)  
  
# 打印输出张量的形状  
print(output_tensor.shape)  # 应该是 [1, out_channels, 32, 32]

在这个例子中,DepthwiseSeparableConv 类包含两个卷积层:depthwise(深度卷积层)和 pointwise(逐点卷积层)。在 forward 方法中,输入 x 首先通过深度卷积层,然后通过逐点卷积层。

注意,nn.Conv2d 在定义深度卷积层时使用了 groups=in_channels 参数,这表示每个输入通道都有一个独立的卷积核。这确保了深度卷积只在其自己的输入通道上进行操作。

然后,逐点卷积层(即1x1卷积)将深度卷积的输出作为输入,并输出具有所需通道数的特征图。

这种实现方法相比标准卷积更加高效,因为它减少了参数数量和计算量,特别适合在移动和嵌入式设备上使用。

在dw卷积中,增加膨胀了

在深度卷积中再实现扩张卷积(也称为空洞卷积或 Atrous Convolution)需要调整卷积层的参数来包含扩张率(dilation rate)。扩张卷积允许卷积核在输入特征图上以指定的间隔进行采样,从而在不增加参数数量的情况下增大卷积核的感受野。

在 PyTorch 中,你可以在 nn.Conv2d 中通过 dilation 参数来指定扩张率。因此,要在 DWConv 类中实现扩张卷积,你需要在初始化 nn.Conv2d 时传入一个 dilation 参数。

下面是一个修改后的 DWConv 类,参考了YOLOv5中的DWconv,另外,实现了深度卷积并带有扩张率:

import torch  
import torch.nn as nn  
import torch.nn.functional as F  
  
class Conv(nn.Module):  
    # Standard convolution  
    def __init__(self, c1, c2, k, s=1, p=None, g=1, act=True, dilation=1):  
        super(Conv, self).__init__()  
        self.conv = nn.Conv2d(c1, c2, k, s, autopad(k, p), groups=g, bias=False, dilation=dilation)  
        self.bn = nn.BatchNorm2d(c2)  
        self.act = nn.Hardswish() if act else nn.Identity()  
  
    def forward(self, x):  
        return self.act(self.bn(self.conv(x)))  
  
def autopad(k, p=None):  
    # Compute padding  
    if p is None:  
        p = k // 2  
    return p  
  
class DWConv(nn.Module):  
    # Depthwise Separable Convolution with dilation and pointwise convolution  
    def __init__(self, c1, c2, k=1, s=1, act=True, dilation=1):  
        super(DWConv, self).__init__()  
          
        # Depthwise Convolution  
        self.depthwise = Conv(c1, c1, k, s, act=False, g=c1, dilation=dilation)  
          
        # Pointwise Convolution (1x1 Convolution)  
        self.pointwise = Conv(c1, c2, 1)  
          
        # Activation function for the final output  
        self.act = nn.Hardswish() if act else nn.Identity()  
          
    def forward(self, x):  
        # Apply depthwise convolution  
        x = self.depthwise(x)  
        # Apply pointwise convolution  
        x = self.pointwise(x)  
        # Apply activation function  
        return self.act(x)  
  
# Example usage:  
# Create a depthwise separable convolution layer with dilation and pointwise convolution  
dw_separable_conv = DWConv(c1=64, c2=128, k=3, s=1, act=True, dilation=2)  
  
# Create an input tensor  
input_tensor = torch.randn(1, 64, 32, 32)  
  
# Forward pass through the layer  
output_tensor = dw_separable_conv(input_tensor)

在这个例子中,dw_conv_layer 是一个深度卷积层,它使用 3x3 的卷积核,步长为 1,并且有一个扩张率为 2,这意味着卷积核在输入特征图上的采样间隔为 2,从而增大了感受野。同时,由于 groups=c1,它仍然是一个深度卷积层,每个输入通道有一个独立的卷积核。

与普通卷积的对比

直接上代码

import torch  
import torch.nn as nn  
import torch.nn.functional as F  
  
class Conv(nn.Module):  
    # Standard convolution  
    def __init__(self, c1, c2, k, s=1, p=None, g=1, act=True, dilation=1):  
        super(Conv, self).__init__()  
        self.conv = nn.Conv2d(c1, c2, k, s, autopad(k, p), groups=g, bias=False, dilation=dilation)  
        self.bn = nn.BatchNorm2d(c2)  
        self.act = nn.Hardswish() if act else nn.Identity()  
  
    def forward(self, x):  
        return self.act(self.bn(self.conv(x)))  
  
def autopad(k, p=None):  
    # Compute padding  
    if p is None:  
        p = k // 2  
    return p  
  
class DWConv(nn.Module):  
    # Depthwise Separable Convolution with dilation and pointwise convolution  
    def __init__(self, c1, c2, k=1, s=1, act=True, dilation=1):  
        super(DWConv, self).__init__()  
          
        # Depthwise Convolution  
        self.depthwise = Conv(c1, c1, k, s, act=False, g=c1, dilation=dilation)  
          
        # Pointwise Convolution (1x1 Convolution)  
        self.pointwise = Conv(c1, c2, 1)  
          
        # Activation function for the final output  
        self.act = nn.Hardswish() if act else nn.Identity()  
          
    def forward(self, x):  
        # Apply depthwise convolution  
        x = self.depthwise(x)  
        # Apply pointwise convolution  
        x = self.pointwise(x)  
        # Apply activation function  
        return self.act(x)  
  
# Example usage:  
# Create a depthwise separable convolution layer with dilation and pointwise convolution  
dw_separable_conv = DWConv(c1=64, c2=128, k=3, s=1, act=True, dilation=2)  

normal_conv = Conv(c1=64, c2=128, k=3, s=1, act=True, dilation=2)

# Create an input tensor  
input_tensor = torch.randn(1, 64, 32, 32)  
print(input_tensor.shape)

# Forward pass through the layer  
output_tensor = dw_separable_conv(input_tensor)
print(output_tensor.shape)

print("Normal Convolution")
output_tensor = normal_conv(input_tensor)
print(output_tensor.shape)

# 计算参数量和计算量
from ptflops import get_model_complexity_info

flops,params = get_model_complexity_info(normal_conv,(64,640,640),as_strings=True,print_per_layer_stat=True)

print(" |flops: %s |params: %s" % (flops, params))
from fvcore.nn import FlopCountAnalysis
input_ = torch.randn((1, 64, 256, 256))
flops = FlopCountAnalysis(normal_conv, input_)
print("flops: ", flops.total() / 1e9)

print("DW Convolution")
# 计算参数量和计算量
from ptflops import get_model_complexity_info

flops,params = get_model_complexity_info(dw_separable_conv,(64,640,640),as_strings=True,print_per_layer_stat=True)

print(" |flops: %s |params: %s" % (flops, params))
from fvcore.nn import FlopCountAnalysis
input_ = torch.randn((1, 64, 256, 256))
flops = FlopCountAnalysis(dw_separable_conv, input_)
print("flops: ", flops.total() / 1e9)

在这里插入图片描述

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

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

相关文章

IntelliJ IDEA 2024 for Mac/Win:引领Java开发新纪元的高效集成环境

在日新月异的软件开发领域,一款高效、智能的集成开发环境(IDE)无疑是程序员们不可或缺的神兵利器。今天,我要为大家介绍的,正是这样一款集大成之作——IntelliJ IDEA 2024。无论是Mac用户还是Windows用户,只…

Golang | Leetcode Golang题解之第27题移除元素

题目&#xff1a; 题解&#xff1a; func removeElement(nums []int, val int) int {left, right : 0, len(nums)for left < right {if nums[left] val {nums[left] nums[right-1]right--} else {left}}return left }

8个 可以让 Python 加速的 tips

Python 是一种脚本语言&#xff0c;相比 C/C 这样的编译语言&#xff0c;在效率和性能方面存在一些不足。但是&#xff0c;有很多时候&#xff0c;Python 的效率并没有想象中的那么夸张。本文对一些 Python 代码加速运行的技巧进行整理。 0. 代码优化原则 本文会介绍不少的 P…

攻防世界12-baby_web

12-baby_web 题目说想想初始页面是哪个&#xff0c;一般都是index.php&#xff0c;然后如题分析即可。 我们在链接后面拼接上/index.php&#xff0c;返回后发现界面又回到了1.php&#xff0c;有可能是重定向。 我们点击检查-网络&#xff0c;发现没有index的请求&#xff0c;…

番外篇 | YOLOv8改进之在C2f中引入即插即用RepViTBlock模块 | CVPR2024清华RepViT

前言:Hello大家好,我是小哥谈。YOLOv8是一种基于深度学习的实时物体检测算法,其通过将物体检测任务转化为目标框回归问题,并使用卷积神经网络实现高效的特征提取和目标分类。然而,YOLOv8在处理一些复杂场景和小目标时可能存在一定的性能限制。为了克服YOLOv8的局限性,清华…

ES6: set和map数据结构以及使用场景

ES6:set和map数据结构 一、Set 数据结构&#xff1a;二、使用场景&#xff1a;使用Set 进行去重三、Map 数据结构四、使用场景&#xff1a;使用Map进行树型数据懒加载刷新五、Set和Map的区别六、Map、Set的实际使用场景 Set 和 Map 是 ES6 中引入的两种新的数据结构&#xff0c…

代码随想录算法训练营三刷day53 | 动态规划之子序列 1143.最长公共子序列 1035.不相交的线 53. 最大子序和

day53 1143.最长公共子序列1.确定dp数组&#xff08;dp table&#xff09;以及下标的含义2.确定递推公式3.dp数组如何初始化4.确定遍历顺序5.举例推导dp数组 1035.不相交的线53. 最大子序和1.确定dp数组&#xff08;dp table&#xff09;以及下标的含义2.确定递推公式3.dp数组如…

2024 十五届蓝桥杯省赛Python B组

以下仅是我的答案&#xff0c;仅供参考&#xff0c;欢迎讨论。 A&#xff1a;穿越时空之门 二进制、四进制转换。答案&#xff1a;63。 B&#xff1a;数字串个数 排除0&#xff0c;总的方案数9^10000,减去不存在3和不存在7的2*8^10000&#xff0c;再加上同时不存在3和7的7^…

Coding and Paper Letter(八十九)

CPL之第八十九期。 1 Coding: 1.openai通用代理转换是一个用于将其他厂商服务转为openai 标准接口相应的工具. 通过该工具, 可以将其他厂商的服务转为openai 标准接口. 讯飞星火,通义千问,gemini,openai,copilot,double&#xff0c;kimi&#xff0c;智谱清言 使用spring2webf…

Quantum Temple借助Sui通过NFT推动再生旅游

从金融到艺术&#xff0c;从游戏到无线网络&#xff0c;各行各业都涌现出大量初创公司&#xff0c;利用区块链技术颠覆现状。说到旅游业&#xff0c;让人联想到拥挤的机场、快节奏的旅游和豪华游轮&#xff0c;可能看起来对区块链创新持守旧态度。一家初创公司认为现在是时候改…

FreeRTOS创建第一个程序

使用freeRTOS创建任务时使用如下函数 函数的参数 创建一个FreeRTOS任务点亮led灯实现led灯500毫秒翻转一次 具体的代码实现 #include "stm32f10x.h" // Device header #include "Delay.h" #include "freeRTOS.h" #include &quo…

使用 Python 开发一个 Python 解释器

计算机只能理解机器码。归根结底&#xff0c;编程语言只是一串文字&#xff0c;目的是为了让人类更容易编写他们想让计算机做的事情。真正的魔法是由编译器和解释器完成&#xff0c;它们弥合了两者之间的差距。解释器逐行读取代码并将其转换为机器码。 在本文中&#xff0c;我…

C#简单工厂模式的实现

using System.Diagnostics.Metrics; using System.Runtime.InteropServices; using static 手写工厂模式.Program;namespace 手写工厂模式 {internal class Program{public interface eats {void eat();}//定义了一个接口public class rice : eats{public void eat() {Console.…

代码随想录算法训练营DAY25|C++回溯算法Part.2|216. 组合总和III、17.电话号码的字母组合

文章目录 216. 组合总和III题意理解树形结构伪代码实现剪枝操作CPP代码实现 17.电话号码的字母组合解题思路树形结构伪代码实现隐藏回溯CPP代码 216. 组合总和III 力扣题目链接 文章讲解&#xff1a;216. 组合总和III 视频讲解&#xff1a;和组合问题有啥区别&#xff1f;回溯算…

Oracle获取对象的DDL创建语句

1.命令行方式&#xff08;如&#xff1a;sqlplus&#xff09; ## 用户 select dbms_metadata.get_ddl(USER,TEST) from dual;## 表 select dbms_metadata.get_ddl(TABLE,TEST,T1) from dual;## 表空间 select dbms_metadata.get_ddl(TABLESPACE,TBS_NAME) from dual;## 索引 s…

【MySQL】:深入解析多表查询(下)

&#x1f3a5; 屿小夏 &#xff1a; 个人主页 &#x1f525;个人专栏 &#xff1a; MySQL从入门到进阶 &#x1f304; 莫道桑榆晚&#xff0c;为霞尚满天&#xff01; 文章目录 &#x1f4d1;前言一. 自连接1.1 自连接查询1.2 联合查询 二. 子查询2.1 概述2.2 分类2.3 标量子查…

Linux数据库自动备份 - 定时任务发到百度云盘、坚果云、邮箱附件

前言 1. 坚果云的webdav云盘最好&#xff01; &#xff08;免费账号每月1G上传流量&#xff09; 2. 不建议数据库备份文件发送到SMTP邮箱&#xff0c;因为对方服务器非常容易当做垃圾邮件处理&#xff0c;而且发信的SMTP账号会被封禁&#xff08;实测163发到QQ邮箱被封&…

区块链媒体推广的8个成功案例解析-华媒舍

区块链领域作为一个新兴行业&#xff0c;媒体推广对于项目的成功发展起着至关重要的作用。本文将从八个成功案例中来分析区块链媒体推广的重要性和成功策略。 1. 媒体报道对于区块链项目的重要影响 媒体报道是提升区块链项目知名度和用户认可度的重要手段。对于区块链项目来说…

蓝桥杯备赛:考前注意事项

考前注意事项 1、DevCpp添加c11支持 点击 工具 - 编译选项 中添加&#xff1a; -stdc112、万能头文件 #include <bits/stdc.h>万能头文件的缺陷&#xff1a;y1 变量 在<cmath>中用过了y1变量。 #include <bits/stdc.h> using namespace std;// 错误示例 …