1. 程式人生 > >神經網路卷積層的實現原理與視覺化其過程 (caffe為例)

神經網路卷積層的實現原理與視覺化其過程 (caffe為例)

caffe中卷積層的實現

1 caffe卷積前向傳播

caffe前向傳播涉及到的類主要如下:
conv_class

首先卷積層conv_layer.cpp中的Fprward進行前向傳播,呼叫父類base_conv_layer.cpp中的forward進行前向傳播,該函式呼叫conv_layer.cpp中的conv_im2col計算輸入矩陣轉換後的矩陣,然後通過權重矩陣與轉換後的矩陣相乘得到卷積計算。其示意圖如下:
conv_process

卷積前向傳播中最為主要的就是輸入矩陣的轉換,其主要程式碼如下(cafffe原始碼):

//計算輸出矩陣的高 (dilation為卷積中膨脹係數)
const int output_h = (height + 2
* pad_h - (dilation_h * (kernel_h - 1) + 1)) / stride_h + 1; //計算輸出矩陣的寬 const int output_w = (width + 2 * pad_w - (dilation_w * (kernel_w - 1) + 1)) / stride_w + 1; //計算每個通道的大小(N維矩陣都儲存為1維陣列的形式) const int channel_size = height * width; //處理每個通道 for (int channel = channels; channel--; data_im += channel_size) { //處理核區域中的每個元素
for (int kernel_row = 0; kernel_row < kernel_h; kernel_row++) { for (int kernel_col = 0; kernel_col < kernel_w; kernel_col++) { //選取核大小區域的行的初始位置 (如果有pad,則為負,沒有在原始陣列中補充0) int input_row = -pad_h + kernel_row * dilation_h; //處理輸出的每一行 for (int output_rows = output_h; output_rows; output_rows--) { //如果選取在pad行,則都補充0
if (!is_a_ge_zero_and_a_lt_b(input_row, height)) { for (int output_cols = output_w; output_cols; output_cols--) { *(data_col++) = 0; } } else { //選取核大小區域的列的初始位置 int input_col = -pad_w + kernel_col * dilation_w; //處理輸出的每一列 for (int output_col = output_w; output_col; output_col--) { //如果選取的在pad列,則補充0,否則將原矩陣位置輸出 if (is_a_ge_zero_and_a_lt_b(input_col, width)) { *(data_col++) = data_im[input_row * width + input_col]; } else { *(data_col++) = 0; } //由於矩陣儲存以1維矩陣,則卷積視窗的滑動直接向後移動 input_col += stride_w; } } input_row += stride_h; } } } }

轉換是把原始輸入矩陣的的第一個卷積和大小的區域拉成一個列向量,然後卷積核區域向後滑動一步,再拉成一個列向量,所有列向量組成一個轉換後的矩陣,如果多個通道,每個通道計算的矩陣向下拼接 (就如上面示意圖所示)。由於caffe中是行優先,則每次需要先對卷積區域的第一個元素處理,滑動完所有視窗後對第二個元素處理,這樣就可以一行一行的生成轉換後的輸出矩陣了。

其轉換過程視覺化如下節所示(FLTK+opengl實現,除錯了蠻久的,以為是opengl宣傳除了bug,最後原來是轉換計算時時指標出了問題,完整的demo程式見github)。

卷積中膨脹係數,就是空洞卷積(dilated convolution)的實現,在卷積和中插入0。如在ENet網路中,定義dilated convolution操作為:
dilated

2 caffe卷積前向傳播動畫演示

conv_demo

通過最上面的卷積實現示意圖可知,卷積的實現是權重矩陣和輸入轉換的矩陣做矩陣乘法。權重矩陣的大小定義為(out_channels x in_channels/groups x kH x kW),根據上圖和矩陣乘法示意圖可知,將卷積核與輸入的所有通道做卷積計算,所有通道的和作為輸出的第一個通道,然後將不同權重卷積核與輸入的所有通道做卷積計算,得到第二個輸出通道。

3 caffe卷積反向傳播

網路反向傳播需要需要跟新兩項:*weightsdeltas,其公式推到見之前部落格Neural Network and deep learning

網路的forward過程是使用權重更新每層的feature,而backward則是使用deltas跟新weights。因此在pyTorch框架中網路層和feature中都有grad,網路層的grad用來跟新權重,feature中的grad則用來傳遞deltas。

4 根據可變卷積實現caffe自定義卷積層

5 Convolution Operator and Correlation Operator

Convolution Operator是卷機操作,需要將卷機核翻轉180度然後滑動視窗做卷機操作,如果進行翻轉,則為Correlation Operator操作,如果卷機核是對稱的,則兩種操作等價。

卷機的其中一方參與這是衝擊的影響,即當前時間之前造成的影響,從而卷機的輸出等於以前的訊號效果累加,這個累加必須從當前時間的逆時間流逝的方向進行。因此需要對卷機核翻轉。

deep learning中的卷機並不是嚴格意義上的卷機,所以沒有翻轉