OpenCV 之 神經網絡 (一)

  人工神經網絡(ANN) 簡稱神經網絡(NN),能模擬生物神經系統對物體所做出的交互反應,是由具備適應性簡單單元(稱爲神經元)組成的普遍並行互連網絡html

1  神經元

1.1  M-P 神經元

  以下圖所示,來自其它神經元的信號,$x_1, x_2, ... , x_n $,傳遞過來做爲輸入信號,並經過帶權重 ($w_1, w_2, ... , w_n$) 的鏈接 (connection) 繼續傳遞,網絡

  而後神經元的總輸入值 $\sum w_i x_i$ 與閾值 $\theta$ 做比較,最後通過激活函數$\,f\,$產生神經元的輸出: $y = f\left(\,\sum \limits_{i=1}^n {w_i x_i} - \theta \right)$機器學習

  

1.2  激活函數 (activation function)

  理想中,階躍函數可做爲激活函數,將輸入值映射爲輸出值 「0」 和 「1;實際中,經常使用 Sigmoid 函數做激活函數, $f(x)=\,\dfrac{1}{1+e^{-x}}$,以下圖所示:函數

 

  OpenCV 中使用的激活函數是另外一種形式,$f(x)=\beta \,\dfrac{1-e^{-\alpha x}}{1+e^{-\alpha x}}$post

  當 α = β = 1 時,$f(x)=\dfrac{1-e^{-x}}{1+e^{x}}$,該函數把可能在較大範圍內變化的輸入值,「擠壓」 到 (-1, 1) 的輸出範圍內學習

      

  具體的設置函數以下,param1 --> α,param2 --> βui

// 設置激活函數,目前只支持 ANN_MLP::SIGMOID_SYM
virtual void cv::ml::ANN_MLP::setActivationFunction(int type, double param1 = 0, double param2 = 0); 

 

2  神經網絡

2.1  感知機 (perceptron)

  感知機由兩層神經元組成,輸入層接收外界輸入信號,而輸出層則是一個 M-P 神經元。url

  實際上,感知機可視爲一個最簡單的「神經網絡」,用它可很容易的實現邏輯與、或、非等簡單運算。spa

   

2.2 層級結構

  常見的神經網絡,可分爲三層:輸入層、隱含層、輸出層。輸入層接收外界輸入,隱層和輸出層負責對信號進行加工,輸出層輸出最終的結果。.net

  如下圖爲例:每層神經元與下一層神經元全互連,而同層神經元之間不鏈接,也不存在跨層鏈接,這樣的結構稱爲「多層前饋神經網絡」(multi-layer feedforward neural networks)

   

2.3  層數設置

   OpenCV 中,設置神經網絡層數和神經元個數的函數爲 setLayerSizes(InputArray _layer_sizes),則上圖對應的 InputArray 可由以下代碼來構成

// (a) 3層,輸入層神經元個數爲 4,隱層的爲 6,輸出層的爲 4
Mat layers_size = (Mat_<int>(1,3) << 4,6,4);

// (b) 4層,輸入層神經元個數爲 4,第一個隱層的爲 6,第二個隱層的爲 5,輸出層的爲 4
Mat layers_size = (Mat_<int>(1,4) << 4,6,5,4);

   如何設置隱層神經元的個數還是個未決的問題,實際中多采用「試錯法」來調整

 

3  OpenCV 函數

1)  建立

static Ptr<ANN_MLP> cv::ml::ANN_MLP::create();  // 建立空模型

2) 設置參數

// 設置神經網絡的層數和神經元數量
virtual void cv::ml::ANN_MLP::setLayerSizes(InputArray _layer_sizes);

// 設置激活函數,目前只支持 ANN_MLP::SIGMOID_SYM
virtual void cv::ml::ANN_MLP::setActivationFunction(int type, double param1 = 0, double param2 = 0); 

// 設置訓練方法,默認爲 ANN_MLP::RPROP,較經常使用的是 ANN_MLP::BACKPROP
// 若設爲 ANN_MLP::BACKPROP,則 param1 對應 setBackpropWeightScale()中的參數,param2 對應 setBackpropMomentumScale() 中的參數
virtual void cv::ml::ANN_MLP::setTrainMethod(int method, double param1 = 0, double param2 = 0);
virtual void cv::ml::ANN_MLP::setBackpropWeightScale(double val); // 默認值爲 0.1
virtual void cv::ml::ANN_MLP::setBackpropMomentumScale(double val); // 默認值爲 0.1
 
// 設置迭代終止準則,默認爲 TermCriteria(TermCriteria::MAX_ITER + TermCriteria::EPS, 1000, 0.01)
virtual void cv::ml::ANN_MLP::setTermCriteria(TermCriteria val);

3)  訓練

// samples - 訓練樣本; layout - 訓練樣本爲 「行樣本」 ROW_SAMPLE 或 「列樣本」 COL_SAMPLE; response - 對應樣本數據的分類結果
virtual
bool cv::ml::StatModel::train(InputArray samples,int layout,InputArray responses);

4)  預測

// samples,輸入的樣本書數據;results,輸出矩陣,默認不輸出;flags,標識,默認爲 0
virtual
float cv::ml::StatModel::predict(InputArray samples, OutputArray results=noArray(),int flags=0) const;      

 

4 代碼示例

  下面是 OpenCV 3.3 中,在「支持向量機」的例程上作的修改,使用 BP 神經網絡,實現了和 SVM 相同的分類功能。

   OpenCV 中的 支持向量機 (Support Vector Machine),可參見另外一篇博文 OpenCV 之 支持向量機 (一)

 1 #include "opencv2/core/core.hpp"
 2 #include "opencv2/imgproc/imgproc.hpp"
 3 #include "opencv2/imgcodecs/imgcodecs.hpp"
 4 #include "opencv2/highgui/highgui.hpp"
 5 #include "opencv2/ml/ml.hpp"
 6 
 7 using namespace cv;
 8 
 9 int main()
10 {
11     // 512 x 512 零矩陣
12     int width = 512, height = 512;
13     Mat img = Mat::zeros(height, width, CV_8UC3);
14 
15     // 訓練樣本
16     float train_data[6][2] = { { 500, 60 },{ 245, 40 },{ 480, 250 },{ 160, 380 },{400, 25},{55, 400} };
17     float labels[6] = {0,0,0,1,0,1};  // 每一個樣本數據對應的輸出
18     Mat train_data_mat(6, 2, CV_32FC1, train_data);
19     Mat labels_mat(6, 1, CV_32FC1, labels);
20 
21     // BP 模型建立和參數設置
22     Ptr<ml::ANN_MLP> bp = ml::ANN_MLP::create();
23 
24     Mat layers_size = (Mat_<int>(1,3) << 2,6,1); // 2維點,1維輸出
25     bp->setLayerSizes(layers_size);
26 
27     bp->setTrainMethod(ml::ANN_MLP::BACKPROP,0.1,0.1);
28     bp->setActivationFunction(ml::ANN_MLP::SIGMOID_SYM);
29     bp->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER, 10000, /*FLT_EPSILON*/1e-6));
30 
31     // 保存訓練好的神經網絡參數
32     bool trained = bp->train(train_data_mat,ml::ROW_SAMPLE,labels_mat);
33     if (trained) {
34         bp->save("bp_param");
35     }
36 
37     // 建立訓練好的神經網絡
38 //    Ptr<ml::ANN_MLP> bp = ml::ANN_MLP::load("bp_param");
39 
40     // 顯示分類的結果
41     Vec3b green(0, 255, 0), blue(255, 0, 0);
42     for (auto i=0; i<img.rows; ++i) {
43         for (auto j=0; j<img.cols; ++j) {
44             Mat sample_mat = (Mat_<float>(1, 2) << j, i);
45             Mat response_mat;
46             bp->predict(sample_mat,response_mat);
47             float response = response_mat.ptr<float>(0)[0];
48             if (response > 0.5) {
49                 img.at<Vec3b>(i, j) = green;
50             } else if (response < 0.5) {
51                 img.at<Vec3b>(i, j) = blue;
52             }
53         }
54     }
55 
56     // 畫出訓練樣本數據
57     int thickness = -1;
58     int lineType = 8;
59     circle(img, Point(500, 60), 5, Scalar(255, 255, 255), thickness, lineType);
60     circle(img, Point(245, 40), 5, Scalar(255, 255, 255), thickness, lineType);
61     circle(img, Point(480, 250), 5, Scalar(255, 255, 255), thickness, lineType);
62     circle(img, Point(160, 380), 5, Scalar(0, 0, 255), thickness, lineType);
63     circle(img, Point(400, 25), 5, Scalar(255, 255, 255), thickness, lineType);
64     circle(img, Point(55, 400), 5, Scalar(0, 0, 255), thickness, lineType);
65 
66     imwrite("result.png", img);        // 保存訓練的結果
67     imshow("BP Simple Example", img);
68 
69     waitKey(0);
70 }

   運行結果以下所示:

   

注意:OpenCV 3.0 以上版本,相較以前的版本,其中有關機器學習的部分作了較大改動,本人也是踩了一些坑才獲得預期的效果。

 1)  代碼 #25,必須在 setActivationFunction() 以前,不然訓練後的結果多爲 nan

 2)  代碼 #46response_mat 爲預測的結果。若輸出向量爲 1 列,則如 #47 所示,可直接取出預測結果;若輸出向量爲 n 列,則可取平均值或者最大值。

      同時,根據平均值或最大值,代碼 #48 處的閾值也要相應的改變。

    float response = 0;
    for (auto i=0;i<n;++i) {
          response += response_mat.ptr<float>(0)[i];
    }

 3)  代碼 #39,若已經訓練好神經網絡的參數,並將其保存到文件 bp_param 中。

      則可將 #22 ~ #35 所有註釋掉,再反註釋掉 #38,這樣,直接加載訓練好的神經網絡,即可以使用了。

 

參考資料

  <機器學習> 周志華  第5章

  <統計學習方法> 李航  第1章

  OpenCV 3.0  Tutorials  -- Neural Networks

  OpenCV進階之路:神經網絡識別車牌字符       ☆Ronny丶

 【模式識別】OpenCV中使用神經網絡 CvANN_MLP       xiaowei_cqu

相關文章
相關標籤/搜索