Caffe:训练自己的数据

    1、数据准备 

    对于训练,需要两个数据集:一个用于train,一个用于validation(边训练边测试,用于检测模型变化)。

    具体过程参考博文caffe学习系列:训练自己的图片集(超详细教程),简要步骤如下:

    (1)准备好训练和测试样本。

    可以先准备好一个一样的数据集,然后从中每一类抽取一定的比例作为测试样本。如取5个类别的图片,每一类100张,共500张。每一类随机抽取20张作为测试,于是训练集为80*5=400张,测试集为20*5=100张。把训练集和测试集的图片分别放在一个单独的文件夹中,如trian_img和test_img。

    (2)生成lmdb文件。

    首先,新建两个txt文件train.txt和test.txt,列出train_img和test_img的文件名和对应的label(如分类数为5,则取label为0,1,2,3,4,不要取别的,否则会影响训练的精度)。可以参考上述博文的shell脚本:

#!/usr/bin/env sh
    DATA=data/re/
    MY=examples/myfile

    echo "Create train.txt..."
    rm -rf $MY/train.txt
    for i in 3 4 5 6 7 
    do
    find $DATA/train -name $i*.jpg | cut -d '/' -f4-5 | sed "s/$/ $i/">>$MY/train.txt
    done
    echo "Create test.txt..."
    rm -rf $MY/test.txt
    for i in 3 4 5 6 7
    do
    find $DATA/test -name $i*.jpg | cut -d '/' -f4-5 | sed "s/$/ $i/">>$MY/test.txt
    done
    echo "All done"
    其中,可以把第8行的
sed "s/$/ $i/"

    换成

sed "s/$/ $((i-3))/"

    就可以直接生成label为0-4的txt,而不用像博客里的再手动更改。

    其次,也可以用python代码来执行这个过程,甚至可以手动编写,只要能生成这两个txt文件就可以了,生成后的格式如下:

train/348.jpg 0
train/360.jpg 0
train/374.jpg 0
...
...
test/303.jpg 0
test/317.jpg 0
test/316.jpg 0
...
...

    然后,调用caffe自带的convert_imageset工具来生成lmdb文件。可以参考博文里的shell脚本:

#!/usr/bin/env sh
    MY=examples/myfile

    echo "Create train lmdb.."
    rm -rf $MY/img_train_lmdb
    build/tools/convert_imageset \
    --shuffle \
    --resize_height=256 \
    --resize_width=256 \
    /home/xxx/caffe/data/re/ \
    $MY/train.txt \
    $MY/img_train_lmdb

    echo "Create test lmdb.."
    rm -rf $MY/img_test_lmdb
    build/tools/convert_imageset \
    --shuffle \
    --resize_width=256 \
    --resize_height=256 \
    /home/xxx/caffe/data/re/ \
    $MY/test.txt \
    $MY/img_test_lmdb

    echo "All Done.."

    实际上,这一段脚本执行的核心内容是调用了下面的命令。(同样的,也可以使用python来做这个步骤,或者直接手动在终端执行这些命令行)

    build/tools/convert_imageset \
    --shuffle \
    --resize_height=256 \
    --resize_width=256 \
    /home/xxx/caffe/data/re/ \
    $MY/train.txt \
    $MY/img_train_lmdb

    其中的参数主要有:

        shuffle:乱序;

        resize_height、resize_width:把图片变换到需要的大小;

        图片源文件所在的目录;

        上一步生成的txt描述文件的路径;

        目标lmdb的路径。

    执行完上述脚本后,会在指定的目录下生成两个文件夹:img_train_lmdb和img_test_lmdb,里面就是进行训练和测试所需的lmdb文件。

    2、计算均值,生成均值文件

    之所以要计算均值,是为了在后面进行训练和测试的输入时,先把数据减去这个均值,即把数据进行中心化,使数据分布在原点附近,从而加快训练的速度和精度。

    caffe自带了计算均值的工具compute_image_mean,使用方法为:

build/tools/compute_image_mean examples/myfile/img_train_lmdb examples/myfile/mean.binaryproto

    其中,我们只计算train数据集的均值,在validation中也是直接使用这个值,因为train和validation是同源的图片,它们的均值是很接近的。

    3、创建模型,并编辑配置文件

    一个caffe模型主要有以下几个配置文件:

    solver.prototxt:指定模型的训练参数

    train_val.prototxt:指定train和validation的具体网络结构

    deploy.prototxt:指定模型使用时的网络结构(这个结构和train_val的结构基本相似,只是train_val输入的是一个个批次的训练数据,输出的是accuracy和loss,而deploy输入的一般是单个图片,输出的类别编号和概率,里面的网络结构是一样的)

    其中,solver.prototxt的内容如下:

net: "examples/my_file/train_val.prototxt"
test_iter: 2 #2 iteration every test
test_interval: 50 #Test every 50 iteration(batch)
base_lr: 0.001
lr_policy: "step"
gamma: 0.1
stepsize: 100
display: 50
max_iter: 200
momentum: 0.9
weight_decay: 0.005
solver_mode: CPU
snapshot: 50
snapshot_prefix: "examples/my_file/minemodel"

    具体参数意义如下:

    net:指定train_val.prototxt的路径

    test_iter:每次validation时,执行测试的iteration数(一个iteration就是输入一个batch的数据,进行一次迭代),一般一次测试要覆盖一次测试集的大小,即根据训练集大小和batchsize(在train_val.prototxt中设置)来确定

    test_interval:validation的间隔,如该数值为50就是说每训练50个iteration就进行一次test

    base_lr:基本学习率,与后面的lr_policy配合使用

    lr_policy:学习率的下降策略,可用的策略和学习率的计算方式如下

- fixed:   保持base_lr不变.
- step:    如果设置为step,则还需要设置一个stepsize,  返回 base_lr * gamma ^ (floor(iter / stepsize)),其中iter表示当前的迭代次数
- exp:     返回base_lr * gamma ^ iter, iter为当前迭代次数
- inv:      如果设置为inv,还需要设置一个power, 返回base_lr * (1 + gamma * iter) ^ (- power)
- multistep: 如果设置为multistep,则还需要设置一个stepvalue。这个参数和step很相似,step是均匀等间隔变化,而multistep则是根据                                 stepvalue值变化
- poly:     学习率进行多项式误差, 返回 base_lr (1 - iter/max_iter) ^ (power)
- sigmoid: 学习率进行sigmod衰减,返回 base_lr ( 1/(1 + exp(-gamma * (iter - stepsize))))

    还有人做了学习率的变化图,膜拜一下:

        

    gamma、stepsize:学习率下降策略的参数,不同的策略可能参数不太一样

    display:每隔多少次iteration输出一次执行结果

    max_iter:训练的迭代次数,实测可以随时按control+c终止训练,并不会崩溃,而且还会把最后一次训练的结果保存到指定目录。一般需要对训练集进行100个epoch左右,如有10000张训练图片,batchsize为100(即一次iteration就会使用100张图片),那么iteration的次数应该为:100*n/batchsize = 100 * 10000 / 100 = 10000(n为训练集大小)

    momentum:动量,类似于物理的动量,使参数不会剧烈变化。如一般的SGD更新参数的方式为x = x - α * dx,而带momentum的更新方式为v = β * v − α * dx,x = x + v

    weight_decay:参数衰减比例,防止过拟合

    solve_mode:训练的模式,CPU或GPU(没有GPU训练速度比TensorFlow慢)

    snapshot:存储训练快照的频率,如该参数为50,表示每隔50次iteration会自动存储一次模型快照

    snapshot_prefix:模型快照的存储路径

    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: "examples/my_file/mean.binaryproto"
  }
  data_param {
    source: "examples/my_file/img_train_lmdb"
    batch_size: 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/my_file/mean.binaryproto"
  }
  data_param {
    source: "examples/my_file/img_test_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: "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: 5
    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"
}

    其中,网络的第一个layer是data,即数据输入层,配置文件指定了两个data层,一个用于train,一个用于validation的test,分别用include { phase: TRAIN }和include { phase: TEST }来区分。

    cov1后面的就是具体的网络层,常用的层有:

        Convolution:卷积层
        Pooling:池化层
        LRN:局部归一化
        ReLU:激活函数
        InnerProduct:全连接层
        Dropout:随机丢弃

    最后的是InnerProduct全连接层,Accuracy层、SoftmaxWithLoss层,分别输出分类编号、准确率、损失值。其中,最后一个InnerProduct的num_output应该设置为实际类别的数量,如图片分为5类,则该值为5

    其他的参数意义如下:

    transform_param:对数据做预处理的相关参数

    data_param:数据源的相关参数

    mirror:是否做镜像,如果为true,会对输入的图像随机进行左右对称变换

    crop_size:剪切成指定大小

    mean_file:指定均值文件的路径,就是上面第2步生成的文件路径

    source:数据源的路径,就是第1步生成的lmdb文件夹的路径

    batch_size:一个batch的大小。一次iteration实际上是对一个batch的数据进行处理,并根据它们的平均结果来更新参数

    backend:数据源的格式    

    param:本层的参数变化,如果一层有两个param,则第一个指定weight,第二个指定bias

    weight_filler:该层的weight参数初始化方法,(据说gaussian配合softmax使用,xavier配合relu使用,未验证)

    bias_filler:该层的bias参数初始化方法

    lr_mult:用lr_base乘以lr_mult作为该层的参数学习率下降比例

    decay_mult:用weith_dacay乘以decay_mult作为该层的weight_decay

    4、进行训练

    准备好数据,编辑好配置文件,就可以开始训练了,命令如下

build/tools/caffe train -solver examples/myfile/solver.prototxt

    训练过程会根据指定的参数,每隔一定的iteration就会输出训练和测试的结果,并把快照存储到指定的目录

    至此,训练步骤完成。

猜你喜欢

转载自blog.csdn.net/xiezongsheng1990/article/details/80638854