Windows下基於Caffe的SSD網路學習(一)配置加生成自己的資料集
最近準備要做畢業設計了,所以從頭又配了一遍Caffe,學了一遍SSD,看了Caffe的原始碼,準備對SSD網路做一些改進。由於這已經是第n遍配置Caffe了,但是還是費了不少時間,所以意識到,總結還是很重要的,所以寫下部落格記錄這一路如何走來,同時也希望可以給有需要的朋友一點點幫助。
配置環境win7+caffe+cudnn8.0+Anaconda2 GPU:1080ti
配置這幾位博主總結的就很好了,照著配就沒問題
https://blog.csdn.net/Allyli0022/article/details/62215416
第二個網址裡的網盤還沒有失效,第一個網址裡面給的網址的網盤失效了。
結合這幾位博主參考的兩篇部落格,已經總夠了。不過我還想補充一些個人經驗,比如opencv2.4.10包的問題,可以看我另一篇部落格。Windows下基於Caffe的SSD網路配置經驗。
配置完成後,先編譯libcaffe,生成需要的一些庫檔案,再編譯caffe。其他的以後用到哪個編譯哪個,注意,這裡編譯是在release模式下編譯,因為我們是要在D:\Caffe_Project\caffe-ssd-microsoft\Build\x64\Release生成.exe檔案,方便以後呼叫。在windows下呼叫它們的方法就是通過.bat檔案。
接著就改準備自己的資料集了。就是要把圖片檔案和.xml檔案整合在一起生成caffe可以識別的.lmdb檔案。一下是步驟
1、由於我的資料集的圖片和.xml檔案是在一起放著,所以我先要把他們分開,把xml檔案存入Annotations(註解的意思)資料夾裡,把bmp圖片存入BMPImages資料夾裡。為什麼要分開呢?因為想要用自帶的一些工具必須這麼做,隨後會提到。但是我沒用自帶的工具,自己寫了指令碼所以不分開也可以。分開當然不能自己手動分,丟程式設計師的人,所以用python寫了一個指令碼,下面是程式碼和講解。
import os,shutil root = "D:/database/ssd/XingChe" txtfilenames=[] for dirpath, dirnames, filenames in os.walk(root): filenames=filter(lambda filename:filename[-4:]=='.bmp',filenames) filenames=map(lambda filename:os.path.join(dirpath,filename),filenames) txtfilenames.extend(filenames) for file in txtfilenames:#注意這裡的txtfilenames是列表,不要加括號 print file shutil.copy(file,r'D:/database/ssd/BMPImages')
txtfilenames是列表,不要加括號 print file shutil.copy(file,r'D:/database/ssd/BMPImages')
別看這麼短的程式碼,我寫了快一上午,沒辦法,不知道該用哪個函式。匯入了兩個模組,os和shutil,他們兩個的用法這裡有
https://www.cnblogs.com/dkblog/archive/2011/03/25/1995537.html
https://www.cnblogs.com/WonderHow/p/4403727.html
關於os.walk(path)的用法就是遍歷這個path下的所有檔案,然後返回三元元組(dirpath,dirnames,filenames)
dirpath:根路徑(字串),dirnames:路徑下的所有目錄名(列表),filenames:路徑下的所有非目錄檔名(列表)其中目錄名和檔名都是沒有加上根路徑的,所以需要完整路徑時要將目錄名和檔名與根路徑連線起來。
示例:
import os
root = "C:\\dir"
for dirpath, dirnames, filenames in os.walk(root):
for filepath in filenames:
print os.path.join(dirpath, filepath)
接著filter就是一個過濾器,lamda的用法如下:
#lambda簡化了函式定義的書寫形式 func=lambda x:x+1就相當於
def func(x):
return(x+1)
1 from functools import reduce
2 foo = [2, 18, 9, 22, 17, 24, 8, 12, 27]
3
4 print (list(filter(lambda x: x % 3 == 0, foo)))
5 #[18, 9, 24, 12, 27]
6
7 print (list(map(lambda x: x * 2 + 10, foo)))
8 #[14, 46, 28, 54, 44, 58, 26, 34, 64]
接著是shutil.copy(),把file檔案拷貝到,第二個資料夾裡,用法可參考
https://blog.csdn.net/qq_25360769/article/details/80023656
我還要補充下append和extend的區別。這樣就把圖片和xml檔案分開了。接下來就要用編譯出來的create_annoset.exe,沒有這個應用程式編譯一下create_annoset工程就有了。但是在用它之前需要準備幾樣東西,我們一個一個來說。
labelmap_voc.prototxt檔案,這個檔案就是一個對映檔案,根據自己標註的類別修改
item {
name: "none_of_the_above"
label: 0
display_name: "background"
}
item {
name: "car"
label: 1
display_name: "car"
}
item {
name: "person"
label: 2
display_name: "person"
}
接著就是trainval.txt檔案格式是一個有路徑的圖片名空格它對應的有路徑xml檔案。它的生成方法,我用matlab寫了一個指令碼實現的,程式碼講解如下:大致思想就是讀出xml檔案,然後生成同名的.bmp檔案存入trainval.txt檔案裡。
clear;
trainval_dir = 'D:\database\ssd\Annotations';
test_dir = 'D:\database\test';
all_file_folder = fullfile(trainval_dir);%fullfile的用法就是產生一個地址
file_names = {dir(fullfile(all_file_folder,'*.xml'))}';%定義為一個cell資料
fid = fopen(fullfile(trainval_dir,'trainval.txt'),'w');
for i_file = 1: length(file_names{1,1})%即定義一個1*1的cell單元
xml_file_name = file_names{1,1}(i_file).name;
name_len = length(file_names{1,1}(i_file).name);
image_file_name = [file_names{1,1}(i_file).name(1:name_len - 4),'.bmp'];
fprintf(fid,'%s %s\n',[image_file_name],[trainval_dir,'\',file_names{1,1}(i_file).name]);
disp(sprintf('當前進度: %d / %d ...', i_file ,length(file_names{1,1})));
end
fclose(fid);
all_file_folder = fullfile(test_dir);
file_names = {dir(fullfile(all_file_folder,'*.xml'))}';
fid = fopen(fullfile(test_dir,'test.txt'),'w');
for i_file = 1: length(file_names{1,1})
xml_file_name = file_names{1,1}(i_file).name;
name_len = length(file_names{1,1}(i_file).name);
image_file_name = [file_names{1,1}(i_file).name(1:name_len - 4),'.bmp'];
fprintf(fid,'%s %s\n',[image_file_name],[test_dir,'\',file_names{1,1}(i_file).name]);
disp(sprintf('當前進度: %d / %d ...', i_file ,length(file_names{1,1})));
end
fclose(fid);
fullfile的用法
f = fullfile('dir1', 'dir2', ..., 'filename')
%fullfile構成地址字串;
如:輸入:f
= fullfile('C:','Applications','matlab','fun.m')
得到:f =C:\Applications\matlab\fun.m
%下例為讀取train資料夾中的所有圖片;
folder=‘train';
filepaths
= dir(fullfile(folder,'*.bmp'));%列出該資料夾下所有.bmp格式的檔案(其中包括檔案的名字、日期、畫素等);
for
i = 1 : length(filepaths)
image = imread(fullfile(folder,filepaths(i).name));%讀入第i個圖片;
image = rgb2ycbcr(image);
image = im2double(image(:, :, 1));%獲得影象的y通道;
im_label = modcrop(image, scale);%保證影象被scale整除;
[hei,wid] = size(im_label);
im_input = imresize(imresize(im_label,1/scale,'bicubic'),[hei,wid],'bicubic');%對影象用'bicubic'先下采樣再上取樣;
%提取資料;
for x = 1 : stride : hei-size_input+1
for y = 1 :stride : wid-size_input+1
subim_input = im_input(x : x+size_input-1, y : y+size_input-1);%子影象尺寸33*33;
subim_label = im_label(x+padding : x+padding+size_label-1, y+padding : y+padding+size_label-1);%子影象類別尺寸21*21;
%subim_input和subim_label的中心一致;
count=count+1;
data(:, :, 1, count) = subim_input;
label(:, :, 1, count) = subim_label;
end
end
end
這樣就完成了trainval.txt , test.txt和labelmap_voc.prototxt的生成。
生成好了的trainval.txt , test.txt,labelmap_voc.prototxt檔案是用來生成資料集train_lmdb和test_lmdb的,我們這裡用convert_annoset.exe,是之前編譯caffe工程生成的一個工具,不用作者給的python檔案來生成資料集,是因為會報錯。建立convert_annoset.bat檔案,裡面輸入為
D:\caffe-ssd-microsoft\Build\x64\Release\convert_annoset.exe --anno_type=detection --label_map_file=D:\caffe-ssd-microsoft\models\MyXingChe\labelmap_xingche.prototxt --encode_type=bmp D:\caffe-ssd-microsoft\models\MyXingChe\out\ D:\caffe-ssd-microsoft\models\MyXingChe\trainval1.txt D:\caffe-ssd-microsoft\models\MyXingChe\trainval_lmdb
D:\caffe-ssd-microsoft\Build\x64\Release\convert_annoset.exe --anno_type=detection --label_map_file=D:\caffe-ssd-microsoft\models\MyXingChe\labelmap_xingche.prototxt --encode_type=bmp D:\caffe-ssd-microsoft\models\MyXingChe\out\ D:\caffe-ssd-microsoft\models\MyXingChe\trainval1.txt D:\caffe-ssd-microsoft\models\MyXingChe\test_lmdb
因為我這裡生成的trainval.txt裡面的檔案只有名字,沒有路徑,所以在它前面要加上絕對路徑即D:\caffe-ssd-microsoft\models\MyXingChe\out\。根據自己的路徑進行修改,我這裡偷了個懶訓練資料和測試資料是一樣的。