【详细图解】再次理解im2col

【详细图解】再次理解im2col

转自:https://mp.weixin.qq.com/s/GPDYKQlIOq6Su0Ta9ipzig

一句话:im2col是将一个[C,H,W]矩阵变成一个[H,W]矩阵的一个方法,其原理是利用了行列式进行等价转换。

为什么要做im2col? 减少调用gemm的次数。

重要:本次的代码只是为了方便理解im2col,不是用来做加速,所以代码写的很简单且没有做任何优化。

一、卷积的可视化

例子是一个[1, 6, 6]的输入,卷积核是[1, 3, 3],stride等于1,padding等于0。那么卷积的过程可视化如下图,一共需要做16次卷积计算,每次卷积计算有9次乘法和8次加法。

在这里插入图片描述

输出的公式如下,即Output_height = (6 - 3 + 2*0)/1 + 1 = 4 = Output_width

在这里插入图片描述

二、行列式

在这里插入图片描述

乘号左边的横条,跟乘号右边的竖条进行点乘(即每个元素对应相乘后再全部加起来)。

关于行列式,大家都清楚的一点,一根横条的元素个数要等于一根竖条的元素个数(这样才可以让做点乘的时候能一一对应起来,不会让小方块落单)。竖条有多少条,出来的结果就有多少个小方块(在横条的个数为1的情况下)。

出来的结果(等号的右边)的行数等于乘号左边的横条的行数,出来的结果(等号的右边)的列数等于乘号右边的横条的列数,公式表示就是[row, x] * [x, col] = [row, col]。举个例子[3, 8] * [8, 4] = [3, 4]

在这里插入图片描述

三、[1, H, W]的im2col

在这里插入图片描述

在这里插入图片描述

展开后,就可以直接做两个数组的矩阵乘积了

在这里插入图片描述

import  numpy as npscr = np.array(np.arange(0,7**2).reshape(7, 7))
intH, intW= scr.shapekernel = np.array([-0.2589,  0.2106, -0.1583, -0.0107,  0.1177,  0.1693, -0.1582, -0.3048, -0.1946]).reshape(3,3)
KHeight, KWeight = kernel.shaperow_num = intH - KHeight + 1
col_num = intW - KWeight + 1
OutScrIm2Col = np.zeros([row_num*col_num,KHeight*KWeight]) ii, jj = 0, 0
col_cnt, row_cnt = 0, 0
for i in range(0, row_num):for j in range(0, col_num): # 这俩个for是为了遍历列,即乘了多少次,这里完全可以merge成一个for循环,只需要提前计算好就行ii = ijj = jfor iii in range(0, KHeight): # 这俩个for是为了取出一次 一横 * 一竖 的 行列式,这里完全可以mege成一个for循环,只需要提前计算好就行for jjj in range(0, KHeight):OutScrIm2Col[row_cnt][col_cnt] = scr[ii][jj]jj +=1col_cnt += 1ii += 1jj = jcol_cnt = 0row_cnt += 1im2col_kernel = im2col_kernel.reshape(-1,9)
OutScrIm2Col = OutScrIm2Col.T
out = np.matmul(im2col_kernel,OutScrIm2Col) # 这步就是做两个数组的矩阵乘积

中间俩个for循环是来填满展开的数组/矩阵的每一列,即卷积核对应的元素,其个数等于卷积核的元素个数,举个例子,[1, 3, 3]的卷积核,那么该卷积核的元素个数等于9;最外层的两个for循环是用来填满展开的数组/矩阵的每一行,即列数,也就是卷积核在输入滑动了多少次

在这里插入图片描述

pytorch来做验证

import torch
from torch import nn
import numpy as np
torch.manual_seed(100)net = nn.Conv2d(1, 1, 3, padding=0, bias=False)scr = np.array(np.arange(0, 7**2).reshape(1, 1, 7, 7)).astype(np.float32)
scr = torch.from_numpy(scr)print(net.weight.data) # 把这里的weight的值复制到上面numpy的代码来做验证
print(net(scr))# print的信息
tensor([[[[-0.2589,  0.2106, -0.1583],[-0.0107,  0.1177,  0.1693],[-0.1582, -0.3048, -0.1946]]]])
tensor([[[[ -7.6173,  -8.2053,  -8.7934,  -9.3815,  -9.9695],[-11.7337, -12.3217, -12.9098, -13.4978, -14.0859],[-15.8500, -16.4381, -17.0261, -17.6142, -18.2022],[-19.9664, -20.5545, -21.1425, -21.7306, -22.3186],[-24.0828, -24.6708, -25.2589, -25.8469, -26.4350]]]],grad_fn=<ThnnConv2DBackward>)

四、[C, H, W]的im2col

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

前面一堆图,是我故意不写文字,希望大家能够通过图能够看明白。前面卷积核只有一行的情况,跟[1, H, W]的情况基本一摸一样,只是这一行的元素个数等于卷积核的元素个数即可5x3x3=45,展开的特征图的每一个竖条也是45。

当卷积核函数等于3的时候,就是对应的只要增加卷积核的横条数即可,展开的特征图没有改变。这里希望大家用行列式的计算和普通卷积的过程联想起来,你会发现是一摸一样的计算过程。

代码其实跟[1,H, W]只有一初不同,就是从特征图里面取数据的时候多了个维度,需要取对应的通道。这里为什么要取对应的通道数呢?原因是行列式的计算中,横条和竖条是元素一一对应做乘法。

import  numpy as np
np.set_printoptions(threshold=np.inf)src = np.array(np.arange(0, 9**3))[0:5*9*9]
src = np.tile(src, 5)
src = src.reshape(-1, 5, 9, 9)
kernel = np.array([[[[-0.1158,  0.0942, -0.0708],[-0.0048,  0.0526,  0.0757],[-0.0708, -0.1363, -0.0870]],[[-0.1139, -0.1128,  0.0702],[ 0.0631,  0.0857, -0.0244],[ 0.1197,  0.1481,  0.0765]],[[-0.0823, -0.0589, -0.0959],[ 0.0966,  0.0166,  0.1422],[-0.0167,  0.1335,  0.0729]],[[-0.0032, -0.0768,  0.0597],[ 0.0083, -0.0754,  0.0867],[-0.0228, -0.1440, -0.0832]],[[ 0.1352,  0.0615, -0.1005],[ 0.1163,  0.0049, -0.1384],[ 0.0440, -0.0468, -0.0542]]]])scrN, srcChannel, intH, intW= src.shape
KoutChannel, KinChannel, kernel_H, kernel_W = kernel.shape
im2col_kernel = kernel.reshape(KoutChannel, -1)outChannel, outH, outW =  KoutChannel, (intH - kernel_H + 1) , (intW - kernel_W + 1)
OutScrIm2Col = np.zeros( [ kernel_H*kernel_W*KinChannel, outH*outW ] )
row_num, col_num = OutScrIm2Col.shapeii, jj, cnt_row, cnt_col = 0, 0, 0, 0# 卷积核的reshape准备 :outchannel, k*k*inchannel
im2col_kernel = kernel.reshape(KoutChannel, -1)
# 输入的reshape准备 :outH = (intH - k + 2*pading)/stride + 1 
outChannel, outH, outW =  KoutChannel, (intH - kernel_H + 1) , (intW - kernel_W + 1)i_id = -1
cnt_col = -1
cnr = 0
for Outim2colCol_H in range(0, outH):i_id += 1j_id = -1cnt_row  = -1for Outim2colCol_W in range(0, outW):j_id, cnt_col += 1,  += 1cnt_row = 0for c in range(0, srcChannel): # 取一次卷积的数据,放到一列for iii in range(0, kernel_H):i_number = iii + i_idfor jjj in range(0, kernel_W):j_number = jjj + j_idOutScrIm2Col[cnt_row][cnt_col] = src[bs][c][i_number][j_number]cnr +=1cnt_row += 1Out =  np.matmul(im2col_kernel, OutScrIm2Col)
Out.reshape(outChannel, outH, outW)
print(Out.shape)
print(outChannel, outH, outW)

pytorch代码的验证

import torch
from torch import nn
import numpy as np
torch.manual_seed(100)net = nn.Conv2d(in_channels=5, out_channels=1, kernel_size=3, padding=0, bias=False)
print(net.weight.data.shape)
print(net.weight.data)scr = np.array(np.arange(0, 9**3))[:9*9*5].reshape(1, -1, 9, 9).astype(np.float32)scr = torch.from_numpy(src)
print("data:", scr.shape)
scr = torch.from_numpy(scr)
print("data:", scr.shape)Out = net(scr)
print("Our:", Out.shape)
print(Out)

五、[B, C, H, W]的im2col

在这里插入图片描述

问题:如何bs=9的情况呢,要怎么做im2col+gemm呢?方法 1:把filter摊平的shape变成[3,5339],把input摊平的shape变成[5339,16]
– output的shape就为[3,16]了 - ❌

方法 2:把filter摊平的shape变成[39,533],把input摊平的shape变成[533,16],output的shape就为[39,16]了
– 隐患:如何filter数量是51233这种数量,那么非常占用显存/内存

方法 3:im2col+gemm外面加一层关于bs的for循环
– 隐患:加一层for循环嵌套非常耗时

经过简单分析,发现采取for循环的方式来进行im2col是相对合适的情况。我向msnh2012的作者穆士凝魂请教,得到的答案是,是用加一层for循环的方式居多,而且由于可以并发,多一层循环的开销比想象中小一些。如果是推理框架的话,有部分情况bs是等于1的,所以可以规避这个问题。

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

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

相关文章

反思 大班 快乐的机器人_幼儿园大班教案《快乐的桌椅》含反思

大班教案《快乐的桌椅》含反思适用于大班的体育主题教学活动当中&#xff0c;让幼儿提高协调性和灵敏性&#xff0c;创新桌椅的玩法&#xff0c;正确爬的方法&#xff0c;学会匍匐前进&#xff0c;快来看看幼儿园大班《快乐的桌椅》含反思教案吧。幼儿园大班教案《快乐的桌椅》…

DCN可形变卷积实现1:Python实现

DCN可形变卷积实现1&#xff1a;Python实现 我们会先用纯 Python 实现一个 Pytorch 版本的 DCN &#xff0c;然后实现其 C/CUDA 版本。 本文主要关注 DCN 可形变卷积的代码实现&#xff0c;不会过多的介绍其思想&#xff0c;如有兴趣&#xff0c;请参考论文原文&#xff1a; …

蓝牙耳机声音一顿一顿的_线控耳机党阵地转移成功,OPPO这款TWS耳机体验满分...

“你看到我手机里3.5mm的耳机孔了吗”&#xff0c;这可能是许多线控耳机党最想说的话了。确实&#xff0c;如今手机在做“减法”&#xff0c;而厂商们首先就拿3.5mm耳机孔“开刀”&#xff0c;我们也丧失了半夜边充电边戴耳机打游戏的乐趣。竟然如此&#xff0c;那如何在耳机、…

AI移动端优化之Im2Col+Pack+Sgemm

AI移动端优化之Im2ColPackSgemm 转自&#xff1a;https://blog.csdn.net/just_sort/article/details/108412760 这篇文章是基于NCNN的Sgemm卷积为大家介绍Im2ColPackSgemm的原理以及算法实现&#xff0c;希望对算法优化感兴趣或者做深度学习模型部署的读者带来帮助。 1. 前言 …

elementui的upload组件怎么获取上传的文本流、_抖音feed流直播间引流你还不会玩?实操讲解...

本文由艾奇在线明星优化师写作计划出品在这个全民惊恐多灾多难且带有魔幻的2020&#xff0c;一场突如其来的疫情改变了人们很多消费习惯&#xff0c;同时加速了直播电商的发展&#xff0c;现在直播已经成为商家必争的营销之地&#xff0c;直播虽然很火&#xff0c;但如果没有流…

FFmpeg 视频处理入门教程

FFmpeg 视频处理入门教程 转自&#xff1a;https://www.ruanyifeng.com/blog/2020/01/ffmpeg.html 作者&#xff1a; 阮一峰 日期&#xff1a; 2020年1月14日 FFmpeg 是视频处理最常用的开源软件。 它功能强大&#xff0c;用途广泛&#xff0c;大量用于视频网站和商业软件&…

checkbox wpf 改变框的大小_【论文阅读】倾斜目标范围框(标注)的终极方案

前言最常用的斜框标注方式是在正框的基础上加一个旋转角度θ&#xff0c;其代数表示为(x_c,y_c,w,h,θ)&#xff0c;其中(x_c,y_c )表示范围框中心点坐标&#xff0c;(w,h)表示范围框的宽和高[1,2,7]。对于该标注方式&#xff0c;如果将w和h的值互换&#xff0c;再将θ加上或者…

彻底理解BP之手写BP图像分类你也行

彻底理解BP之手写BP图像分类你也行 转自&#xff1a;https://zhuanlan.zhihu.com/p/397963213 第一节&#xff1a;用矩阵的视角&#xff0c;看懂BP的网络图 1.1、什么是BP反向传播算法 BP(Back Propagation)误差反向传播算法&#xff0c;使用反向传播算法的多层感知器又称为B…

梯度下降法和牛顿法计算开根号

梯度下降法和牛顿法计算开根号 本文将介绍如何不调包&#xff0c;只能使用加减乘除法实现对根号x的求解。主要介绍梯度下降和牛顿法者两种方法&#xff0c;并给出 C 实现。 梯度下降法 思路/步骤 转化问题&#xff0c;将 x\sqrt{x}x​ 的求解转化为最小化目标函数&#xff…

汇博工业机器人码垛机怎么写_全自动码垛机器人在企业生产中的地位越来越重要...

全自动码垛机器人在企业生产中的地位越来越重要在智能化的各种全自动生产线中&#xff0c;全自动码垛机器人成了全自动生产线的重要机械设备&#xff0c;在各种生产中发挥着不可忽视的作用。全自动码垛机器人主要用于生产线上的包装过程中&#xff0c;不仅能够提高企业的生产率…

小说中场景的功能_《流浪地球》:从小说到电影

2019年春节贺岁档冒出一匹黑马&#xff1a;国产科幻片《流浪地球》大年初一上映后口碑、票房双丰收&#xff1a;截至9日下午&#xff0c;票房已破15亿&#xff0c;并获得9.2的高评分。著名导演詹姆斯卡梅隆通过社交媒体对我国春节期间上映的科幻影片《流浪地球》发出的祝愿&…

线性回归与逻辑回归及其实现

线性回归与逻辑回归及其实现 回归与分类 预测值定性分析&#xff0c;即离散变量预测时&#xff0c;称之为分类&#xff1b;预测值定量分析&#xff0c;即连续变量预测时&#xff0c;称之为回归。 如预测一张图片是猫还是狗&#xff0c;是分类问题&#xff1b;预测明年的房价…

hbase 页面访问_HBase

HBase 特点 海量存储 Hbase 适合存储 PB 级别的海量数据&#xff0c;在 PB 级别的数据以及采用廉价 PC 存储的情况下&#xff0c;能在几十到百毫秒内返回数据。这与 Hbase 的极易扩展性息息相关。正式因为 Hbase 良好的扩展性&#xff0c;才为海量数据的存储提供了便利。 2&…

深入理解L1、L2正则化

深入理解L1、L2正则化 转自&#xff1a;【面试看这篇就够了】L1、L2正则化理解 一、概述 正则化&#xff08;Regularization&#xff09;是机器学习中一种常用的技术&#xff0c;其主要目的是控制模型复杂度&#xff0c;减小过拟合。正则化技术已经成为模型训练中的常用技术&a…

机器学习中的概率模型

机器学习中的概率模型 转自&#xff1a;https://zhuanlan.zhihu.com/p/164551678 机器学习中的概率模型 概率论&#xff0c;包括它的延伸-信息论&#xff0c;以及随机过程&#xff0c;在机器学习中有重要的作用。它们被广泛用于建立预测函数&#xff0c;目标函数&#xff0c;以…

max std value 宏_Rust Macro/宏 新手指南

Rust语言最强大的一个特点就是可以创建和利用宏/Macro。不过创建 Rust宏看起来挺复杂&#xff0c;常常令刚接触Rust的开发者心生畏惧。这片文章 的目的就是帮助你理解Rust Macro的基本运作原理&#xff0c;学习如何创建自己的 Rust宏。相关链接&#xff1a;在线学编程 - 汇智网…

农林资金 大数据审计案例_大数据审计:现状与发展

大数据审计&#xff1a;现状与发展【摘要】传统手工环境下&#xff0c;审计人员常用的审计方法包括检查法、观察法、重新计算法、外部调查法、分析法、鉴定法等。随着信息技术的发展&#xff0c;被审计单位的运行越来越依赖于信息化环境。信息化环境下审计工作发生了巨大的变化…

angularjs sill 创建项目_开源项目——博客项目MyBlogs.Core,基于.NET 5

个人博客站项目源码&#xff0c;高性能低占用的博客系统&#xff0c;这也许是我个人目前写过的性能最高的web项目了 。目前日均处理请求数80-120w次&#xff0c;同时在线活跃用户数30-100人&#xff0c;数据量累计已达到100多万条&#xff0c;数据库Redis网站主程序同时运行在一…

怀旧服推荐配置_【怀旧服】狂暴战P4毕业装备推荐

在怀旧服开启P4阶段之后&#xff0c;狂暴战玩家的输出也得到了进一步的提升。当然&#xff0c;狂暴战想要打出足够的伤害离不开对应的装备&#xff0c;现在就给大家介绍下狂暴战P4阶段的BIS装备。散件装备狂暴战在这一阶段依旧有非常不错的散件装备&#xff0c;个人建议玩家入手…

高斯混合模型GMM及EM迭代求解算法(含代码实现)

高斯混合模型GMM及EM迭代求解算法&#xff08;含代码实现&#xff09; 高斯分布与高斯混合模型 高斯分布 高斯分布大家都很熟悉了&#xff0c;下面是一元高斯分布的概率密度函数&#xff08;Probability Density Function&#xff0c;PDF&#xff09;&#xff1a; P(x)N(μ,…