3. 目标检测模型训练教程
-
目标检测模型训练教程
通过本教程,用户能够了解或掌握:
- 训练数据到tfrecord的转换过程
- 目标检测算法的训练方法
- 目标检测算法的后处理方法
本次实验的流程如下图所示:
Note:
1.本次实验中各步骤均通过提前编写好的python文件实现,详细实现方式请参考对应.py文件。
2.Linux用户需要进入docker,并在docker中执行本教程的所有步骤。docker的进入方法如下:sudo docker start Rainbuilder sudo docker exec -ti Rainbuilder bash
SSD目标检测框架概述
深度学习算法在目标检测领域已有比较成熟的应用,主要框架分为One-Shot Detector和Two-Shot Detector两种。One-Shot,是指只需一段网络计算即可完成目标物体的检测。One-Shot相对于Two-Shot在基本保持相同精度的情况下,速度大幅提升,更加适用于工业级应用。
本教程中从采用经典的Single-Shot Multibox Detector(SSD),具体原理可以参考原论文。
SSD网络主要由主干网络(特征提取网络)和多尺度的检测分支两部分组成。
最初SSD的特征提取网络使用了VGG-16神经网络,关于VGG-16的网络结构请参考原论文。VGG网络通过嵌套卷积层(CONV)+池化层(Pooling)完成特征提取,随着网络层数的加深,特征图尺寸越来越小。不同层的特征图能代表不同尺度下的语义信息,浅层特征图包含更多局部特征,更偏向于对于细节pattern的描述,适合小尺度目标的检测。深层的特征捕捉更抽象化的全局信息,适合对大尺度目标的检测。
另外,SSD包含不同尺度的特征上的检测分支,每个检测分支负责预测该尺度上目标框的类别和位置信息。检测分支采用Anchors实现实际的预测操作,其中anchor定义了一系列基准检测框,SSD解决的是如何对于基准框进行微调来计算最终的高精度检测结果。
关于SSD中Anchors的概念可以参考下图:
上图显示了SSD检测图中的猫(蓝框)和狗(红框)的过程,其中不同颜色代表我们上面提到的类别。由于猫和狗在图中的尺寸不同,SSD中使用不同的分支完成对于猫和狗的检测。b图代表8x8的特征图对应的分支,c图代表4x4的特征图分支。具体来说,b层位于浅层,对应于猫的检测,c层位于深层,对应于狗的检测。b、c图中的虚线框代表Anchor基准框,基准框有着不同的尺度和长宽比,以保证对于各种尺寸和形状物体的匹配。基于匹配的Anchor,SSD通过计算每个anchor负责区域的位置偏差量$\Delta(cx, cy, w, h)$和对应的类别置信度$(c_1, c_2, ..., c_p)$,最终实现对于物体的检测。接下来,本教程会逐步骤介绍如何基于SSD训练一个目标检测模型。
1. 测试数据集结构与tfrecoard格式转换
1.1 原理介绍
深度神经网络需要提供大量数据进行模型的学习和优化。本次实验中使用20张图片作为训练数据,帮助用户了解算法模型的训练过程。
本次实验中,标注文件采用如下格式,用户可以在
/Hands_on/algorithm/imagetxt/img_label.txt
中看到具体的描述:[图像名] [物体数量] [物体1]:[物体1的label_id] [2(预定义字段)] [左上角x坐标] [y坐标] [右下角x坐标] [y坐标]
具体如下:
1530697831_1.jpg 1 face:1 2 414.0 207.0 536.0 304.0 1530697831_2.jpg 1 face:1 2 2461.224 985.714 2981.633 1695.918 1530697831_3.jpg 1 face:1 2 3746.939 1224.49 4573.469 1897.959 1530697831_4.jpg 1 face:1 2 155.0 113.0 282.0 278.0 1530697831_5.jpg 1 face:1 2 1910.204 1518.367 3618.367 3336.735 1530697831_6.jpg 1 face:1 2 2442.857 1126.531 3704.082 2014.286 1530697831_7.jpg 1 face:1 2 2473.469 1028.571 3936.735 2387.755
标注文件中显示图片名称,目标物体种类,在对应图片中目标的位置。用户可以方便地制作属于自己的图片数据集进行算法模型的训练。
TensorFlow为了实现高效率的模型训练,采用TFRecord文件格式进行数据的读写操作。TFRecords是一种TensorFlow的内定标准文件格式,其实质是二进制文件,遵循protocol buffer(PB)协议。(Protocol Buffer是谷歌的一种数据交换的格式,它独立于语言,独立于平台)。tfrecords文件的后缀一般为tfrecord。TFRecords文件方便复制和移动,能够很好的利用内存,无需单独标记文件,适用于大量数据的顺序读取,是TensorFlow“从文件里读取数据”的一种官方推荐方法
因此,本实现中首先需要将数据和标注转化为tfrecord文件。
1.2 操作流程
在
/Hands_on/algorithm
下,通过单击右键选择Open in Terminal
打开终端,并运行如下代码:./1_run_convert.sh
即可执行脚本,进行数据格式的转换。
可以通过
cat 1_run_convert.sh
来浏览脚本中的命令,脚本内容如下。python tf_convert_data.py #调用py文件 --dataset_name=test_release #数据库名称 --dataset_dir=../imagetxt/ #输入路径 --output_dir=./data_conversion #输出路径 --shuffle=True
2. 进行神经网络训练
2.1 原理介绍
完成训练集数据处理、图像预处理函数定义和神经网络函数定义后,可以通过运行
train_ssd_network.py
对已有的网络进行训练。在以20张图片为训练集的情况下,使用CPU进行模型训练可能需要3-4个小时才能收敛损失函数。通常情况下,当loss值下降到一定程度,不继续下降之后,模型已经收敛,训练完成。
训练完成后,在
./log_test/
文件夹下会有四个文件,分别为:- checkpoint:记录训练过程中中间节点保存的模型名称
- model-*.data:保存模型参数值。
- model-*.index:保存变量值和图形结构对应关系。
- model-*.meta: 保存图结构。
这四个文件将会在接下来的实验中使用,同时TensorFlow也可以适用这些文件来读取模型。
2.2 操作流程
在
/Hands_on/algorithm
目录中运行如下代码。./2_run_training.sh
即可执行脚本,进行模型的训练。可以通过
cat 2_run_training.sh
来浏览脚本中的代码,代码内容如下。DATASET_DIR=./ #指定数据库路径 TRAIN_DIR=./logs_test/ #指定保留checkpoint文件的路径 CKPT=./model/ssd_5b #加载预训练模型 DATASET_NAME=test_release #明确TF格式数据库的名称 if [ ! -d ${TRAIN_DIR} ]; then mkdir ${TRAIN_DIR} fi cp ${DATASET_DIR}/${DATASET_NAME}.json ${TRAIN_DIR}/image.json cp ${DATASET_DIR}/${DATASET_NAME}.INFO ${TRAIN_DIR}/image.INFO python -u train_ssd_network.py \ --gpus=1 \ #通过指定id来使用特定的GPU进行计算 --num_clones=1 \ #训练所使用的GPU数量 --train_dir=${TRAIN_DIR} \ --dataset_dir=${DATASET_DIR} \ --dataset_name=test_release \ --dataset_split_name=train \ --model_name=ssd_KYnet_v3_5b \ #模型文件 --save_summaries_secs=600 \ --save_interval_secs=1200 \ #存储模型文件的间隔时间 --weight_decay=0.00001 \ #正则项系数 --optimizer=adam \ --learning_rate=0.005 \ #起始学习速率 --learning_rate_decay_factor=0.95 \ #学习率的调整幅度 --batch_size=20 \ --debug_type=True \ --num_epochs_per_decay=100.0 #调整学习率变化的步数间隔
部分参数说明:
-
weight_decay
: 正则项系数,通常小于1。正则项通过将网络参数的L2_norm加入最终loss中来抑制过拟合现象,通过调整该系数使得正则项起到抑制作用,但是又不会过大地影响问题本身的loss。通常来说,正则项loss为总loss的1/5~1/10较为常见。 -
optimizer
: 优化器选择,可选项包括adadelta
,adagrad
,adam
,ftrl
,momentum
,sgd
和rmsprop
。不同优化器的网络参数更新方式和学习率调整策略有所不同,本实验中建议使用adam
。 -
learning_rate
: 起始学习率。起始学习率过大,可能导致NaN数值错误。起始学习率过小,可能导致收敛过慢。 -
learning_rate_decay_factor
: 每次学习率调整时的调整幅度,通常<1以保证learning_rate逐渐减小。 -
batch_size
: 训练过程中,通常将训练数据拆分成多个data batch,而每个batch中样本的数量称为batch_size, 一般来说在显存允许的情况下,batch_size越大越好。
其中,
learning_rate
、learning_rate_decay_factor
、learning_rate
这三个参数定义了学习率的更新规则。三者关系如下:每隔 num_epochs_per_decay 步,learning_rate更新为learning_rate_decay_factor和当前learning_rate的乘积。注:更多具体的参数用户可以通过
gedit train_ssd_network.py
进行查看。执行该脚本后,终端打印如下:
2014-05-13 10:41:35.929852: I tensorflow/core/platform/cpu_feature_guard.cc:141] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX AVX2 INFO:tensorflow:Running local_init_op. INFO:tensorflow:Done running local_init_op. INFO:tensorflow:Starting Session. INFO:tensorflow:Saving checkpoint to path ./logs_test/model.ckpt INFO:tensorflow:Starting Queues. INFO:tensorflow:global_step/sec: 0 INFO:tensorflow:Recording summary at step 0. INFO:tensorflow:global step 10: loss = 966542.6875 (11.725 sec/step) INFO:tensorflow:global step 20: loss = 161.3684 (12.124 sec/step) INFO:tensorflow:global step 30: loss = 56.6930 (9.073 sec/step) INFO:tensorflow:global step 40: loss = 60.9939 (9.895 sec/step) INFO:tensorflow:global step 50: loss = 40.8773 (10.166 sec/step) INFO:tensorflow:global_step/sec: 0.0900846 INFO:tensorflow:Recording summary at step 55. INFO:tensorflow:global step 60: loss = 32.6265 (9.873 sec/step)INFO:tensorflow:global step 70: loss = 29.1204 (9.INFO:tensorflow:global step 80: loss = 21.6570 (9.INFO:tensorflow:global step 90: loss = 21.9894 (10INFO:tensorflow:global step 100: loss = 17.8053 (1INFO:tensorflow:global
3. 训练结果验证
3.1 原理介绍
本步骤的目标是使用训练好的模型文件对图片进行推理从而得到人脸的位置信息。本步骤中需要使用一个常用的图像处理库
OpenCV
, 关于OpenCV
的介绍请参考 https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_setup/py_intro/py_intro.html验证过程由以下几步构成:
- 输入图像 --> 导入内存
- 图像前处理 --> 计算网络输入
- 网络前向推演 --> 网络输出feature map
- 模型后处理 --> 根据FeatureMap计算最终检测结果
其中后处理步骤包含以下子步骤:
- BoundingBox Decoding
- 根据Score排序
- 非极大值抑制(NMS)
3.2 操作流程
在
/Hands_on/algorithm
目录中运行如下代码:./3_run_test.sh
可以通过
cat 3_run_test.sh
来浏览脚本中的命令。python run_single_image.py \ --_model_key ssd_KYnet_v3_5b \ --_model_path logs_test \ --_img_path ./imagetxt/1530697831_1.jpg \ --_out_img_path ./test.jpg
可以发现该脚本调用了
run_single_image.py
文件,并向其传入了三个参数,通过_model_key
调用名称为ssd_KYnet_v3_5b
的模型,在路径log_test
中存放着该模型的checkpoint文件,图像输入的路径为_img_path
,用户可以通过修改输入图像路径,选择其他图像进行测试。运行程序之后在终端中显示的结果应为:
充分训练得到的模型,其检测结果应如下图所示:
4. 生成后处理参数
本步骤的目的在于导出预设的anchor参数,具体请参考课程中"Object Detection"中的"Anchors"部分。导出的数据以二进制文件的形式进行存储,用于之后RbRuntime运行的后处理函数中。注:用户可以定义自己的后处理参数传递模式。如果用户使用自定义的后处理操作,本步骤可以跳过。
在
/Hands_on/algorithm
目录中运行如下命令:./4_gen_PostParam.sh
通过
cat 4_gen_PostParam.sh
命令打开脚本后,可以看到脚本内的内容如下:python post_gen.py \ #调用py文件 ssd_KYnet_v3_5b \ #声明网络结构 ./post_param #输出路径
运行指令后,可以在
post_param
文件夹下看到生成的后处理参数。
5. 导出推演图
本步骤的目的在于除去推演中不需要的于训练相关的节点,只保留核心的运算节点,简化模型解析复杂度。在
/algotirhm
目录中运行如下代码:./5_run_truncate_model.sh
通过
cat 5_run_truncate_model.sh
命令打开脚本后,可以看到脚本内的内容如下:python export_inference_graph.py \ #调用py文件 ssd_KYnet_v3_5b \ ./logs_test \ #输入路径 ./inference_model #输出路径
运行该指令后,能在
inference_model
文件夹中看到生成的模型推演图文件。
-
@Corerain 大佬能不能将人工智能应用社区的手动标框数据集的imagetxt可以自己导出,自己处理太费事了
-
@Corerain InvalidArgumentError (see above for traceback): Assign requires shapes of both tensors to match. lhs shape= [24] rhs shape= [8]
[[Node: save/Assign_9 = Assign[T=DT_FLOAT, _class=["loc:@ssd_KYnet_v2/block10_box/conv_cls/biases"], use_locking=true, validate_shape=true, _device="/job:localhost/replica:0/task:0/device:CPU:0"](ssd_KYnet_v2/block10_box/conv_cls/biases, save/RestoreV2_9)]]
-
此回复已被删除!
-
知识小贴士:
Docker 我们现在使用方式是为了方便可移植一些系统环境,以便我们可以不用花费太多的时间进行环境的搭建工作,同时我们也能保证所有使用这个Docker的用户所用的环境是相同的,从而避免出现问题、无法复现导致无法Debug的情况。
Linux 系统下 Docker 使用方式:- 获取/加载镜像
获取镜像方式有两种,其一,从Docker Hub上 pull 下想要的镜像;其二,其他情况下保存出来的镜像文件,一般形如 Image_name.tar。
第一种获取/加载方式:
sudo docker pull <repository>:<tag>
第二种获取/加载方式:
sudo docker load < Image_name.tar
- 查看系统内的镜像
sudo docker images
- 用镜像生成容器
sudo docker run --name <container name> --network <host or others> --privileged=true -v <host shared folder>:<container folder> -dit <repository>:<tag> /bin/bash
- 查看系统内生成的容器
sudo docker ps -a
- 启动、运行系统内的某个容器
第一次启动容器方式:
sudo docker start <container name>
重新启动容器方式:
sudo docker restart <container name>
运行容器方式:
sudo docker exec -it <container name> /bin/bash
- 系统与容器间的数据拷贝:
sudo docker cp <host file or dir> <container name>:<container absolute path of file or dir>
或者
sudo docker cp <container name>:<container absolute path of file or dir> <host file or dir>
- 退出某个容器:
exit
赠送链接一枚:https://www.runoob.com/docker/docker-container-usage.html
- 获取/加载镜像
-
@Frank
我们的论坛中提供了两种不同的使用方法,这两种方法对应的环境都已经预装了tensorflow环境。
第一种是使用virtualbox来打开一个名为Corerain Lab V3的系统镜像,这个镜像中已经包含了TensorFlow环境和Rainbuilder编译工具,你可以直接在这个系统镜像中按着步骤进行实验。
第二种是我们为linux用户提供了docker,docker中也已经预置了tensorflow的环境,你可以进入docker后,在docker中使用命令行进行实验。(在教程中docker的名字被命名为Rainbuilder)
因为在安装docker的教程中,我们使用了docker -v的命令建立起了主机workspace文件夹与docker的映射,因此可以在docker中直接访问主机的workspace文件夹,但是相关的脚本需要在docker中执行。
-
能不能再写一个详细的gpu安装办法呀,我进了docker以后,运行那个sh文件提示:no moudel named tensorflow,这个怎么解决啊?可是我在终端打开python调用tensorflow是可以的啊@Corerain
-
@Frank 我们提供的docker Rainbuilder已经包含了tensorflow环境,因此只需要按照如下方式进入docker,并在docker的
/workspace/Hands_on
下执行相关脚本即可。sudo docker start Rainbuilder sudo docker exec -ti Rainbuilde bash
由于docker和主机已经建立了双方workspace文件的映射,因此在主机中的workspace进行文件的移动、删除等操作,都会同步映射到docker的workspace中来
-
教一教别人怎么装了docker之后再运行代码呗,搞了好久查了好多都没搞明白