1. 程式人生 > >caffe學習筆記6--訓練自己的資料集

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檔案。將這個檔案拷貝到你自己的檔案目錄下,需要修改一些目錄和檔名,看一下里面的內容。

#!/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

這個問題可能比較多,說明學習率的值設的太大,改小一點再嘗試.