接觸caffe時日不多,基本上把官網上的example玩了一遍,只是走馬觀花的過一遍。
昨天晚上想在自己的數據集上做分類。於是就開始了下面的一系列事情。
1、挑選適合自己任務的modal
caffe zoo中有很多已經訓練好的modal,那麼根據自己的任務需求找到適合自己的modal,由於我現在想做的是classification的事情,所以我就從http://dl.caffe.berkeleyvision.org/bvlc_reference_caffenet.caffemodeldownload了bvlc_reference_caffenet。下載後的modal放到caffe根目錄下的 models/bvlc_reference_caffenet/ 文件夾下面,如果是安裝官網給的方法下載的話,
# sudo ./scripts/download_model_binary.py models/bvlc_reference_caffenet
# sudo sh ./data/ilsvrc12/get_ilsvrc_aux.sh
至此我們第一步的任務就over了。
2、準備自己的數據集
我使用的數據集是http://www.vision.caltech.edu/Image_Datasets/Caltech101/Caltech101.html,你用什麼樣的數據集根據你自己要求,我用這個數據集是因爲手邊剛好有這個數據,因爲該數據集一共有101類,我只是爲了練習,所以從中挑選了兩類做實驗,airplanes和Faces。我把數據集分成了兩個部分,train和test。
至此我們第二步的任務就over了。
3、數據集的預處理
當你準備好你自己的數據集後,我們開始預處理數據集。我將數據分成了4個文件夾,如圖所示:
這裏最好將你自己的圖片都resize成網絡所需的,比如說我的都resize成227*227的了,因爲這個是caffeNet網絡所需要的大小。我這裏給出一個簡單的程序可以批處理文件夾中的文件大小。
clear;clc;close all;
tic; % 用於計算程序運行時間,和toc搭配使用
CoreNum=4; % cpu核的數量
% 下面代碼塊爲並行處理檢測與開啓程序,需要在執行結束後予以關閉
if matlabpool('size')<=0
matlabpool('open','local',CoreNum);
else
disp('Already initialized');
end
imagePath = '/home/zf/caffe/data/own_data/val_faces/'; % 圖片存放路徑
imageFiles = dir(imagePath);
numFiles = length(imageFiles);
parfor i=3:numFiles % 從3開始,因爲前兩個是當前路徑‘.’和上一級路徑‘..’
j = i-2;
disp(j);
imageFile = strcat(imagePath,imageFiles(i).name);
A = imread(imageFile);
B = imresize(A,[227 227]); % resize爲227
imwrite(B,imageFile); % 覆蓋原始圖片,若需要另存爲,則修改此處的imageFile爲新的存儲路徑
end
matlabpool close % 關閉並行
toc; % 顯示運行時間
來自網上的代碼3.1、數據集label文件生成
到這一個步驟,我們的數據徹底準備好了,需要把我們的數據以及相應的label寫進一個txt中,作爲我們下一步工作的輸入。最不需要智商的方法就是手動生成txt,但是我個人覺得這個工作量微大,我推薦代碼實現,幾乎任何語言都可以實現這個功能。我這裏給出我使用的代碼,網上一搜羅一大筐這種代碼。
pos_folder='/home/zf/caffe/data/own_data/airplans/';
neg_folder = '/home/zf/caffe/data/own_data/Faces/';
image_width = 227; %圖像小塊的寬度
image_height = 227; %圖像小塊的高度
pixel_total = image_width * image_height*3; %圖像中像素點的數目
pos = dir(pos_folder);
[pos_row,pos_line] = size(pos);
neg = dir(neg_folder);
[neg_row,neg_line] = size(neg);
fid=fopen('/home/zf/caffe/data/myfile/train.txt','w');
for i=3:pos_row
img_name = [pos_folder,pos(i).name];
[a,b]=strtok(img_name,pos_folder);
d=strcat(a,b);
d=strcat('train_pos/',d);
fprintf(fid,'%s %d\n',d,0);
end
for i=3:neg_row
img_name = [neg_folder,neg(i).name];
[a,b]=strtok(img_name,neg_folder);
d=strcat(a,b);
d=strcat('train_neg/',d);
fprintf(fid,'%s %d\n',d,1);
end
fclose(fid);
通過上面的代碼,修改幾次路徑後,我就生成了我所需要的label文件,如下圖所示:
到此基本上我們這一個步驟的工作就完成了。
3.2、將自己的圖片數據集轉換成lmdb
又耽擱了好幾天,繼續罵我的心路歷程。
caffe一共支持三種格式(我的知識理解範疇),LMDB,leveldb以及最原始的image格式。我們這裏選擇LMDB格式,他們三者的優缺點caffe官網上講解的很是清楚,這裏就不羅嗦了。
經過上面的步驟後,我的圖片以及相應的圖片對應的txt文件也準備好了,使用
/home/zf/caffe/build/tools/convert_imageset /home/zf/caffe/data/own_data/ /home/zf/caffe/data/own_data/val.txt test_lmdb
-resize_width=227 -resize_height=227 -check_size -shuffle true
可以將你上一步驟準備好的圖片轉換成相應的格式。其中將
/home/zf/caffe/
/home/zf/caffe/data/own_data/val.txt
改成自己的路徑,test_lmdb
表示的是生成的LMDB的名字,-shuffle true
表示的是是否進行打亂的操作。由於我當時準備的數據集有訓練集和測試集,這樣我修改上面的對應部分,生成了兩個文件,其中每個文件夾中包含兩個文件,如下圖所示。
3.3、計算數據集的mean iamge
現在我們的數據集已經做好了,接下來我們就計算mean image,爲什麼一定要計算這個,這個在caffe後面進行training的階段,會把每個數據圖片減去這個mean image,這樣據說是可以達到去除背景的功能(據說,其實我不明白這個步驟的具體原因)。使用下面的代碼就可以完成這個功能。
sudo /home/zf/caffe/build/tools/compute_image_mean /home/zf/caffe/data/test_lmdb/ /home/zf/caffe/mean_test.binaryproto
調用tools文件夾下面的compute_image_mean 對之前生成的lmdb文件進行求解,求出來的結果保存在一個二進制文件中。網上有其他人將這個圖片imshow出來了,啥也沒有。這個函數其實我們自己也可以實現,它就是將你準備的數據集中的所有圖片的三個圖片對應像素點的像素求了一個均值。
OK,That is all!!
4、開始fineturn
剩下的事情就是fineturn了。萬事俱備只欠一條指令。使用下面的指令我們就完成了。
./build/tools/caffe train --solver ./models/bvlc_reference_caffenet/solver.prototxt
--weights ./models/bvlc_reference_caffenet/bvlc_reference_caffenet.caffemodel --gpu 0
當然如果不指定下面的命令--weights ./models/bvlc_reference_caffenet/bvlc_reference_caffenet.caffemodel
我們進行的就是利用我們準備的數據集以及給定的網絡結構,生成自己的網絡權重。兩者之間的差距其實就是網絡權重初始化的區別。fineturn的網絡權重的初始化是利用我們已經有的caffemodel進行初始化我們網絡的權重,而不加weight的意思是隨機初始化整個網絡的權重,重頭開始train一個新的每層權重。4.1、修改prototxt文件
哈哈,有沒有發現上面單額代碼並不能讓你很好的fineturn以及train,爲什麼了,因爲solver對應的網絡結構prototxt文件和我們所做的任務不相同。舉個簡單的例子,我用的是caffenet做fineturn,caffenet中最後一層softmax可以分類1000類別,而我準備的數據只是二分類,因此這是個需要修改的地方。
同時由於我們的train以及test的數據source和caffenet的肯定不一樣,所以需要修改。同時mean image的文件位置也有可能需要修改一下,基本上需要需改的地方也就是這三個地方。
4.2、開始train
./build/tools/caffe train --solver ./models/bvlc_reference_caffenet/solver.prototxt
--weights ./models/bvlc_reference_caffenet/bvlc_reference_caffenet.caffemodel --gpu 0
OKKKKK!!!!5、done
5.1、查看loss
運行train的時候shell界面出現很多行不知道是啥的東西,我們可以在train的時候將他們保存起來。
./examples/mnist/train_lenet.sh|& tee train_loss.log
這樣我們就把運行的log文件保存下來了。利用tools目錄下面的parse_log.sh可以將我們保存的log文件parse成兩個文件,.test文件和.train文件。
./parse_log.sh train_loss.log
生成如下兩個文件。
通過修改plot_log.gnuplot.example(依然在tools文件夾下),可以畫出Training loss vs. training iterations曲線、Training loss vs. training time曲線等等各種曲線。下圖是我在我自己數據集上訓練誤差曲線。
5.2、查看fineturn過程中生成的snapshot
基本上我們的任務就完成了。剩下的是我們可以使用我們train生成的model進行單張圖片測試等任務。
利用下面的代碼可以實現利用我們生成的caffemodel進行單張圖片分類。
./build/examples/cpp_classification/classification.bin models/bvlc_reference_caffenet/deploy.prototxt models/bvlc_reference_caffenet/bvlc_reference_caffenet.caffemodel
data/ilsvrc12/imagenet_mean.binaryproto data/ilsvrc12/synset_words.txt examples/images/basketball.jpg
到此關於fineturn以及如何自我訓練就完成了。以上都是我親測完的。歡迎大家補充和糾正。謝謝!