Pytorch实现卷积、Depthwise Convolution、分组卷积、动态卷积和转置卷积、反卷积、全卷积、空洞卷积、可变形卷积、深度可分离卷积等操作

底层是用img2col实现的,但是如果想用pytorch来实现,可以试试torch.unfold这个函数,

torch.unfold

torch.unfold可以按照指定维度,以一定的间隔将原始张量进行分片(slicing),然后返回重整后的张量。先以二维矩阵展示其用法

>>> a = torch.arange(16).view(4, 4)
>>> a
tensor([[ 0,  1,  2,  3],
        [ 4,  5,  6,  7],
        [ 8,  9, 10, 11],
        [12, 13, 14, 15]])
>>> b = a.unfold(0, 3, 1)           # 按照行,以每3个元素,跨步为1进行展开
>>> b
tensor([[[ 0,  4,  8],
         [ 1,  5,  9],
         [ 2,  6, 10],
         [ 3,  7, 11]],

        [[ 4,  8, 12],
         [ 5,  9, 13],
         [ 6, 10, 14],
         [ 7, 11, 15]]])
>>> b.shape
torch.Size([2, 4, 3])
>>> c = b.unfold(1, 3, 1)           # 对b按照列以每3个元素跨步为1进行展开
>>> c                               # 注意此时c即为3x3滑动窗展开结果
tensor([[[[ 0,  1,  2],
          [ 4,  5,  6],
          [ 8,  9, 10]],

         [[ 1,  2,  3],
          [ 5,  6,  7],
          [ 9, 10, 11]]],


        [[[ 4,  5,  6],
          [ 8,  9, 10],
          [12, 13, 14]],

         [[ 5,  6,  7],
          [ 9, 10, 11],
          [13, 14, 15]]]])
>>> c.shape
torch.Size([2, 2, 3, 3])

这里看出b是a按照行,以每3个元素,跨步为1进行展开;而c是对b按照列以每3个元素跨步为1进行展开,注意此时c即为3×3滑动窗展开结果。这里c的前两维2×2,表示的是卷积输出结果的大小;而后面3×3即是为了完成卷积运算所需要的滑动窗内输入元素。因此卷积结果就是让卷积核权重与2×2个3×3的滑动窗元素相乘并加和得到。

而CNN中完整的卷积是对于两个4维张量进行操作。其中输入 X 尺寸大小为 N × C × H × W N\times C\times H \times W N×C×H×W,分别代表了批样本量(batch size),输入通道数(channel),输入长和宽。而卷积核尺寸大小为 D × C × K × K D\times C\times K\times K D×C×K×K,分别代表输出通道数,输入通道数,和卷积核尺寸(kernel size)。 而在每个输出通道上由 C × K × K C\times K\times K C×K×K 的单个卷积核与 C × H × W C\times H\times W C×H×W 输入通道分别进行二维卷积,再累加在一起形成一个二维的输出。
下面函数就实现了以上逻辑:

def conv2d(x, weight, bias, stride, pad): 
    n, c, h_in, w_in = x.shape
    d, c, k, j = weight.shape
    x_pad = torch.zeros(n, c, h_in+2*pad, w_in+2*pad)   # 对输入进行补零操作
    if pad>0:
        x_pad[:, :, pad:-pad, pad:-pad] = x
    else:
        x_pad = x

    x_pad = x_pad.unfold(2, k, stride)
    x_pad = x_pad.unfold(3, j, stride)        # 按照滑动窗展开
    out = torch.einsum(                          # 按照滑动窗相乘,
        'nchwkj,dckj->ndhw',                    # 并将所有输入通道卷积结果累加
        x_pad, weight)
    out = out + bias.view(1, -1, 1, 1)          # 添加偏置值
    return out

上面代码’nchwkj,dckj->ndhw’中,hw是过了两次unfolder的结果,刚好是输出卷积特征图的hwkj是卷积核的hw,dc是卷积核的输出通道和输入通道

在这里插入图片描述
https://github.com/arogozhnikov/einops ,里面将einsum实现了扩展,可以玩转多种复杂张量操作,有空可以专门另写一篇好好聊聊。

深度卷积(Depthwise Convolution)

所谓Depthwise Convolution,就是在进行卷积的时候,只是各个通道对应相乘,而不进行累加求和。那么实现起来,只需要改动torch.einsum的求和指标即可

out = torch.einsum('nchwkj,ckj->nchw', x_pad, weight)

此时的权重shape也变成了 C × 1 × K × K C\times 1\times K\times K C×1×K×K

分组卷积(Group Convolution)

分组卷积就是在进行卷积运算时,输入通道不是全部参与计算,而是分割开来成为几组,每组内部进行正常卷积。那实现起来,就需要对输入和权重进行一下reshape,都变成多组形式,然后每个组内进行相乘累加求和。新的改造代码如下

def group_conv2d(x, weight, bias, stride, pad, groups): 
    n, c, h_in, w_in = x.shape
    d, c_g, k, j = weight.shape
    assert c // groups == c_g                                     # 保证分组之后通道相同
    x_pad = torch.zeros(n, c, h_in+2*pad, w_in+2*pad)   # 对输入进行补零操作
    if pad>0:
        x_pad[:, :, pad:-pad, pad:-pad] = x
    else:
        x_pad = x

    x_pad = x_pad.unfold(2, k, stride)
    x_pad = x_pad.unfold(3, j, stride)                            # 按照滑动窗展开
    h_pad, w_pad = x_pad.size(2), x_pad.size(3)
    x_pad = x_pad.reshape(n, groups, -1, h_pad, w_pad, k, j)      # 对输入按照通道分组
    weight = weight.reshape(groups, -1, c_g, k, j)                      # 对权重按照输出通道分组
    out = torch.einsum(                                  # 按照滑动窗相乘,
        'ngchwkj,gdckj->ngdhw',                      # 并将所有输入通道卷积结果累加
        x_pad, weight)
    out = out.reshape(n, d, out.size(3), out.size(4))                     # 再重新reshape成完整输出
    out = out + bias.view(1, -1, 1, 1)                                          # 添加偏置值
    return out

动态卷积(Dynamic Convolution)

所谓动态卷积,本质思想就是让一个batch的输入内部各个单独张量,可以有不同的权重值进行卷积操作。 现在的常规卷积是共享的。那实现这种动态卷积最大难点是什么呢?为了提高并行度与速度,就不可能按照for循环每一个输入与不同的权重相乘。所以也是有很多工作想办法去解决这个问题。比如NeurIPS 2019的这篇文章
https://proceedings.neurips.cc/paper/2019/file/f2201f5191c4e92cc5af043eebfd0946-Paper.pdf

就提出CondConv,先根据输入产生一组gate,然后在已有的一组权重上进行加权,从而实现动态调节产生动态权重。具体如下图

在这里插入图片描述
左侧是CondConv示意图,右侧是他们论证这个等效于Mixture of Experts,就是先计算多组卷积结果,再用gate融合。但是相比MoE,CondConv只需要执行整体的一次卷积即可。

那具体怎么实现呢?有一种实现方式,是把N个Batch按照channel维度堆叠起来,然后做group convolution,再拆分开来。那按照我们上面的实现思路,CondConv实现起来非常直观。我们忽略掉产生gate动态加权权重的部分,假设已经产生了 N\times D\times C\times K\times K 的权重,那么只需要更改一行torch.einsum代码即可

out = torch.einsum('nchwkj,ndckj->ndhw', x_pad, weight)

以上摘录自 https://www.zhihu.com/tardis/zm/art/349683405?source_id=1003

深度可分离卷积(Depthwise separable convolution)

来自于MobileNet V1,顾名思义,来自于分离+Depthwise Convolution 的操作:
在这里插入图片描述

转置卷积=反卷积(为了上采样,语义分割用)

细节可以参考 FCN 全卷积网络和转置卷积,反卷积是上采样(unsampling) 的一种方式,论文作者在实验之后发现反卷积相较于其他上采样方式例如 bilinear upsampling 效率更高,所以采用了这种方式。关于反卷积的解释借鉴了这一篇: https://medium.com/activating-robotic-minds/up-sampling-with-transposed-convolution-9ae4f2df52d0, 英文OK的小伙伴推荐看原文,讲的很通透。

全卷积

FCN 的基本结构很简单,就是全部由卷积层组成的网络。用于图像分类的网络一般结构是"卷积-池化-卷积-池化-全连接",其中卷积和全连接层是有参数的,池化则没有参数。论文作者认为全连接层让目标的位置信息消失了,只保留了语义信息,因此将全连接操作更换为卷积操作可以同时保留位置信息及语义信息,达到给每个像素分类的目的。网络的基本结构如下:
在这里插入图片描述

空洞卷积(为了上采样,语义分割用)

如何不通过池化等下采样操作就能扩大感受野呢?空洞卷积应运而生。顾名思义,空洞卷积就是在标准的卷积核中注入“空洞”,以增加卷积核的感受野。空洞卷积引入了扩张率(dilation rate)这个超参数来指定相邻采样点之间的间隔,扩张率为了的空洞卷积。

可变形卷积

可变形卷积在卷积核的每个采样点上添加一个可学习的偏移量(offset),让采样点不再局限于规则的网格点。
在这里插入图片描述
适应物体在不同图片中出现的复杂几何形变(如尺度形态、非刚性形变等),一直是物体识别领域的难点,可变形卷积网络给出了一个可行的解决方案。它可以端到端地学习几何形变的偏移量,不需要额外的监督信息,并且只增加了少许计算量,最终却能带来效果的显著提升。

全文搜集自:

  1. https://www.zhihu.com/tardis/zm/art/349683405?source_id=1003
  2. 葫芦书
  3. https://zhuanlan.zhihu.com/p/92134485

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

开发知识点-前端-layUI

layui layertabletable render <script type"text/html" id"buttonTpl">{{# if(d.check true){ }}<button class"layui-btn layui-btn-xs">已审核</button>{{# } else { }}<button class"layui-btn layui-btn-prim…

Docker镜像导出/导入

Docker镜像导出/导入 一、前言 在实际操作中&#xff0c;为了便于docker镜像环境和服务配置的迁移&#xff0c;我们有时需要将已在测试环境主机上完成一系列配置的docker镜像或运行中的容器镜像导出&#xff0c;并传输到生产或其他目标环境主机上运行。为此&#xff0c;本文主…

Python-sklearn-LinearRegression

目录 1 手动实现/使用sklearn实现线性回归训练 1.1 单特征线性回归&#xff08;One Feature&#xff09; 1.2 多特征线性回归&#xff08;Multiple Features&#xff09; 1.3 多项式线性回归&#xff08;Polynomial&#xff09; 1 手动实现/使用sklearn实现线性回归训练 1…

flutter之终极报错

看到这个报错头都大了 一开始在网上各种搜搜&#xff0c;然后有人说是flutter版本的问题&#xff0c;改完版本之后还是不对&#xff0c;又是各种搜搜搜 有人说是环境变量的问题&#xff0c;后来改了环境变量&#xff0c;妈的&#xff0c;竟然还不行&#xff0c;想砸电脑的心都…

深入浅出RPC原理

远程过程调用(Remote Procedure Call&#xff0c;简称RPC)&#xff0c;在微服务大行其道的今天&#xff0c;得到了广泛的应用。因此&#xff0c;在分布式系统服务群中开发应用&#xff0c;了解RPC一些原理和实现架构&#xff0c;还是很有必要的。本文&#xff0c;将从大的框架层…

js字符串转json的3种方法

1.eval方式解析 function strToJson(str){var json eval("(" str ")");return json;}console.log(strToJson("{int:1, string:demo}")); 运行截图&#xff1a; 注&#xff1a; 记得别忘了str两旁的小括号。 永远不要使用 eval !!! eval() 是一…

华容道问题求解第一部分_详细设计(一)之棋子和游戏类_初始化部分

按&#xff1a;因为自控力和能力的原因&#xff0c;这个其实是在和代码同时进行的。 主要 类 说明 这一层是整个项目的基础&#xff0c;将对未来的算法的效率产生重要影响。为了和界面隔离&#xff0c;以及自身逻辑的清晰&#xff0c;下面的两个类是必须的&#xff0c;棋子类…

42、网络编程/多点通信和域套接字通信模型20240304

一、多点通信之广播的收发端实现 1.广播发送端代码&#xff1a; #include<myhead.h>int main(int argc, const char *argv[]) {int sfdsocket(AF_INET,SOCK_DGRAM,0);//创建套接字if(sfd-1){perror("socket,error");return -1;}int broadcast1;//设置套接字广…

[计算机网络]:流量控制

一、流量控制简介 一条TCP连接的每一侧主机都为其设置了接收缓存&#xff0c;当TCP成功连接后&#xff0c;它发送的数据会放入接受缓存中。相关联的进程会从缓存中读取数据。但是存在一个问题&#xff0c;当某应用程序读取数据速率太慢&#xff0c;而发送数据一方不停的发送数…

计算机网络 网络原理之Http

目录 1 前言2 什么是http的一次交互&#xff1f;3 理解“协议”二字4 认识URL4.1 简介4.2 URL的编码和解码(urlencode和urldecode) 5 抓包工具 fiddler6 http和https的区别7 http 头8 HTTP 状态码9 常见的 Http 服务器 1 前言 为什么要了解Http原理呢&#xff1f;因为http原理…

Vue.js中的diff算法:让虚拟DOM更高效

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

计算机设计大赛 深度学习疲劳驾驶检测 opencv python

文章目录 0 前言1 课题背景2 实现目标3 当前市面上疲劳驾驶检测的方法4 相关数据集5 基于头部姿态的驾驶疲劳检测5.1 如何确定疲劳状态5.2 算法步骤5.3 打瞌睡判断 6 基于CNN与SVM的疲劳检测方法6.1 网络结构6.2 疲劳图像分类训练6.3 训练结果 7 最后 0 前言 &#x1f525; 优…

排序算法:插入排序

文章目录 插入排序 插入排序 什么叫插入排序&#xff1f; 也就是把数字从前&#xff0c;或者从最后开始比较然后插入到这个数的前面或者后面&#xff0c;从[0,end]区间插入 void InsertSort(int* a,int n) {for (int i 1; i < n; i){int end i-1;int tmp a[i];while (end…

华为配置基于VLAN限速示例

华为配置基于VLAN限速示例 组网图形 图1 流量监管配置组网图 表1 Switch为上行流量提供的QoS保障 流量类型 CIR(kbps) PIR(kbps) DSCP优先级 语音 2000 10000 46 视频 4000 10000 30 数据 4000 10000 14 ^^^ 流分类简介配置注意事项组网需求配置思路操作步…

实名制交友-智能匹配-仿二狗交友系统-TP6+uni-APP小程序H5公众号-源码交付-支持二开!

一、代码风格 通常不同的开发者具备不同的代码风格&#xff0c;但为了保证语音交友系统开发质量&#xff0c;在编码前需要进行代码风格的统一&#xff0c;通过制定一定的规则&#xff0c;约束开发者的行为。具有统一风格的代码才能更清晰、更完整、更容易理解、更方便后期维护…

【CSS】(浮动定位)易忘知识点汇总

浮动特性 加了浮动之后的元素,会具有很多特性,需要我们掌握的. 1、浮动元素会脱离标准流(脱标&#xff1a;浮动的盒子不再保留原先的位置) 2、浮动的元素会一行内显示并且元素顶部对齐 注意&#xff1a; 浮动的元素是互相贴靠在一起的&#xff08;不会有缝隙&#xff09;&…

基于机器学习的密码强度检测

项目简介 利用机器学习对提供的数据集预测用户输入的密码是否为弱密码。 原始数据集只包含关于弱密码的信息&#xff0c;并没有包含强密码的数据或分类器&#xff0c;这意味着模型无法学习到强密码的规律!!! 我之所以这样设计这个示例&#xff0c;其目的是为了向你展示模型的…

python统计分析——单变量数据统计作图

参考资料&#xff1a;python统计分析-托马斯 1、导入库和数据准备 # 导入库 # 用于数值处理的库 import numpy as np import pandas as pd import scipy as sp from scipy import stats # 用于绘图的库 import matplotlib.pyplot as plt import seaborn as sns sns.set()# 数…

安全特性 悬垂指针

英文名称 Dangling point&#xff0c;它还有一个兄弟叫 wild point - 野指针。 简单的对Dangling point做一个类比&#xff1a;我换手机号码了&#xff0c;但是没有通知老板&#xff0c;老板通讯录存的是我的旧号码。然后老板打电话有两种可能&#xff1a;打不通电话或者电话打…

OpenAI划时代大模型——文本生成视频模型Sora作品欣赏(十五)

Sora介绍 Sora是一个能以文本描述生成视频的人工智能模型&#xff0c;由美国人工智能研究机构OpenAI开发。 Sora这一名称源于日文“空”&#xff08;そら sora&#xff09;&#xff0c;即天空之意&#xff0c;以示其无限的创造潜力。其背后的技术是在OpenAI的文本到图像生成模…