vgg_face人脸识别
最近参考http://blog.csdn.net/hlx371240/article/details/51388022一文,用LFW数据集对vgg_face.caffemodel进行fine-tune。主要步骤和http://blog.csdn.net/hlx371240/article/details/51388022文中所阐述的步骤没有区别。个别地方稍微补充一下:
1.LFW标定生成程序
#include <stdio.h> #include <unistd.h> #include <dirent.h> #include <stdlib.h> #include <sys/stat.h> #include <string.h> #include <assert.h> #define MAX_PATH_LEN 512 int count =0; char dirPath[MAX_PATH_LEN]; void listAllFiles(char *dirname) { assert(dirname != NULL); char path[512]; struct dirent *filename; DIR *dir; dir = opendir(dirname); if(dir == NULL) { printf("open dir %s error!\n",dirname); exit(1); } while((filename = readdir(dir)) != NULL) { if(!strcmp(filename->d_name,".")||!strcmp(filename->d_name,"..")) continue; sprintf(path,"%s/%s",dirname,filename->d_name); struct stat s; lstat(path,&s); if(S_ISDIR(s.st_mode)) { listAllFiles(path); count++; //每个子文件夹对应的labelID计算 } else { printf("%s/%s %d\n",dirname,filename->d_name,count); } } closedir(dir); } int main(int argc, char **argv) { if(argc != 2) { printf("one dir required!(for eample: ./a.out /home/myFolder)\n"); exit(1); } strcpy(dirPath,argv[1]); listAllFiles(dirPath); //printf("total files:%d\n",count); return 0; }
程序使用命令:
gcc label_generate.c -o label_generate
./label_generate $DATA_ROOT/lfw
2. Finetuning的prototxt
我们只针对fc8进行fine-tune,因此将相应的层名称修改为fc8_finetune
# Data Layer layers { name: "data" type: DATA include { phase: TRAIN } transform_param { crop_size: 224 mean_file: "/$DATA_ROOT/face_mean.binaryproto" mirror: true } data_param { source: "/$DATA_ROOT/face_train_lmdb" batch_size: 144 backend: LMDB } top: "data" top: "label" } layers { name: "data" type: DATA include { phase: TEST } transform_param { crop_size: 224 mean_file: "/$DATA_ROOT/face_mean.binaryproto" mirror: false } data_param { source: "$DATA_ROOT/face_val_lmdb" batch_size: 144 backend: LMDB } top: "data" top: "label" } # conv1_1~fc7 layers { bottom: "conv1_1" top: "conv1_1" name: "relu1_1" type: RELU } layers { bottom: "conv1_1" top: "conv1_2" name: "conv1_2" type: CONVOLUTION convolution_param { num_output: 64 pad: 1 kernel_size: 3 } } layers { bottom: "conv1_2" top: "conv1_2" name: "relu1_2" type: RELU } layers { bottom: "conv1_2" top: "pool1" name: "pool1" type: POOLING pooling_param { pool: MAX kernel_size: 2 stride: 2 } } layers { bottom: "pool1" top: "conv2_1" name: "conv2_1" type: CONVOLUTION convolution_param { num_output: 128 pad: 1 kernel_size: 3 } } layers { bottom: "conv2_1" top: "conv2_1" name: "relu2_1" type: RELU } layers { bottom: "conv2_1" top: "conv2_2" name: "conv2_2" type: CONVOLUTION convolution_param { num_output: 128 pad: 1 kernel_size: 3 } } layers { bottom: "conv2_2" top: "conv2_2" name: "relu2_2" type: RELU } layers { bottom: "conv2_2" top: "pool2" name: "pool2" type: POOLING pooling_param { pool: MAX kernel_size: 2 stride: 2 } } layers { bottom: "pool2" top: "conv3_1" name: "conv3_1" type: CONVOLUTION convolution_param { num_output: 256 pad: 1 kernel_size: 3 } } layers { bottom: "conv3_1" top: "conv3_1" name: "relu3_1" type: RELU } layers { bottom: "conv3_1" top: "conv3_2" name: "conv3_2" type: CONVOLUTION convolution_param { num_output: 256 pad: 1 kernel_size: 3 } } layers { bottom: "conv3_2" top: "conv3_2" name: "relu3_2" type: RELU } layers { bottom: "conv3_2" top: "conv3_3" name: "conv3_3" type: CONVOLUTION convolution_param { num_output: 256 pad: 1 kernel_size: 3 } } layers { bottom: "conv3_3" top: "conv3_3" name: "relu3_3" type: RELU } layers { bottom: "conv3_3" top: "pool3" name: "pool3" type: POOLING pooling_param { pool: MAX kernel_size: 2 stride: 2 } } layers { bottom: "pool3" top: "conv4_1" name: "conv4_1" type: CONVOLUTION convolution_param { num_output: 512 pad: 1 kernel_size: 3 } } layers { bottom: "conv4_1" top: "conv4_1" name: "relu4_1" type: RELU } layers { bottom: "conv4_1" top: "conv4_2" name: "conv4_2" type: CONVOLUTION convolution_param { num_output: 512 pad: 1 kernel_size: 3 } } layers { bottom: "conv4_2" top: "conv4_2" name: "relu4_2" type: RELU } layers { bottom: "conv4_2" top: "conv4_3" name: "conv4_3" type: CONVOLUTION convolution_param { num_output: 512 pad: 1 kernel_size: 3 } } layers { bottom: "conv4_3" top: "conv4_3" name: "relu4_3" type: RELU } layers { bottom: "conv4_3" top: "pool4" name: "pool4" type: POOLING pooling_param { pool: MAX kernel_size: 2 stride: 2 } } layers { bottom: "pool4" top: "conv5_1" name: "conv5_1" type: CONVOLUTION convolution_param { num_output: 512 pad: 1 kernel_size: 3 } } layers { bottom: "conv5_1" top: "conv5_1" name: "relu5_1" type: RELU } layers { bottom: "conv5_1" top: "conv5_2" name: "conv5_2" type: CONVOLUTION convolution_param { num_output: 512 pad: 1 kernel_size: 3 } } layers { bottom: "conv5_2" top: "conv5_2" name: "relu5_2" type: RELU } layers { bottom: "conv5_2" top: "conv5_3" name: "conv5_3" type: CONVOLUTION convolution_param { num_output: 512 pad: 1 kernel_size: 3 } } layers { bottom: "conv5_3" top: "conv5_3" name: "relu5_3" type: RELU } layers { bottom: "conv5_3" top: "pool5" name: "pool5" type: POOLING pooling_param { pool: MAX kernel_size: 2 stride: 2 } } layers { bottom: "pool5" top: "fc6" name: "fc6" type: INNER_PRODUCT inner_product_param { num_output: 4096 } } layers { bottom: "fc6" top: "fc6" name: "relu6" type: RELU } layers { bottom: "fc6" top: "fc6" name: "drop6" type: DROPOUT dropout_param { dropout_ratio: 0.5 } } layers { bottom: "fc6" top: "fc7" name: "fc7" type: INNER_PRODUCT inner_product_param { num_output: 4096 } } layers { bottom: "fc7" top: "fc7" name: "relu7" type: RELU } layers { bottom: "fc7" top: "fc7" name: "drop7" type: DROPOUT dropout_param { dropout_ratio: 0.5 } } # fc8_finetune and Loss layers { bottom: "fc7" top: "fc8" name: "fc8_finetune" type: INNER_PRODUCT inner_product_param { num_output: 5749 } } layers { name: "loss" bottom: "fc8" bottom: "label" top: "loss" type: SOFTMAX_LOSS }
3.脚本配置
crete_lmdb.sh:生成训练和测试数据
#!/usr/bin/env sh # Create the imagenet lmdb inputs # N.B. set the path to the imagenet train + val data dirs # CAFFE_ROOT is the path of your caffe and you should set it as the absolute path # train.txt and val.txt are saved in the path $CAFFE_ROOT/VGG/data EXAMPLE=$CAFFE_ROOT/VGG/lmdb_root DATA=$CAFFE_ROOT/VGG/data TOOLS=$CAFFE_ROOT/build/tools TRAIN_DATA_ROOT=$CAFFE_ROOT/VGG/data VAL_DATA_ROOT=$CAFFE_ROOT/VGG/data # 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=224 RESIZE_WIDTH=224 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.bin \ --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.bin \ --resize_height=$RESIZE_HEIGHT \ --resize_width=$RESIZE_WIDTH \ --shuffle \ $VAL_DATA_ROOT \ $DATA/val.txt \ $EXAMPLE/face_val_lmdb echo "Done."
compute_mean.sh:生成face_mean.binaryproto
#!/usr/bin/env sh # Compute the mean image from the imagenet training lmdb # N.B. this is available in data/ilsvrc12 EXAMPLE=$CAFFE_ROOT/VGG/lmdb_root DATA=$CAFFE_ROOT/VGG/data TOOLS=$CAFFE_ROOT/build/tools $TOOLS/compute_image_mean $EXAMPLE/face_train_lmdb \ $DATA/face_mean.binaryproto echo "Done."
vgg_train.sh:开启训练
#!/usr/bin/env sh $CAFFE_ROOT/build/tools/caffe train \ --solver=$CAFFE_ROOT/VGG/solver.prototxt \ --weights=$CAFFE_ROOT/VGG/VGG_FACE.caffemodel -gpu=0
爱上一个人,就像突然有了盔甲,也突然有了软肋。