caffe入门-人脸检测1

最近刚入门caffe,跟着视频做了一个简单人脸检测。包括人脸二分类模型+方框框出人脸。

人脸二分类模型

1. 收集数据

我用的是lfw数据集,总共有13233张人脸图片。非人脸数据有两种选择。1. 用完全不是人脸的图片;2. 用与人脸重叠比例较小的图片。我用的是动物的图片作为负样本。负样本数据集

2. 制作LMDB数据源(caffe非常支持的常用于分类的数据源)

首先需要写两个txt文档。train.txt 和 val.txt

主要保存的是图片的路径、名称、label。

形如:train.txt

0/xxx.jpg 0

1/xxx.jpg 1

val.txt

0/xxx.jpg 0

1/xxx.jpg 1

其中0文件夹表示正样本(人脸)、1文件夹表示负样本(非人脸)

如果是多分类,文件夹名称也是从0开始

生成txt文本的python代码(linux和Windows下的代码有点不同):

linux版。jupyter notebook作为编译器

import os 
#定义Caffe根目录
caffe_root = \'/home/z/work/face_detect/\'

# 制作训练标签数据
i = 0 # 标签
with open(caffe_root + \'train.txt\', \'w\') as train_txt:
    for root, dirs, files in os.walk(caffe_root + \'train/\'):  # 遍历文件夹
        for dir in dirs:
            for root, dirs, files in os.walk(caffe_root + \'train/\' + str(dir)): # 遍历每一个文件夹中的文件
                for file in files:
                    image_file = str(dir) + \'/\' + str(file)
                    label = image_file + \' \' + str(i) + \'\n\'     # 文件路径+空格+标签编号+换行
                    train_txt.writelines(label)                  # 写入标签文件中
                i += 1   # 编号加1

# 制作测试标签数据
i = 0 # 标签
with open(caffe_root + \'val.txt\', \'w\') as val_txt:
    for root, dirs, files in os.walk(caffe_root + \'val/\'):  # 遍历文件夹
        for dir in dirs:
            for root, dirs, files in os.walk(caffe_root + \'val/\' + str(dir)): # 遍历每一个文件夹中的文件
                for file in files:
                    image_file = str(dir) + \'/\' + str(file)
                    label = image_file + \' \' + str(i) + \'\n\'     # 文件路径+空格+标签编号+换行
                    val_txt.writelines(label)                  # 写入标签文件中
                i += 1   # 编号加1
print(\'成功生成文件列表\')

两个txt文件创建后,使用caffe提供create_imagenet.sh。当然需要修改。前几行改成自己的安装目录。还要进行一个resize操作,比如ALEXNET或者VGG通常都是给它resize 227*227. 我的文件是face_lmdb.sh

EXAMPLE=/home/z/work/face_detect
DATA=/home/z/work/face_detect
TOOLS=/home/z/caffe/build/tools

TRAIN_DATA_ROOT=/home/z/work/face_detect/train/
VAL_DATA_ROOT=/home/z/work/face_detect/val/

# Set RESIZE=true to resize the images to 256x256. Leave as false if images have
# already been resized using another tool.
RESIZE=true
if $RESIZE; then
  RESIZE_HEIGHT=227
  RESIZE_WIDTH=227
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 \
    --resize_height=$RESIZE_HEIGHT \
    --resize_width=$RESIZE_WIDTH \
    --shuffle \
    $TRAIN_DATA_ROOT \
    $DATA/train.txt \
    $EXAMPLE/face_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/face_val_lmdb

echo "Done."

命令行输入:sh LMDB脚本文件。

3. 训练模型

使用的是AlEXNET,当然用其他的网络也可以,比如VGG。主要是电脑配置比较差,使用cpu跑的,人脸数据集也没有全部使用。

只是为了跑通上述流程。我的训练集使用了1000张人脸,1000张非人脸。测试集使用600张人脸,600张非人脸。生成的LMDB数据源。

1. 网络模型文件train_val.prototxt.

要改的地方不多。数据来源、batch_size、最后全连接层的num_output该为2(2分类)

name: "AlexNet"
layer {
  name: "data"
  type: "Data"
  top: "data"
  top: "label"
  include {
    phase: TRAIN
  }
  transform_param {
    mirror: true
    crop_size: 227
    #mean_file: "data/ilsvrc12/imagenet_mean.binaryproto"
  }
  data_param {
    source: "/home/z/work/face_detect/face_train_lmdb"
    batch_size: 16
    backend: LMDB
  }
}
layer {
  name: "data"
  type: "Data"
  top: "data"
  top: "label"
  include {
    phase: TEST
  }
  transform_param {
    mirror: false
    crop_size: 227
    #mean_file: "data/ilsvrc12/imagenet_mean.binaryproto"
  }
  data_param {
    source: "/home/z/work/face_detect/face_val_lmdb"
    batch_size: 16
    backend: LMDB
  }
}
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: 2
    weight_filler {
      type: "gaussian"
      std: 0.01
    }
    bias_filler {
      type: "constant"
      value: 0
    }
  }
}

2. 参数配置文件solver.prototxt

net: "/home/z/work/face_detect/train_val.prototxt"
test_iter: 20
test_interval: 1000
base_lr: 0.001
lr_policy: "step"
gamma: 0.1
stepsize: 2000
display: 20
max_iter: 450000
momentum: 0.9
weight_decay: 0.0005
snapshot: 1000
snapshot_prefix: "/home/z/work/face_detect/model"
solver_mode: CPU

3. 训练脚本train.sh

#!/usr/bin/env sh
/home/z/caffe/build/tools/caffe train --solver=/home/z/work/face_detect/solver.prototxt