1. 程式人生 > >使用caffe中的imagenet對自己的圖片進行分類訓練(超級詳細版)

使用caffe中的imagenet對自己的圖片進行分類訓練(超級詳細版)

因為自己在網路上查到的資料對於一個新手來說雖然指明瞭方向,但是在細節上沒有給出很好的例項,因此我把自己訓練的過程記錄下來。

【實驗環境】

實體記憶體:64G Free:7.5G  CPU個數:3,單個CPU物理核數:8

作業系統:Linux

備註:具有GPU運算能力

【實驗目標】

使用自己的圖片集,以及caffe框架,對imagenet進行訓練,得到自己的model。

【前期準備】

1.      安裝並配置caffe環境

【實驗過程】

1.      資料集準備

獲取訓練圖片集與驗證圖片集,併產生train.txt與val.txt,內容為圖片路徑與分類標籤;將圖片進行大小重設,設定為256*256大小;使用create_imagenet.sh指令碼將2組圖片集轉換為lmbp格式。

2.      計算影象均值

使用make_imagenet_mean.sh計算影象均值,產生imagenet_mean.binaryproto檔案。

3.      設定網路引數

拷貝caffe-master/model/bvlc_reference_caffenet中的檔案,修改train_val.prototxt,solver.prototxt中的執行引數,並進行路徑的修改;拷貝caffe_master/examples/imagenet中的train_caffnet.sh檔案,對路徑進行修改。

4.      執行train_caffnet.sh

【實驗過程詳細版】

備註一下目錄的情況,這樣比較調理啦:

Caffe根目錄:caffe_root=/home/james/caffe/

圖片類資料:caffe_root/data/mydata

命令引數類資料:caffe_root/examples/mytask

注:預設我們手動新增的除圖片以及.txt之外的檔案都屬於命令引數類資料,執行的時候注意路徑就好,另外,我門在實驗的時候換了別人的電腦,因此存在caffe根路徑前後不一致的狀況,大家注意一下就好。

1.      資料集準備

a.      準備訓練圖片集以及驗證圖片集

新建caffe_root/data/mydata,分別將圖片集放置於caffe_root/data/mydata/train與caffe_root/data/mydata/val下面

b.      準備圖片清單

在caffe_root/data/mydata下面新建兩個檔案train.txt與val.txt,train.txt中的內容為:

       1.jpg 7

       2.jpg7

       3.jpg 7

       …

以上格式為圖片名稱+空格+類標(數字)的格式,val.txt的格式也是一樣的(同樣需要類標)。

此步可以使用create_filelist.sh進行批量新增圖片路徑至train.txt。create_filelist.sh內容需要按照自身圖片的名稱與類標情況進行修改,並持續執行(因為是在檔案後面追加)內容如下:

#!/usr/bin/env sh

#!/bin/bash

DATA=/home/james/caffe/data/mydata/val

MY=/home/james/caffe/data/mydata

for i in {3122..3221}

do

echo $i.jpg 3 >> $MY/val.txt

done

echo "All done"

以上命令意思是,在val資料夾下面的圖片中,名稱為3122.jpg至3221.jpg的圖片都是第3類,因此就會在val.txt寫入:

        3122.jpg 3

        3123.jpg 3

        …

注意:此時可能會報出bad loop variable的錯誤,這是由於Ubuntu bash的版本的原因,可以自行檢視如何解決。

c.      調整圖片大小至256*256

因為之前沒有仔細看caffe的相關檔案,後來才知道可以使用之自動調整大小,因此此步採用的是自己呼叫命令進行調整大小。如果不調整圖片大小的話,在執行後面命令的時候是會報錯的。

   可以使用convert256.sh進行轉換。注意,該命令中用到了imagemagick工具,因此如果自己沒有安裝的話,還需要安裝該工具(命令為:sudo apt-get install imagemagick)。convert256.sh內容如下:

for name in/home/james/caffe/data/mydata/train/*.jpg; do

convert -resize 256x256\! $name $name

done

d.      構建圖片資料庫

要讓Caffe進行圖片的訓練,必須有圖片資料庫,並且也是使用其作為輸入,而非直接使用圖片作為輸入。使用create_imagenet.sh指令碼將train與val的2組圖片集轉換為lmbp格式。create_imagenet.sh內容如下:

#!/usr/bin/env sh

# Create the imagenet lmdb inputs

# N.B. set the path to the imagenet train +val data dirs

EXAMPLE=/home/james/caffe/examples/mytask

DATA=/home/james/caffe/data/mydata

TOOLS=/home/james/caffe/build/tools

TRAIN_DATA_ROOT=/home/james/caffe/data/mydata/train/

VAL_DATA_ROOT=/home/james/caffe/data/mydata/val/

# Set RESIZE=true to resize the images to256x256. Leave as false if images have

# already been resized using another tool.

RESIZE=false

if $RESIZE; then

 RESIZE_HEIGHT=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 thepath" \

      "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 thepath" \

      "where the ImageNet validation data is stored."

 exit 1

fi

echo "Creating train lmdb..."

GLOG_logtostderr=1 $TOOLS/convert_imageset\

   --resize_height=$RESIZE_HEIGHT \

   --resize_width=$RESIZE_WIDTH \

   --shuffle \

   $TRAIN_DATA_ROOT \

   $DATA/train.txt \

   $EXAMPLE/ilsvrc12_train_lmdb

echo "Creating val lmdb..."

GLOG_logtostderr=1 $TOOLS/convert_imageset\

   --resize_height=$RESIZE_HEIGHT \

   --resize_width=$RESIZE_WIDTH \

   --shuffle \

   $VAL_DATA_ROOT \

   $DATA/val.txt \

   $EXAMPLE/ilsvrc12_val_lmdb

echo "Done."

注:將其中的地址均修改為自己的對應地址,不是地址的就不要強行修改啦。

2.      計算影象均值

據說計算影象均值之後的訓練效果會更好,使用make_imagenet_mean.sh計算影象均值,產生imagenet_mean.binaryproto檔案。make_imagenet_mean.sh檔案內容如下:

#!/usr/bin/env sh

# Compute the mean image from the imagenettraining lmdb

# N.B. this is available in data/ilsvrc12

EXAMPLE=/home/james/caffe/examples/mytask

DATA=/home/james/caffe/data/mydata/

TOOLS=/home/james/caffe/build/tools

$TOOLS/compute_image_mean$EXAMPLE/ilsvrc12_train_lmdb \

  $DATA/imagenet_mean.binaryproto

echo "Done."

注:將其中的地址修改為自己的地址,並且產生的imagenet_mean.binaryproto檔案在data/mydata資料夾下,稍後設定的時候注意該路徑。

3.      設定訓練引數

拷貝caffe-master/model/bvlc_reference_caffenet中的檔案,修改train_val.prototxt,solver.prototxt中的執行引數,並進行路徑的修改;拷貝caffe_master/examples/imagenet中的train_caffnet.sh檔案,對路徑進行修改。

train_val.prototxt是網路的結構,內容如下:

name: "CaffeNet"

layer {

 name: "data"

 type: "Data"

 top: "data"

 top: "label"

 include {

   phase: TRAIN

  }

 transform_param {

   mirror: true

   crop_size: 227

   mean_file:"/home/dina/caffe/examples/mytask/imagenet_mean.binaryproto"

  }

# mean pixel / channel-wise mean instead ofmean image

# transform_param {

#   crop_size: 227

#   mean_value: 104

#   mean_value: 117

#   mean_value: 123

#   mirror: true

#  }

 data_param {

   source: "/home/dina/caffe/examples/mytask/ilsvrc12_train_lmdb"

   batch_size: 256

   backend: LMDB

  }

}

layer {

 name: "data"

 type: "Data"

 top: "data"

 top: "label"

 include {

   phase: TEST

  }

 transform_param {

   mirror: false

   crop_size: 227

   mean_file:"/home/dina/caffe/examples/mytask/imagenet_mean.binaryproto"

  }

# mean pixel / channel-wise mean instead ofmean image

# transform_param {

#   crop_size: 227

#   mean_value: 104

#   mean_value: 117

#   mean_value: 123

#   mirror: false

#  }

 data_param {

   source: "/home/dina/caffe/examples/mytask/ilsvrc12_val_lmdb"

   batch_size: 50

   backend: LMDB

  }

}

layer {

 name: "conv1"

 type: "Convolution"

 bottom: "data"

 top: "conv1"

 param {

    lr_mult: 1

   decay_mult: 1

  }

 param {

   lr_mult: 2

   decay_mult: 0

  }

 convolution_param {

   num_output: 96

   kernel_size: 11

   stride: 4

   weight_filler {

     type: "gaussian"

     std: 0.01

    }

   bias_filler {

     type: "constant"

     value: 0

    }

  }

}

layer {

 name: "relu1"

 type: "ReLU"

 bottom: "conv1"

 top: "conv1"

}

layer {

 name: "pool1"

 type: "Pooling"

 bottom: "conv1"

 top: "pool1"

 pooling_param {

   pool: MAX

   kernel_size: 3

   stride: 2

  }

}

layer {

 name: "norm1"

 type: "LRN"

 bottom: "pool1"

 top: "norm1"

 lrn_param {

   local_size: 5

   alpha: 0.0001

   beta: 0.75

  }

}

layer {

 name: "conv2"

 type: "Convolution"

 bottom: "norm1"

 top: "conv2"

 param {

    lr_mult:1

   decay_mult: 1

  }

 param {

   lr_mult: 2

   decay_mult: 0

  }

 convolution_param {

   num_output: 256

   pad: 2

   kernel_size: 5

   group: 2

   weight_filler {

     type: "gaussian"

     std: 0.01

    }

   bias_filler {

     type: "constant"

     value: 1

    }

  }

}

layer {

 name: "relu2"

 type: "ReLU"

 bottom: "conv2"

 top: "conv2"

}

layer {

 name: "pool2"

 type: "Pooling"

 bottom: "conv2"

 top: "pool2"

 pooling_param {

   pool: MAX

   kernel_size: 3

   stride: 2

  }

}

layer {

 name: "norm2"

 type: "LRN"

 bottom: "pool2"

 top: "norm2"

 lrn_param {

   local_size: 5

   alpha: 0.0001

   beta: 0.75

  }

}

layer {

 name: "conv3"

 type: "Convolution"

 bottom: "norm2"

 top: "conv3"

 param {

    lr_mult:1

   decay_mult: 1

  }

 param {

   lr_mult: 2

   decay_mult: 0

  }

 convolution_param {

   num_output: 384

   pad: 1

   kernel_size: 3

   weight_filler {

     type: "gaussian"

     std: 0.01

    }

   bias_filler {

     type: "constant"

     value: 0

    }

  }

}

layer {

 name: "relu3"

 type: "ReLU"

 bottom: "conv3"

 top: "conv3"

}

layer {

 name: "conv4"

 type: "Convolution"

 bottom: "conv3"

 top: "conv4"

 param {

   lr_mult: 1

   decay_mult: 1

  }

 param {

   lr_mult: 2

   decay_mult: 0

  }

 convolution_param {

   num_output: 384

   pad: 1

   kernel_size: 3

   group: 2

   weight_filler {

     type: "gaussian"

     std: 0.01

    }

   bias_filler {

     type: "constant"

     value: 1

    }

  }

}

layer {

 name: "relu4"

 type: "ReLU"

 bottom: "conv4"

 top: "conv4"

}

layer {

 name: "conv5"

 type: "Convolution"

 bottom: "conv4"

 top: "conv5"

 param {

   lr_mult: 1

   decay_mult: 1

  }

 param {

   lr_mult: 2

   decay_mult: 0

  }

 convolution_param {

   num_output: 256

   pad: 1

   kernel_size: 3

   group: 2

   weight_filler {

     type: "gaussian"

     std: 0.01

    }

   bias_filler {

     type: "constant"

     value: 1

    }

  }

}

layer {

 name: "relu5"

 type: "ReLU"

 bottom: "conv5"

 top: "conv5"

}

layer {

 name: "pool5"

 type: "Pooling"

 bottom: "conv5"

 top: "pool5"

 pooling_param {

   pool: MAX

   kernel_size: 3

   stride: 2

  }

}

layer {

 name: "fc6"

 type: "InnerProduct"

 bottom: "pool5"

 top: "fc6"

 param {

   lr_mult: 1

   decay_mult: 1

  }

 param {

   lr_mult: 2

   decay_mult: 0

  }

 inner_product_param {

   num_output: 4096

   weight_filler {

     type: "gaussian"

     std: 0.005

    }

   bias_filler {

     type: "constant"

     value: 1

    }

  }

}

layer {

 name: "relu6"

 type: "ReLU"

 bottom: "fc6"

 top: "fc6"

}

layer {

 name: "drop6"

 type: "Dropout"

 bottom: "fc6"

 top: "fc6"

 dropout_param {

   dropout_ratio: 0.5

  }

}

layer {

 name: "fc7"

 type: "InnerProduct"

 bottom: "fc6"

 top: "fc7"

 param {

   lr_mult: 1

   decay_mult: 1

  }

 param {

   lr_mult: 2

   decay_mult: 0

  }

 inner_product_param {

   num_output: 4096

   weight_filler {

     type: "gaussian"

     std: 0.005

    }

   bias_filler {

     type: "constant"

     value: 1

    }

  }

}

layer {

 name: "relu7"

 type: "ReLU"

 bottom: "fc7"

 top: "fc7"

}

layer {

 name: "drop7"

 type: "Dropout"

 bottom: "fc7"

 top: "fc7"

 dropout_param {

   dropout_ratio: 0.5

  }

}

layer {

 name: "fc8"

 type: "InnerProduct"

 bottom: "fc7"

 top: "fc8"

 param {

   lr_mult: 1

   decay_mult: 1

  }

 param {

   lr_mult: 2

   decay_mult: 0

  }

 inner_product_param {

   num_output: 1000

   weight_filler {

     type: "gaussian"

     std: 0.01

    }

   bias_filler {

     type: "constant"

     value: 0

    }

  }

}

layer {

 name: "accuracy"

 type: "Accuracy"

 bottom: "fc8"

 bottom: "label"

 top: "accuracy"

 include {

   phase: TEST

  }

}

layer {

 name: "loss"

 type: "SoftmaxWithLoss"

 bottom: "fc8"

 bottom: "label"

 top: "loss"

}

solver.prototxt是網路引數的設定,內容如下:

net:"/home/dina/caffe/examples/mytask/train_val.prototxt"

test_iter: 2

test_interval: 50

base_lr: 0.001

lr_policy: "step"

gamma: 0.1

stepsize: 100

display: 20

max_iter: 1000

momentum: 0.9

weight_decay: 0.0005

snapshot: 500

snapshot_prefix:"models/bvlc_reference_caffenet/caffenet_train"

solver_mode: GPU

train_caffnet.sh是執行網路的命令,內容如下:

#!/usr/bin/env sh

./build/tools/caffe train \

--solver=./examples/mytask/solver.prototxt

好了,可以等待訓練過程了,我們的訓練圖片是2000個訓練圖片,1000個驗證圖片,大約過了3-4個小時,就訓練好了。