1. 程式人生 > >Windows下基於Caffe的SSD網路學習(一)配置加生成自己的資料集

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\。根據自己的路徑進行修改,我這裡偷了個懶訓練資料和測試資料是一樣的。