caffe學習筆記6--訓練自己的資料集
這一部分記錄下如何用caffe訓練自己的資料集,這裡使用AlexNet的網路結構。
該結構及相應的solver檔案在CAFFE/models/bvlc_alexnet目錄下,使用train_val.prototxt和solver.prototxt兩個檔案
首先,在$CAFFE/examples/imagenet下面建立自己的資料夾,myimage,
因為原始的Imagenet資料集太大,我們這裡使用自己的資料集,我從網上下載了兩類資料集存放在myimage下的image資料夾下,檔案結構:
-----images
|-------car
|------person
每一類存放在一個資料夾中,接下來生成txt文件,文件中包含了圖片的存放路徑,圖片的標籤,我用python來實現生成.txt檔案
import os root = os.getcwd() #獲取當前路徑 data = 'images' path = os.listdir(root+'/'+ data) #顯示該路徑下所有檔案 path.sort() file = open('train.txt','w') i = 0 for line in path: str = root+'/'+ data +'/'+line for child in os.listdir(str): str1 = data+'/'+line+'/'+child; d = ' %s' %(i) t = str1 + d file.write(t +'\n') i=i+1 file.close()
生成的txt文字的格式如下:
images/car/101008094025552.jpg 0
images/person/5174f5a74f4f0.jpg 1
這裡需要說一下,樣本標籤需要從0開始,否則會出現一些問題。也可以使用控制檯下的命令,這個需要自己查一下,我沒有用過
還需要生成val測試檔案,同樣的步驟。
在生成txt檔案後,需要使用imagenet下的create_imagenet.sh檔案生成lmdb檔案。將這個檔案拷貝到你自己的檔案目錄下,需要修改一些目錄和檔名,看一下里面的內容。
在caffe根目錄下執行:./examples/imagenet/myimage/create_imagenet.sh,資料夾中會多出兩個lmdb的資料夾#!/usr/bin/env sh # Create the imagenet lmdb inputs # N.B. set the path to the imagenet train + val data dirs EXAMPLE=examples/imagenet/myimage TOOLS=build/tools TRAIN_DATA_ROOT=examples/imagenet/myimage/ #訓練樣本的存放路徑 VAL_DATA_ROOT=examples/imagenet/myimage/ #測試樣本的存放路徑 # Set RESIZE=true to resize the images to 256x256. Leave as false if images have # already been resized using another tool. RESIZE=false if $RESIZE; then RESIZE_HEIGHT=256 #改變圖片的大小為256*256 RESIZE_WIDTH=256 else RESIZE_HEIGHT=0 RESIZE_WIDTH=0 fi # 判斷路徑是否正確的提示資訊 if [ ! -d "$TRAIN_DATA_ROOT" ]; then echo "Error: TRAIN_DATA_ROOT is not a path to a directory: $TRAIN_DATA_ROOT" echo "Set the TRAIN_DATA_ROOT variable in create_imagenet.sh to the path" \ "where the ImageNet training data is stored." exit 1 fi if [ ! -d "$VAL_DATA_ROOT" ]; then echo "Error: VAL_DATA_ROOT is not a path to a directory: $VAL_DATA_ROOT" echo "Set the VAL_DATA_ROOT variable in create_imagenet.sh to the path" \ "where the ImageNet validation data is stored." exit 1 fi echo "Creating train lmdb..." GLOG_logtostderr=1 $TOOLS/convert_imageset \ #呼叫convert_imageset檔案轉換檔案格式,後面為輸入引數 --resize_height=$RESIZE_HEIGHT \ --resize_width=$RESIZE_WIDTH \ --shuffle \ $TRAIN_DATA_ROOT \ $EXAMPLE/train.txt \ $EXAMPLE/train_lmdb echo "Creating val lmdb..." GLOG_logtostderr=1 $TOOLS/convert_imageset \ --resize_height=$RESIZE_HEIGHT \ --resize_width=$RESIZE_WIDTH \ --shuffle \ $VAL_DATA_ROOT \ $EXAMPLE/val.txt \ $EXAMPLE/val_lmdb echo "Done."
其實, 對於改變圖片的大小,可以在當前目錄下使用:
for name in images/*/*.jpg;do convert -resize 256x256\! $name $name; done
這條命令*為萬用字元,上面--resize可以不要
接下來,需要對現有圖片求均值:
使用imagenet中的make_imagenet_mean.sh對訓練圖片資料求均值,將其拷貝到你的檔案目錄下,修改下路徑:
#!/usr/bin/env sh
# Compute the mean image from the imagenet training lmdb
# N.B. this is available in data/ilsvrc12
EXAMPLE=examples/imagenet/myimage
TOOLS=build/tools
$TOOLS/compute_image_mean $EXAMPLE/train_lmdb \ #呼叫compute_iamge_mean計算均值,其cpp程式碼在tool目錄下
$EXAMPLE/imagenet_mean.binaryproto
echo "Done."
在caffe根目錄下執行:./examples/imagenet/myimage/make_imagenet_mean.sh
完成之後,還需要做的事情就是修改網路的訓練引數和獲取檔案的地址:
首先,看一下train_val.prototxt.
需要修改:
name: "AlexNet"
layer {
name: "data"
type: "Data"
top: "data"
top: "label"
include {
phase: TRAIN
}
transform_param {
mirror: true
crop_size: 227
mean_file: "examples/imagenet/myimage/imagenet_mean.binaryproto" #均值二進位制檔案的存放目錄
}
data_param {
source: "examples/imagenet/myimage/train_lmdb" #資料的存放目錄
batch_size: 50 #因為我的資料規模很小,所以批處理的資料的量我改為50。
backend: LMDB
}
}
layer {
name: "data"
type: "Data"
top: "data"
top: "label"
include {
phase: TEST
}
transform_param {
mirror: false
crop_size: 227
mean_file: "examples/imagenet/myimage/imagenet_mean.binaryproto"
}
data_param {
source: "examples/imagenet/myimage/val_lmdb"
batch_size: 50
backend: LMDB
}
}
對於solver.prototxt:
net: "examples/imagenet/myimage/train_val.prototxt"
test_iter: 10
test_interval: 100
base_lr: 0.001
lr_policy: "step"
gamma: 0.1
stepsize: 100
display: 20
max_iter: 400 #這裡說一下最大迭代次數,原來文件中是45000,但是我的資料量很小,在幾百次的時候loss已經比較小了,為了儘快的到訓練結果,因此,所有的引數都相應有所修改。
momentum: 0.9
weight_decay: 0.0005
snapshot: 200
snapshot_prefix: "examples/imagenet/myimage"
solver_mode: CPU #我這裡使用cpu,自作的,慢的要死.
關於這兩個檔案的解釋,可以看我之前寫的部落格,
修改完成後,可以開始訓練了:
將train_caffenet.sh放到自己的檔案目錄下,
#!/usr/bin/env sh
./build/tools/caffe train \
--solver=examples/imagenet/myimage/solver.prototxt
在CAFFE根目錄下執行:./examples/imagenet/myimage/train_caffenet.sh
這裡需要注意,所有的執行語句一定是在根目錄下,否則會報錯,除非你在配置檔案時候更改路徑!
這樣,訓練過程就開始了,
稍微描述一下執行過程:
首先,初始化引數:輸出solver.prototxt中的內容:
然後,初始化網路結構,就是train_val中的內容,這個可以在上個輸出網路初始化過程中看出來。
接下來就是進入訓練過程。
在我的訓練過程中:
剛開始訓練時:
I0418 09:38:17.902889 504 solver.cpp:409] Test net output #0: accuracy = 0
I0418 09:38:17.902942 504 solver.cpp:409] Test net output #1: loss = 6.93296 (* 1 = 6.93296 loss)
在進過一段時間的迭代後:loss減少,但是真確率提高。至於正確率,估計是我的資料的問題
I0418 10:53:33.159943 504 solver.cpp:409] Test net output #0: accuracy = 1
I0418 10:53:33.159999 504 solver.cpp:409] Test net output #1: loss = 0.0103494 (* 1 = 0.0103494 loss)
還有一個要注意的是,在alexnet的訓練中,lr不是固定的,在sovler中設定,這個可以觀察一下控制檯的輸出。
最後要說的是,這裡只是向走一遍訓練的過程,但是網路的訓練肯定是不充分的。
另外,我是將所有的檔案都放在自己的目錄下嗎,也可以不放,但是要注意檔案的路徑。
補充記錄兩個問題:
1.gpu訓練,執行過程中如果出現報錯:
Check failed: error == cudaSuccess (2 vs. 0) out of memory
這個問題很可能是你的網路結構中batch_size的值太大的原因,改小一點就沒有問題
2. 迭代過程中出現 loss=-nan
這個問題可能比較多,說明學習率的值設的太大,改小一點再嘗試.