机器学习入门(17)— 输入 4 维数据、基于 im2col 展开来实现卷积层
1. 輸入 4 維數(shù)據(jù)
CNN 中各層間傳遞的數(shù)據(jù)是 4 維數(shù)據(jù)。所謂 4 維數(shù)據(jù),比如數(shù)據(jù)的形狀是(10, 1, 28, 28),則它對(duì)應(yīng) 10 個(gè)高為 28、長(zhǎng)為 28、通道為 1 的數(shù)據(jù)。用 Python 實(shí)現(xiàn)如下:
In [2]: a = np.random.rand(3, 1, 4, 4)In [4]: a.shape
Out[4]: (3, 1, 4, 4)In [5]: 
如果要訪問第 1 個(gè)數(shù)據(jù)的第 1 個(gè)通道的空間數(shù)據(jù),可以寫成下面這樣。
In [5]: a[0][0]
或者
In [6]: a[0, 0]
2. 基于im2col 的展開
im2col 是一個(gè)函數(shù),將輸入數(shù)據(jù)展開以適合濾波器(權(quán)重)。如圖7-17 所示,對(duì) 3 維的輸入數(shù)據(jù)應(yīng)用 im2col 后,數(shù)據(jù)轉(zhuǎn)換為 2 維矩陣(正確地講,是把包含批數(shù)量的 4 維數(shù)據(jù)轉(zhuǎn)換成了2 維數(shù)據(jù))。
 
 具體地說,如圖7-18 所示,對(duì)于輸入數(shù)據(jù),將應(yīng)用濾波器的區(qū)域(3 維方塊)橫向展開為 1 列。im2col 會(huì)
 在所有應(yīng)用濾波器的地方進(jìn)行這個(gè)展開處理。
 
 在圖7-18 中,為了便于觀察,將步幅設(shè)置得很大,以使濾波器的應(yīng)用區(qū)域不重疊。而在實(shí)際的卷積運(yùn)算中,濾波器的應(yīng)用區(qū)域幾乎都是重疊的。
在濾波器的應(yīng)用區(qū)域重疊的情況下,使用 im2col 展開后,展開后的元素個(gè)數(shù)會(huì)多于原方塊的元素個(gè)數(shù)。因此,使用 im2col 的實(shí)現(xiàn)存在比普通的實(shí)現(xiàn)消耗更多內(nèi)存的缺點(diǎn)。
但是,匯總成一個(gè)大的矩陣進(jìn)行計(jì)算,對(duì)計(jì)算機(jī)的計(jì)算頗有益處。比如,在矩陣計(jì)算的庫(kù)(線性代數(shù)庫(kù))等中,矩陣計(jì)算的實(shí)現(xiàn)已被高度最優(yōu)化,可以高速地進(jìn)行大矩陣的乘法運(yùn)算。因此,通過歸結(jié)到矩陣計(jì)算
 上,可以有效地利用線性代數(shù)庫(kù)。
im2col 這個(gè)名稱是 image to column 的縮寫,翻譯過來就是“從圖像到矩陣”的意思。Caffe 、Chainer 等深度學(xué)習(xí)框架中有名為 im2col 的函數(shù),并且在卷積層的實(shí)現(xiàn)中,都使用了 im2col 。
使用 im2col 展開輸入數(shù)據(jù)后,之后就只需將卷積層的濾波器(權(quán)重)縱向展開為1 列,并計(jì)算 2 個(gè)矩陣的乘積即可(參照?qǐng)D7-19)。這和全連接層的 Affine 層進(jìn)行的處理基本相同。
如圖7-19 所示,基于 im2col 方式的輸出結(jié)果是 2 維矩陣。因?yàn)?CNN 中數(shù)據(jù)會(huì)保存為 4 維數(shù)組,所以要將 2 維輸出數(shù)據(jù)轉(zhuǎn)換為合適的形狀。以上就是卷積層的實(shí)現(xiàn)流程。
 
 im2col 函數(shù)代碼實(shí)現(xiàn)如下:
def im2col(input_data, filter_h, filter_w, stride=1, pad=0):"""Parameters----------input_data : 由(數(shù)據(jù)量, 通道, 高, 長(zhǎng))的4維數(shù)組構(gòu)成的輸入數(shù)據(jù)filter_h : 濾波器的高filter_w : 濾波器的寬stride : 步幅pad : 填充Returns-------col : 2維數(shù)組"""N, C, H, W = input_data.shapeout_h = (H + 2*pad - filter_h)//stride + 1out_w = (W + 2*pad - filter_w)//stride + 1img = np.pad(input_data, [(0,0), (0,0), (pad, pad), (pad, pad)], 'constant')col = np.zeros((N, C, filter_h, filter_w, out_h, out_w))for y in range(filter_h):y_max = y + stride*out_hfor x in range(filter_w):x_max = x + stride*out_wcol[:, :, y, x, :, :] = img[:, :, y:y_max:stride, x:x_max:stride]col = col.transpose(0, 4, 5, 1, 2, 3).reshape(N*out_h*out_w, -1)return col
應(yīng)用示例:
In [8]: x1 = np.random.rand(1, 3, 7, 7)In [9]: col1 = im2col(x1, 5, 5, stride=1, pad=0)In [10]: col1.shape
Out[10]: (9, 75)In [14]: x2 = np.random.rand(10, 3, 7, 7)In [15]: col2 = im2col(x2, 5, 5, stride=1, pad=0)In [16]: col2.shape
Out[16]: (90, 75)In [17]:
第一個(gè)是批大小為1、通道為3 的7 × 7 的數(shù)據(jù),第二個(gè)的批大小為10,數(shù)據(jù)形狀和第一個(gè)相同。
分別對(duì)其應(yīng)用 im2col 函數(shù),在這兩種情形下,第 2 維的元素個(gè)數(shù)均為 75。這是濾波器(通道為 3、大小為
 5 × 5)的元素個(gè)數(shù)的總和。批大小為1 時(shí),im2col 的結(jié)果是(9, 75)。而第 2個(gè)例子中批大小為10,所以保存了10 倍的數(shù)據(jù),即(90, 75)。
3. 卷積層實(shí)現(xiàn)
卷積層的初始化方法將濾波器(權(quán)重)、偏置、步幅、填充作為參數(shù)接收。濾波器是(FN , C , FH , FW ) 的 4 維形狀。另外,FN 、C 、FH 、FW 分別是 FilterNumber (濾波器數(shù)量)、Channel 、Filter Height 、Filter Width 的縮寫。
class Convolution:def __init__(self, W, b, stride=1, pad=0):self.W = Wself.b = bself.stride = strideself.pad = paddef forward(self, x):FN, C, FH, FW = self.W.shapeN, C, H, W = x.shapeout_h = int(1 + (H + 2*self.pad - FH) / self.stride)out_w = int(1 + (W + 2*self.pad - FW) / self.stride)col = im2col(x, FH, FW, self.stride, self.pad)col_W = self.W.reshape(FN, -1).T # 濾波器的展開out = np.dot(col, col_W) + self.bout = out.reshape(N, out_h, out_w, -1).transpose(0, 3, 1, 2)return out
其中:
        col = im2col(x, FH, FW, self.stride, self.pad)col_W = self.W.reshape(FN, -1).T # 濾波器的展開out = np.dot(col, col_W) + self.b
是用 im2col 展開輸入數(shù)據(jù),并用 reshape 將濾波器展開為 2 維數(shù)組。然后,計(jì)算展開后的矩陣的乘積。
將各個(gè)濾波器的方塊縱向展開為 1 列。這里通過 reshape(FN,-1) 將參數(shù)指定為 -1,這是 reshape 的一個(gè)便利的功能。通過在 reshape 時(shí)指定為 -1,reshape 函數(shù)會(huì)自動(dòng)計(jì)算 -1 維度上的元素個(gè)數(shù),以使多維數(shù)組的元素個(gè)數(shù)前后一致。比如,(10, 3, 5, 5) 形狀的數(shù)組的元素個(gè)數(shù)共有 750 個(gè),指定 reshape(10,-1) 后,就會(huì)轉(zhuǎn)換成(10, 75) 形狀的數(shù)組。
forward 的實(shí)現(xiàn)中,最后會(huì)將輸出大小轉(zhuǎn)換為合適的形狀。轉(zhuǎn)換時(shí)使用了 NumPy 的 transpose 函數(shù)。transpose 會(huì)更改多維數(shù)組的軸的順序。如圖 7-20 所示,通過指定從 0 開始的索引(編號(hào))序列,就可以更改軸的順序。
 以上就是卷積層的 forward 處理的實(shí)現(xiàn)。通過使用 im2col 進(jìn)行展開,接下來是卷積層的反向傳播的實(shí)現(xiàn),因?yàn)楹?Affine 層的實(shí)現(xiàn)有很多共通的地方,所以就不再介紹了。但有一點(diǎn)需要注意,在進(jìn)行卷積層的反向傳播時(shí),必須進(jìn)行 im2col 的逆處理。col2im 代碼如下:
def col2im(col, input_shape, filter_h, filter_w, stride=1, pad=0):"""Parameters----------col :input_shape : 輸入數(shù)據(jù)的形狀(例:(10, 1, 28, 28))filter_h :filter_wstridepadReturns-------"""N, C, H, W = input_shapeout_h = (H + 2*pad - filter_h)//stride + 1out_w = (W + 2*pad - filter_w)//stride + 1col = col.reshape(N, out_h, out_w, C, filter_h, filter_w).transpose(0, 3, 4, 5, 1, 2)img = np.zeros((N, C, H + 2*pad + stride - 1, W + 2*pad + stride - 1))for y in range(filter_h):y_max = y + stride*out_hfor x in range(filter_w):x_max = x + stride*out_wimg[:, :, y:y_max:stride, x:x_max:stride] += col[:, :, y, x, :, :]return img[:, :, pad:H + pad, pad:W + pad]
除了使用 col2im 這一點(diǎn),卷積層的反向傳播和 Affine 層的實(shí)現(xiàn)方式都一樣。卷積層反向傳播代碼如下所示:
class Convolution:def __init__(self, W, b, stride=1, pad=0):self.W = Wself.b = bself.stride = strideself.pad = pad# 中間數(shù)據(jù)(backward時(shí)使用)self.x = None   self.col = Noneself.col_W = None# 權(quán)重和偏置參數(shù)的梯度self.dW = Noneself.db = Nonedef forward(self, x):FN, C, FH, FW = self.W.shapeN, C, H, W = x.shapeout_h = 1 + int((H + 2*self.pad - FH) / self.stride)out_w = 1 + int((W + 2*self.pad - FW) / self.stride)col = im2col(x, FH, FW, self.stride, self.pad)col_W = self.W.reshape(FN, -1).Tout = np.dot(col, col_W) + self.bout = out.reshape(N, out_h, out_w, -1).transpose(0, 3, 1, 2)self.x = xself.col = colself.col_W = col_Wreturn outdef backward(self, dout):FN, C, FH, FW = self.W.shapedout = dout.transpose(0,2,3,1).reshape(-1, FN)self.db = np.sum(dout, axis=0)self.dW = np.dot(self.col.T, dout)self.dW = self.dW.transpose(1, 0).reshape(FN, C, FH, FW)dcol = np.dot(dout, self.col_W.T)dx = col2im(dcol, self.x.shape, FH, FW, self.stride, self.pad)return dx
總結(jié)
以上是生活随笔為你收集整理的机器学习入门(17)— 输入 4 维数据、基于 im2col 展开来实现卷积层的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 修复处女膜多少钱啊?
- 下一篇: 机器学习入门(18)— 卷积网络中的池化
