1. 程式人生 > >深度學習Caffe實戰筆記(5)Windows caffe平臺跑Siamese mnist資料集

深度學習Caffe實戰筆記(5)Windows caffe平臺跑Siamese mnist資料集

前幾篇部落格介紹了環境搭建,caffe跑lenet,alexnet,cifar10,基礎的一些操作都介紹的很詳細了。這篇部落格介紹如何使用Siamese網路跑mnist資料集,下一篇介紹如何用Siamese網路跑自己的資料集。說到Siamese網路,這次不哭了,因為幾篇部落格把該哭的都哭完了。
網上的資料都是基於Ubuntu系統的,介紹Windows平臺下Siamese網路幾乎沒有,所以儘管博主查閱了各種論壇、社群,在各種深度學習相關的群裡求助,沒有人理我,(當然,也可能是鑑於博主學術水平太低,沒人理),沒辦法,只能自己從頭開始研究了,慢慢的也就把這個問題搞定了,我願意把我學習到的這些東西分享給大家。
有的人覺得自己辛苦得來的東西,害怕別人知道了,不願意告訴別人怎麼做的,其實這樣的人格局實在太小,殊不知你告訴別人的只不過是一個結果,在你探索過程中得到的分析能力,思維方式,你的知識結構別人是拿不去的!你在乎的,往往能反映出你的水準,為什麼層次越高的人,反而計較的越少呢?不是說他有多麼寬容,而是有些事根本入不了他的眼。願不願意分享,就能看出一個人的眼界和格局,而眼界和格局往往才是決定一個人盛衰成敗的關鍵!共勉。。。。。。
又來了,又來了,博主真矯情,算了,我們開始train。
mnist資料集和Siamese網路不做介紹了吧,如果不知道的話可以Google一下。。。。。。

1、準備資料
從Yann LeCun老先生的主頁上可以下載mnist資料集http://yann.lecun.com/exdb/mnist/解壓完如下:
這裡寫圖片描述
四個檔案分別代表測試資料,測試資料標籤,訓練資料,訓練資料標籤。

2、轉換資料
這次轉換資料和Alexnet的轉換資料方式可不一樣,同樣的方法,在caffe-windows-master\build_cpu_only資料夾下有一個convert_mnist_data檔案,把這個檔案複製,重新命名為convert_mnist_siamese_data,把裡面的release資料夾刪除,把剩下的三個檔案也重新命名為convert_mnist_siamese_data。這是本博主的高明之處,原因在於這樣避免了各種配置環境和找不到各種檔案的問題。然後用vs開啟caffe-windows-master\build_cpu_only\MainBuilder.sln,通過右鍵新增工程的方式把剛才複製的工程新增進來,這個時候新增進來的工程還沒有改名字,把工程名字改成convert_mnist_siamese_data。
新增專案

然後開啟convert_mnist_siamese_data,把裡面原有的cpp檔案移除,把caffe-windows-master\examples\siamese\convert_mnist_siamese_data.cpp檔案新增進來:
這裡寫圖片描述
剩下的步驟就是生成了。。。。
成功生成之後,在caffe-windows-master\examples\mnist\下會有convert_mnist_siamese_data.exe檔案,這個檔案就是我們需要的檔案。
在data資料夾下新建一個mnist_new資料夾,把下載好的資料檔案和convert_mnist_siamese_data.exe檔案都複製過來,寫資料轉換指令碼檔案:
這裡寫圖片描述

請注意:這裡只寫了test資料的指令碼檔案,train資料的指令碼檔案類似,只需要把相應的檔名替換一下即可。然後會生成兩個資料夾,分別是Siamese網路需要的train資料和test資料。
這裡寫圖片描述

這裡寫圖片描述

截止目前,資料準備已經完成。。。。。

3、開始訓練
在caffe-windows-master\examples\siamese\資料夾下有mnist_siamese_solver.prototxt和mnist_siamese_train_test.prototxt檔案,一個是Siamese網路需要的超參檔案,具體引數含義在前面的部落格中我已經做了大量介紹了,在這裡不囉嗦了,一個是Siamese網路結構協議。仔細分析一下Siamese網路,不難發現,其實就是兩個LeNet網路。
需要修改網路協議中的哪些地方我也不做介紹了,前面的部落格中都做了說明了。
寫開始訓練的指令碼檔案:
這裡寫圖片描述

雙擊開始訓練。。。。以為大工告成了?錯!

4、關於損失函式
執行上面的指令碼檔案,發現:
這裡寫圖片描述

發現ContrastiveLoss損失需要四個輸入,但是所有和Siamese網路相關的資料中都是三個輸入的,一個輸入對,在加上這個輸入對是否匹配。難道是協議檔案錯了?就在這個地方,博主一個人思考人生思考了好長時間,以致於開始懷疑人生,在各種社群、論壇、深度學習群裡都問了,可能鑑於博主學術水平太低,沒人理,等開啟ContrastiveLoss損失函式的程式碼,研究了半天,終於:

template <typename Dtype>
    void ContrastiveLossLayer<Dtype>::LayerSetUp(
        const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) {
        LossLayer<Dtype>::LayerSetUp(bottom, top);
        CHECK_EQ(bottom[0]->channels(), bottom[1]->channels());
        CHECK_EQ(bottom[0]->height(), 1);
        CHECK_EQ(bottom[0]->width(), 1);
        CHECK_EQ(bottom[1]->height(), 1);
        CHECK_EQ(bottom[1]->width(), 1);
        CHECK_EQ(bottom[2]->channels(), 1);
        CHECK_EQ(bottom[2]->height(), 1);         //第三個引數和第四個引數表示兩幅影象的標籤
        CHECK_EQ(bottom[2]->width(), 1);
        CHECK_EQ(bottom[3]->channels(), 1);
        CHECK_EQ(bottom[3]->height(), 1);
        CHECK_EQ(bottom[3]->width(), 1);
        ....
        for (int i = 0; i < bottom[0]->num(); ++i) {
            dist_sq_.mutable_cpu_data()[i] = caffe_cpu_dot(channels,
                diff_.cpu_data() + (i*channels), diff_.cpu_data() + (i*channels));
            if (static_cast<int>(bottom[2]->cpu_data()[i]) == static_cast<int>(bottom[3]->cpu_data()[i])) {  // similar pairs
                loss += dist_sq_.cpu_data()[i];
            }
            else {  // dissimilar pairs
                loss += std::max(margin - dist_sq_.cpu_data()[i], Dtype(0.0));
            }
        }

在這個損失函式的原始碼中,發現了端倪。改進的ContrastiveLoss就是四個引數,分別是兩個輸入資料,和兩個輸入資料對應的標籤,通過判斷兩個標籤是否一致,來做損失計算。這下恍然大悟,所以在網路結構的協議損失層,又添加了一個標籤。搞定!
這裡寫圖片描述
在協議中,會打印出來幾個類似於這樣的資料,分析了網路協議,發現兩個分支層是引數共享的,用了同一個名字,這個地方的含義就是告訴我們,feat_w和feat_b引數共享。

這裡寫圖片描述

開始訓練,有意思吧。。。。。。。