基于ROS搭建简易软件框架实现ROV水下目标跟踪(十三)–基于darknet_ros目标识别模型的训练和部署

278
0
2020年11月25日 09时50分

在目标跟踪时,摄像头提供实时的图片信息,我们需要识别出图片目标,且输出目标在图片中的位置,为后续的控制提供条件。在demo中,我是借助darknet_ros实现这一目标。当然这一模块可以替换成性能更优秀的识别算法。

      darknet_ros为yolov3在ros下的一个工具包(https://github.com/leggedrobotics/darknet_ros)。需要对yolov3的使用有所了解(https://pjreddie.com/darknet/yolo/)。例程我就不介绍了,可以在网上搜索。在此主要基于demo测试介绍我个人的使用情况,主要包括摄像头驱动、数据集制作、模型训练、模型部署。

      本文介绍使用darknet_ros进行目标识别模型的训练及部署。

一、训练模型

        这里我主要参考了博客:https://www.cnblogs.com/answerThe/p/11481564.html,同时结合yolo官网教程。在此默认已配置好GPU及CUDA等环境。训练数据集亦已准备好。

1、编译darknet(启用GPU)

        在/darknet_ros/darknet路径下找到Makefile文件并根据需求进行修改:

 

GPU=1 #如果使用GPU设置为1,CPU设置为0
CUDNN=0  #如果使用CUDNN设置为1,否则为0
OPENCV=1 #如果调用摄像头,还需要设置OPENCV为1,否则为0
OPENMP=0  #如果使用OPENMP设置为1,否则为0
DEBUG=0  #如果使用DEBUG设置为1,否则为0

 

关于ARCH值的设置,可以到NVIDIA官网查询自身显卡的算力(https://developer.nvidia.com/cuda-gpus):

 

1

 

如2080TI,则为:

 

ARCH = -gencode arch=compute_75, code=[sm_75,compute_75]

 

   编译:

 

make

 

  编译完成后可以选择进行验证,下载训练好的模型:

 

wget https://pjreddie.com/media/files/yolov3.weights

 

   运行detector:

 

./darknet detect cfg/yolov3.cfg yolov3.weights data/dog.jpg

 

若能识别图片中的物体,则证明darknet安装配置成功。

        顺便下载预训练模型权值后边备用。

 

wget https://pjreddie.com/media/files/darknet53.conv.74

 

2、配置文件

        进入路径darknet/cfg,复制yolov3-voc.cfg、voc.data,并更名为cabin_yolov3.cfg,cabin_data.data。

        ①新建cabin_name.names文件,每一行填入一类目标。如我的demo只有一类目标,所以cabin_name.names文件为

 

sea_cucumber

 

②再来看cabin_data.data文件:

 

classes= 1
train  = /home/pcl-02/darknet_ws/src/darknet_ros/darknet/cabin_data/data/ImageSets/Main/train.txt
valid  = /home/pcl-02/darknet_ws/src/darknet_ros/darknet/cabin_data/data/ImageSets/Main/val.txt
names =  cfg/cabin_name.names
backup = /home/pcl-02/darknet_ws/src/darknet_ros/darknet/cabin_data/data/weights

 

  train和valid分别为训练集和验证集路径,与上一篇数据集制作的博客相对应;

        names为新建的类别名称文件,上文已提及;

        buckup为训练出来的模型的存储路径。

       ③ 最后看cabin_yolov3.cfg文件,我们首先将训练模式打开:

 

[net]
# Testing                 ### 测试模式  
# batch=1
# subdivisions=1
# Training                ### 训练模式,每次前向的图片数目 = batch/subdivisions
batch=64
subdivisions=16
width=416               ### 网络的输入宽、高、通道数    
height=416
channels=3
momentum=0.9          ### 动量
decay=0.0005            ### 权重衰减
angle=0
saturation = 1.5          ### 饱和度 
exposure = 1.5           ### 曝光度
hue=.1                  ### 色调
learning_rate=0.001       ### 学习率
burn_in=1000            ### 学习率控制的参数
max_batches = 10000     ### 迭代次数
policy=steps             ### 学习率策略
steps=40000,45000       ### 学习率变动步长
scales=.1,.1

 

    其它诸如学习率learning_rate,迭代次数max_batches等等网上介绍很多,我就不重复了。

        然后搜索关键词yolo,一共有3处含yolo,每处需要修改2个地方。

        filters:3*(5+len(classes));

        其中:classes: 目标种类,这里以我的工程为例

        filters = 18

        classes = 1

        可修改:random = 1:原来是1,显存小改为0。(是否要多尺度输出。)

        如下:

 

[convolutional]
size=1
stride=1
pad=1
filters=18             #############
activation=linear
[yolo]
mask = 6,7,8
anchors = 10,13,  16,30,  33,23,  30,61,  62,45,  59,119,  116,90,  156,198,  373,326
classes=1             ###############
num=9
jitter=.3
ignore_thresh = .5
truth_thresh = 1
random=1             ###############

 

3、开始训练

 

./darknet detector train cfg/coco.data cfg/yolov3.cfg darknet53.conv.74 -gpus 0,1

 

  在此,利用到了上文提及的下载好的预训练模型权值darknet53.conv.74。由于我训练时使用了两张显卡,故-gpus 0,1 。

        训练时得到的模型将位于cabin_name.names中backup一项设置的路径中。按上文中的配置,模型名为cabin_yolov3.backup。训练过程中实时的权值存储于该模型文件中,当判断已经收敛时,可以终止训练,下一步使用该模型时需要将其拷贝出来并修改其文件名为cabin_yolov3.weights。

        若模型因为训练不充分导致训练的效果不佳,可以在不修改参数的前提下基于该模型文件继续训练:

 

./darknet detector train cfg/coco.data cfg/yolov3.cfg /home/pcl-02/darknet_ws/src/darknet_ros/darknet/cabin_data/data/weights/cabin_yolov3.backup -gpus 0,1

 

  关于如何判断训练已经收敛了,这里推荐一篇关于yolov3训练时输出log的文章解析:https://blog.csdn.net/gzj2013/article/details/82285511

        如下图所示:

 

2

 

 在此关注如下几项:

        256: 指示当前训练的迭代次数;

        3.784128: 是总体的 Loss(损失);

        4.452100 avg: 是平均 Loss, 这个数值应该越低越好, 一般来说, 一旦这个数值趋于稳定不下降时,就可以终止训练了;

        0.000009 rate: 代表当前的学习率, 是在.cfg文件中定义的;

        4.415291 seconds: 表示当前批次训练花费的总时间;

        32768 images:表示到目前为止, 参与训练的图片的总量。

4、测试模型

        在调试过程中,我直接用的录制的视频包进行验证,我会在下一部分的部署模型里介绍。但比较简单直接的方法可以用上文编译介绍部分中图片验证的方法。

        需要将cabin_yolov3.cfg文件中的测试模式打开。

 

[net]
# Testing
 batch=1
 subdivisions=1
# Training
#batch=64
#subdivisions=16

 

二、模型部署

        基于darknet_ros模型部署主要参照了文章:https://blog.csdn.net/qq_42145185/article/details/105730256

        输入输出如下:

 

3

 

  监听topic:/usb_cam/image_raw,格式sensor_msgs::Image,摄像头图片数据流;

        发布topic:/darknet_ros/bounding_boxes,格式darknet_ros_msgs::BoundingBoxes,目标在图片中的位置框图坐标。

1、离线调试

        完成训练后获得模型cabin_yolov3.weights。上一篇博客里介绍的数据包6.bag未参与数据集制作,即未参与模型训练,可用于离线测试。

①darknet_ros/config/ros.yaml

        此处配置监听及发布的topic的名称,需要注意监听的摄像头的数据流的topic。根据之前关于ros下USB摄像头

 

camera_reading:
  topic: /usb_cam/image_raw
  queue_size: 1

 

②darknet_ros/config/cabin_data.yaml

        此处载入训练好的模型及yolov3的配置文件。此处我将训练介绍部分的darknet下的cabin_yolov3.weights拷贝至/darknet_ros/yolo_network_config/weights;将cabin_yolov3.cfg拷贝至/darknet_ros/yolo_network_config/cfg。然后在darknet_ros/config下新建cabin_data.yaml,如下:

 

yolo_model:
  config_file:
    name: my_yolov3.cfg
  weight_file:
    name: cabin_yolov3.weights
  threshold:
    value: 0.3
  detection_classes:
    names:
      - sea_cucumeber

 

  其中threshold为置信度,大于0.3时识别为目标物。

③darknet_ros/launch/cabin_darknet_ros.launch

        拷贝darknet_ros.launch并重命名为cabin_darknet_ros.launch。修改摄像头数据的topic名称/usb_cam/image_raw以及上文提及的配置文件cabin_data.yaml路径。如下:

 

<?xml version="1.0" encoding="utf-8"?>
<launch>
  <!-- Console launch prefix -->
  <arg name="launch_prefix" default=""/>
  <arg name="image" default="/usb_cam/image_raw" />
 
  <!-- Config and weights folder. -->
  <arg name="yolo_weights_path"          default="$(find darknet_ros)/yolo_network_config/weights"/>
  <arg name="yolo_config_path"           default="$(find darknet_ros)/yolo_network_config/cfg"/>
 
  <!-- ROS and network parameter files -->
  <arg name="ros_param_file"             default="$(find darknet_ros)/config/ros.yaml"/>
  <arg name="network_param_file"         default="$(find darknet_ros)/config/cabin_data.yaml"/>
 
  <!-- Load parameters -->
  <rosparam command="load" ns="darknet_ros" file="$(arg ros_param_file)"/>
  <rosparam command="load" ns="darknet_ros" file="$(arg network_param_file)"/>
 
  <!-- Start darknet and ros wrapper -->
  <node pkg="darknet_ros" type="darknet_ros" name="darknet_ros" output="screen" launch-prefix="$(arg launch_prefix)">
    <param name="weights_path"          value="$(arg yolo_weights_path)" />
    <param name="config_path"           value="$(arg yolo_config_path)" />
    <remap from="camera/rgb/image_raw"  to="$(arg image)" />
  </node>
 
 <!--<node name="republish" type="republish" pkg="image_transport" output="screen" 	args="compressed in:=/front_camera/image_raw raw out:=/camera/image_raw" /> -->
</launch>

 

④运行

        分别在终端中启动darknet_ros及播放数据包:

 

roslaunch darknet_ros cabin_darknet_ros.launch

 

rosbag play 6.bag

 

 效果如下:

 

4

 

  从效果上看,帧率很低;但从输出的yolo的log上看,帧率有60帧(使用的是双2080TI)。

 

5

 

这就关系到前文提及的视频传输的时延。录制数据包时视频由水下的树莓派经电力载波线上传至岸上PC录制,不做处理时时延及丢帧非常明显,显然会对后面的跟踪控制部分造成影响。

2、在线部署

        离线调试成功后,这一步就非常简单了,水下摄像头接在树莓派上,岸上pc通过ssh登录到树莓派启动摄像头,此时网络中图片数据发布于/usb_cam/image_raw。

        此时就与离线调试一样了,在岸上PC启动darknet_ros即可。

发表评论

后才能评论