【詳細圖解】再次理解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.pswp.cn/news/532450.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/532450.shtml
英文地址,請注明出處:http://en.pswp.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…

h5頁面禁止復制_H5移動端頁面禁止復制技巧

前言&#xff1a;業務需要&#xff0c;需要對整個頁面禁止彈出復制菜單。在禁止的頁面中加入以下css樣式定義* {-webkit-touch-callout:none;/*系統默認菜單被禁用*/-webkit-user-select:none;/*webkit瀏覽器*/-khtml-user-select:none;/*早起瀏覽器*/-moz-user-select:none;/*…

梯度下降法和牛頓法計算開根號

梯度下降法和牛頓法計算開根號 本文將介紹如何不調包&#xff0c;只能使用加減乘除法實現對根號x的求解。主要介紹梯度下降和牛頓法者兩種方法&#xff0c;并給出 C 實現。 梯度下降法 思路/步驟 轉化問題&#xff0c;將 x\sqrt{x}x? 的求解轉化為最小化目標函數&#xff…

匯博工業機器人碼垛機怎么寫_全自動碼垛機器人在企業生產中的地位越來越重要...

全自動碼垛機器人在企業生產中的地位越來越重要在智能化的各種全自動生產線中&#xff0c;全自動碼垛機器人成了全自動生產線的重要機械設備&#xff0c;在各種生產中發揮著不可忽視的作用。全自動碼垛機器人主要用于生產線上的包裝過程中&#xff0c;不僅能夠提高企業的生產率…

kmeans手寫實現與sklearn接口

kmeans手寫實現與sklearn接口 kmeans簡介 K 均值聚類是最基礎的一種聚類方法。它是一種迭代求解的聚類分析算法。 kmeans的迭代步驟 給各個簇中心 μ1,…,μc\mu_1,\dots,\mu_cμ1?,…,μc? 以適當的初值&#xff1b; 更新樣本 x1,…,xnx_1,\dots,x_nx1?,…,xn? 對應的…

小說中場景的功能_《流浪地球》:從小說到電影

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…

rk3128屏幕占空比參數設置_瑞芯微RK3128芯片怎么樣 性能全面解讀

最近&#xff0c;筆者聽說一款搭載瑞芯微RK3128芯片方案的盒子問市了&#xff0c;打聽了一下才知道還真有其事&#xff0c;這款上市的RK3128盒子叫做開博爾M1&#xff0c;報價229元&#xff0c;這個價位在如今的四核網絡機頂盒市場可謂是不多見&#xff0c;但是這款芯片的性能怎…

機器學習中的概率模型

機器學習中的概率模型 轉自&#xff1a;https://zhuanlan.zhihu.com/p/164551678 機器學習中的概率模型 概率論&#xff0c;包括它的延伸-信息論&#xff0c;以及隨機過程&#xff0c;在機器學習中有重要的作用。它們被廣泛用于建立預測函數&#xff0c;目標函數&#xff0c;以…

訪問云服務器儲存的mp4_訪問云服務器儲存的mp4

{"moduleinfo":{"card_count":[{"count_phone":1,"count":1}],"search_count":[{"count_phone":6,"count":6}]},"card":[{"des":"云服務器 ECS(Elastic Compute Service)是一…

先驗、后驗、似然

先驗、后驗、似然 先驗分布、后驗分布和似然函數 本節轉自&#xff1a;先驗分布、后驗分布、似然估計這幾個概念是什么意思&#xff0c;它們之間的關系是什么&#xff1f; 通俗解釋 先驗分布&#xff1a;根據一般的經驗認為隨機變量應該滿足的分布。先驗分布是你瞎猜參數服從啥…