1. 程式人生 > >卷積神經網路中卷積的OpenCL實現

卷積神經網路中卷積的OpenCL實現

卷積神經網路中卷積的OpenCL實現

 ==============================================================

目錄

1、卷積

4、總結

 ==============================================================

本文主要介紹深度學習中卷積,以及卷積核的OpenCL實現。

另外:新版對齊方式都沒了,莫名其妙。

1、卷積

在CNN(Convolutional Neural Network, 卷積神經網路)中,卷積是個必不可少的部件,該網路也因卷積得名。CNN的卷積層中,有許多濾波器,這些濾波器也稱為卷積核,用於卷積運算,提取資料特徵,這些濾波器的係數由訓練得到。

在數字訊號處理中,訊號x(n)經過系統,相當於訊號與系統的衝激響應函式h(n)進行卷積,得到輸出y(n),其定義如下式。

上式中的符號“*”是卷積的意思。

可以看出,訊號x(n)經過系統,與衝擊響應函式序列經過縱軸翻折過的序列對應相乘。

而在卷積神經網路中卷積操作的原理即卷積核與對應的點對應相乘,核心即是乘累加,

卷積的方式比較多,假定濾波器的滑動步長stride(用s表示),以及濾波器的填充方式(填充長度用p表示),原始特徵圖W*H(寬W,高H),濾波器的尺寸用K*K表示,則輸出特徵圖的尺寸為

上式中括號為下取整。

這個關係暫時沒想通也沒關係,可以搜尋卷積神經網路卷積瞭解一下,卷積的核心即乘累加,如下為卷積圖解。

圖1. 卷積示例

上圖中左側為特徵圖與卷積核卷積,右側為輸出,其中卷積的步長stride為1,濾波器滑動方向先進行行處理,再進行列處理。

如右側的最左上角的數 3= 2*1 + 3*(-1) + 4 + 6*0;

隨後濾波器向右滑動1個單位,此時濾波器對應的資料為[3,7,6,3],所以3*1 + 7*(-1) + 6*1 +3*0 = 2,其他同理。

行處理完成,濾波器向下移動一個單位,接著處理下一行,此時與之對應的數為[4,6,12,0],所以4*1 + 6*(-1) + 12*1 + 0*0 = 10。其他同理。

圖2. 特徵圖填充,卷積示例

圖2中的卷積與圖1不同在於,是否對原始特徵圖進行填充,填充可以保留特徵圖的邊緣資訊,不至於在卷積過程中丟失邊緣資訊。以上是其中一種填充方式,在特徵圖的周圍環繞填充0,本例中忽略頂部及左側的0值,保留右側以及底層的邊緣資訊,使輸出特徵圖大小與原始的特徵圖大小相等。

卷積以及更多填充方式的詳細介紹可以參看如下連結:

Convolution arithmetic tutorial:

A guide to convolution arithmetic for deep learning:

2、卷積與影象處理

瞭解了卷積之後,如何在OpenCL中實現它呢?首先,一個單程序程式,使用一個卷積核對一張特徵圖進行處理,與多個並行程序,使用共享的卷積核對一張特徵圖進行處理相對比,顯然後者計算速度快些。這就是加速,正是時代潮流上的加速。

假設有一個已經訓練好的CNN網路用於識別著名的Lena,原始圖片如下,寬高分別為W和H:

圖 3. 名模Lena

卷積核如下,寬高均為K:

圖 4. K*K卷積核

    現對圖片進行周圍零填充,保持經過卷積後的輸出影象與原始影象大小一致,假設保留右側和底側邊緣資訊,只對這兩側進行填充。(為什麼保留右側及底側,其實如果你保留頂部和左側邊緣,又想輸出影象大小一致,可能右側和底側的邊緣資訊也保留不了,在這我單純只是為了好運算)。

圖 5. 填充後的圖大小(W+K-1)*(W+K-1)

如果使用多個程序處理卷積操作,每個程序輸入對應的濾波器係數和影象資料,對於每個程序,濾波器係數一致,可以共享;資料來自影象的不同位置,資料塊大小為K*K。在深度學習中,訓練完成的網路抽象了資料特徵,得到不同特徵的卷積核(濾波器),所以為了直觀,本文將使用Sobel運算元作為卷積核,K=3,可以用於影象邊緣檢測,生成邊緣特徵圖。

Sobel運算元的原理參考:

圖 6. 水平梯度和垂直梯度卷積因子

3、卷積的OpenCL實現

Sobel運算元與影象卷積的Matlab程式,我已放入Github中,如下:

該程式碼與OpenCL中需要實現的卷積邏輯一致:

(1)影象資料與卷積核在儲存器中是連續的,一維陣列;

(2)輸出特徵圖也是連續的一維陣列。

圖 7. Matlab輸出水平梯度特徵圖

圖 8. Matlab輸出垂直梯度特徵圖

圖 9. Matlab輸出影象卷積圖

在OpenCL中將使用W*H個工作項來完成卷積操作,工作項ID為(x, y),x和y取值分別為[0, W-1]和[0, H-1]。

濾波器的座標值為(kj, ki),kj和ki取值範圍均為[0, 1, 2]。

座標為(kj, ki)卷積核對應的資料座標示意圖如下:

圖 10. 濾波器座標與影象資料座標

所以,濾波器座標(kj, ki)對應的儲存索引值為[kj + K*ki];

影象資料對應的儲存索引值為[( y + ki ) * Wn + x + kj],其中Wn=W+K-1;因為Matlab的首個數據索引為1,但在C語言中首個索引值為0,所以該處與上文Matlab程式碼中索引值略微不同。

以下為OpenCL的核函式Conv2D.cl:

/**********************************************
function: 2D Convolution of CNN
date    : 2018/07/21
**********************************************/

__kernel void Conv2D( __global int * image_in,  //image input
                                     __global int * filter_in, //filter input
                                              int K,            //filter kernel size
                                     __global int * image_out) //feature map output
{

       int W;       //work group global size
       int Wn;      //padded image width
       int x;       //global id x
       int y;       //global id y
       int ki, kj;  //filter coordinate,(kj, ki)

       int sum = 0; //multiply and sum of filter and data
       W = get_global_size(0);
       x = get_global_id(0);
       y = get_global_id(1);
       Wn = W + (K - 1);
      
       for(ki=0; ki<K; ki++)
              for(kj=0; kj<K; kj++)
                     {
                            sum  = sum + filter_in[ki*K + kj] * image_in[Wn*(y+ki) + x + kj];
                     }

       image_out[y*W + x] = sum;
}

OpenCL主函式main.cpp:

圖 11. 隨機數Sobel水平梯度卷積的結果顯示

將輸出影象匯入到Matlab中顯示即可作為驗證,本程式碼中沒有讀取和生成圖片功能,鑑於圖片太大,存入記憶體太大,且只進行了水平梯度特徵圖對隨機數的濾波,但已足以瞭解卷積的並行操作。如需處理檔案,可將圖片資料匯入,輸出檔案已存於程式當前執行目錄的image_out.txt中。

4、總結

本文介紹了卷積,卷積與影象處理,使用Sobel運算元展示lena的水平梯度與垂直梯度的特徵圖,並通過OpenCL實現了卷積核,展示了使用Sobel水平梯度卷積核對隨機數的卷積操作結果。

如有不當,請您斧正,謝謝。

途次客

2018年7月21日