這一部分記錄下如何用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文件。將這個文件拷貝到你自己的文件目錄下,需要修改一些目錄和文件名,看一下里面的內容。
#!/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."
在caffe根目錄下運行:./examples/imagenet/myimage/create_imagenet.sh,文件夾中會多出兩個lmdb的文件夾
其實, 對於改變圖片的大小,可以在當前目錄下使用:
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
這個問題可能比較多,說明學習率的值設的太大,改小一點再嘗試.