学习 Linux 下使用 caffe 进行模型训练(二)

前言

距离环境完成环境配置已经过去一个月了,这一个月内从整理数据、模型训练到最后结果分析,完成了一整个 yolo 识别的流程,因此把这个作为一个节点,来记录一下 caffe 模型训练过程,关于结果分析下一篇再细说~。

前期准备

一、网络选择

上一篇 学习 Linux 下使用 caffe 进行模型训练(一) 中,只是说明了对 caffe 源码的编译过程,由于 caffe 的特殊性,需要提前编译好你所用到的 layer,因此如果使用官方的 caffe 源码去实现其他的网络,往往会出现需要的 layer 不存在的情况(例如 yolo v2 中的 reorg 层),导致后续工作无法进行。因此,当选择好要实现的网络后,应当首先看一下是否所有的 layer 都是存在的,如果不存在则自己重新编译一下需要的 layer 即可。

本次使用的 yolo v3 网络在 github 上已经有很多大牛做了 caffe 实现,因此我下载了源码然后重新编译了一版。

Github 下载链接:https://github.com/eric612/MobileNet-YOLO

Ps: 之后的操作都是基于该版本的 caffe 而非前文提到的原生 caffe,因为除了 layer 之外,为了数据的生成等操作,这位大牛还编写了一些脚本供大家使用,因此推荐根据具体的任务编译具体的 caffe 。

二、文件结构

这里是我个人的爱好,有的人喜欢直接在编译好的 caffe 中,增加或删除一些东西,确实很方便,但是多个网络的模型、数据等混在一起,不利于后续的维护与修改。所以我按照如下结构构建了文件夹,使后续训练更为清晰。

./yoloProject
    ├─ datasets				# 用于存放需要的数据
    |	├─ JPEGImages		# 训练集与验证集图片
    |	├─ Annotations		# labelImage 生成的 xml 标注文件(训/验)
    |	└─ TEST				# 测试集图片
    ├─ models				# 用于存放训练有关的模型
    |	├─ preTrain			# 存放可能需要的与训练模型
    |	└─ outPut			# 存放网络训练输出的训练模型
    └─ nets					# 用于存放网络结构与训练过程相关的文件与脚本
        ├─ LOG				# 存放训练过程中的日志文件,方便后续进行可视化分析
        ├─ prototxt			# 存放 caffe 训练所必须的网络结构文件 .prototxt
        └─ train.sh			# 简单的 shell 脚本,为了更方便的训练网络

三、数据准备(.JPG 等)

和几乎所有的深度学习流程一样,将需要新进行训练的图片数据分为训练集、验证集与测试集,将训练集与验证集的图片放入 JPEGImages,然后将与他们命名完全一致的 .xml 标注文件放入 Annotations,最后,将测试集的图片放入 TEST 中,用来检验最终的效果。

网络训练

一、数据准备(lmdb)

LMDB 是 Caffe 中应用的一种数据库,采用内存-映射文件(memory-mapped files,数据和label都作为value,然后连续增加一个整数作为key),所以拥有非常好的I/O性能。对于图片这种数据量极大的训练集,使用 lmdb 数据可以提高磁盘 I/O效率,提高速度且节省空间。

Caffe 提供了用于将 “img-label” 转为 lmdb 文件的脚本,因此我们只要做一些简单的准备工作,就可以直接使用他完成数据的转换。

  1. 编写脚本来将训练集与验证集中的文件去除后缀名后分别写入 train.txt 和 val.txt ;
  2. 使用 creat_list.sh 脚本,依照 train.txt 和 val.txt,在其前增加路径,其后加入后缀名,生成新的 train.txt 和 val.txt (这也就是为什么之前要求图片与标注的命名要完全一致);
  3. 准备好 labelmap_data.prototxt 文件,该文件记录了被检测的目标类比(与数据集中的label类别对应起来),并且第0类必须是背景类。我是要在特殊场景中识别出鸡蛋,因此我只有两个类别:
    item {
      name: "none_of_the_above"
      label: 0
      display_name: "background"
    }
    item {
      name: "egg"
      label: 1
      display_name: "egg"
    }
    
  4. 使用 creat_data.sh 脚本,根据 train.txt 和 val.txt 两个文件中记录的完整路径与labelmap中记录顶类别,生成 train_lmdb 与 val_lmdb 文件。(该脚本用到了 caffe_rootdir/scripts/creat_annoset.py,如果没有该脚本应去看一下自己的 caffe 是不是适用于 YOLO 的版本)。

经过以上三个步骤,datasets 目录下又多了新的内容:

datasets
  ├─ JPEGImages
  ├─ Annotations
  ├─ TEST
  └─ LMDB
  	  ├─ train_lmdb
  	  └─ val_lmdb

至此,完成了数据的全部准备工作。

二、网络修改

caffe 的网络非常有趣,他使用文本而非代码的形式记录整个网络结构。整个训练以及最后的测试共需要 4 个 prototxt 文件:

nets
 ├─ train.sh
 ├─ LOG
 └─  prototxt
	 ├─ yolov3_train.prototxt  # 存放训练使用的网络结构
	 ├─ yolov3_test.prototxt   # 存放训练时进行验证的网络结构(更倾向于验证集)
	 ├─ yolov3_deploy.prototxt # 存放测试使用的网络结构
	 └─ yolov3_solver.prototxt # 存放训练网络有关的参数设置

本次训练,并没有对网络结构进行调整,仅仅修改了数据的输入和最终的输出。
输入: 修改 lmdb 数据及 labelmap 的路径:

  • yolov3_train 中,将数据路径指向 train_lmdb,标注指向 labelmap_data.prototxt;
  • yolov3_test 中,将数据路径指向 val_lmdb,标注指向 labelmap_data.prototxt;

输出: yolov3 每个 anchorbox 输出(4+1+classNumber)个参数,而三层输出每层有 3 个 anchorbox,因此将:

  • 三个 Loss 层的 num_class 改为 1;(因为不需要包含背景类)
  • 三个最后的卷积层的 num_output 改为 18;( 3*(4+1+1))
    将以上修改应用于 yolov3_train、yolov3_test 与 yolov3_deploy,关于 yolov3_deploy,下一次谈测试时再详细说他,训练网络时和他无关。

三、网络参数调整

接下来对 yolov3_solver.prototxt 进行调整。该文件涉及到的是网络训练的各项超参数(比如学习率)的调整,时每次训练的核心,足以单独写一篇博客,这里引用 denny402 的博客 solver及其配置,其中每一项的修改都写的很详细,这里就不过多赘述了。

四、开始训练

运行 nets 目录下的 train.sh,即可开始训练,其内容为:

#!/bin/bash
LOG=./log/molo-train-`date +%Y-%m-%d-%H-%M`.log
caffe train --solver ./prototxt/mobilenet_yolov3_solver.prototxt --weights ./mobilenet_yolov3_deploy_iter_78000.caffemodel --gpu=6 2>&1| tee $LOG

其中, log 记录了本次训练的日志,训练完毕之后会在命令行中弹出的每一行训练信息都会被写入该文件中,可以通过该文件将训练的 loss 等变化可视化,该部分下一篇测试时再详细说明。
train 则为 caffe 的命令,后接的参数为:

  1. –solver:即为 solver.prototxt 文件的路径;
  2. –weights:即为 与训练模型(该项不是必须的)
  3. –gpu=6:使用 6 号GPU(公司比较富裕嗯……GPU好几个)
  4. 2>&1|tee $LOG :用于记录日志文件

后记

可以看出,训练开始后,可以很好的观察到 loss 的变化,通过打印出的信息,来对学习率等进行调整,使得训练可以正常进行下去。

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页