主要参考
https://www.ncnynl.com/archives/201904/2985.html
源码
https://github.com/dusty-nv/jetson-inference
https://github.com/dusty-nv/ros_deep_learning
第〇步,首先安装jetson-inference,再catkin_make ros_deep_learning。没什么特殊的,根据README.md一步步来就行。我下载了ResNet-18,替代了默认的googlenet。
第一步,测试一下基于ros的inference好不好使。
第1步,启动roscore
roscore
rosrun image_publisher image_publisher __name:=image_publisher ~/jetson-inference/data/images/orange_0.jpg
rosrun ros_deep_learning imagenet /imagenet/image_in:=image_publisher/image_raw _model_name:=resnet-18
rostopic echo /imagenet/classification
第二步,创建数据集。利用迁移学习(transfer learning)训练自己的数据集,基于PyTorch。(我涉及到的是图片分类问题) https://github.com/dusty-nv/jetson-inference/blob/master/docs/pytorch-collect.md
数据集的tree结构是这样的:
.
├── data
│ ├── labels.txt
│ ├── test
│ │ ├── class-A
│ │ ├── class-B
│ │ └── class-C
│ ├── train
│ │ ├── class-A
│ │ ├── class-B
│ │ └── class-C
│ └── val
│ ├── class-A
│ ├── class-B
│ └── class-C
文件夹是这样的,我的数据集名字叫scene_identify:
train存放的是训练数据,val存放的是验证集数据,test存放的是测试数据,labels.txt 中按字母排序每行一个类别名:
这就是为什么labels.txt中要按字母排序的原因:
将数据集放到 ~/jetson-inference/python/training/classification/data/ 下。
第三步,训练。因为要在控制器上部署,对实时性有要求,所以选择resnet-18进行训练。
在 ~/jetson-inference/python/training/classification/ 中打开终端,训练前,先看一下都有哪些选项,执行
python3 train.py --help
训练,需要指明模型保存路径和训练数据路径
python3 train.py --model-dir=models/scene_identifier/ data/scene_identify
如果准确度不理想,想要继续训练,就执行
python3 train.py --model-dir=models/scene_identifier/ data/scene_identify --epochs 100 --resume models/scene_identifier/model_bast.pth.tar
生成onnx,执行
python3 onnx_export.py --model-dir=models/scene_identifier/
imagenet --model=models/scene_identifier/resnet18.onnx --input_blob=input_0 --output_blob=output_0 --labels=data/scene_identify/labels.txt data/scene_identify/test/road/05.jpg test_road_05.jpg
第一次比较慢,因为要生成engine文件,之后再进行推理就快了。随便拿出一张测试集中的图片推理一下,看看效果
同时在 /scene_identifier 下又会多出一个engine文件
提前创建好一个test_output_road文件夹,然后执行下面一行命令可测试某一类文件夹中的所有测试图片:
imagenet --model=models/scene_identifier/resnet18.onnx --input_blob=input_0 --output_blob=output_0 --labels=data/scene_identify/labels.txt data/scene_identify/test/road data/test_output_road
第四步,基于ROS的推理
将/jetson-inference/python/training/classification/data/scene_identify下的labels.txt 和 /jetson-inference/python/training/classification/models/scene_identifier下的resnet18.onnx 放到/home下
修改/home/nvidia/ros_workspace/src/ros_deep_learning/launch/imagenet.ros1.launch文件
<launch>
<!-- IMAGENET -->
<arg name="model_name" default="resnet-18"/>
<arg name="model_path" default="/home/nvidia/resnet18.onnx"/>
<arg name="prototxt_path" default=""/>
<arg name="class_labels_path" default="/home/nvidia/labels.txt"/>
<arg name="input_blob" default="input_0"/>
<arg name="output_blob" default="output_0"/>
<node pkg="ros_deep_learning" type="imagenet" name="imagenet" output="screen">
<remap from="/imagenet/image_in" to="/camera/image"/>
<param name="model_name" value="$(arg model_name)"/>
<param name="model_path" value="$(arg model_path)"/>
<param name="prototxt_path" value="$(arg prototxt_path)"/>
<param name="class_labels_path" value="$(arg class_labels_path)"/>
<param name="input_blob" value="$(arg input_blob)"/>
<param name="output_blob" value="$(arg output_blob)"/>
</node>
<!-- VIDEO OUTPUT -->
<arg name="output" default="display://0"/>
<arg name="output_codec" default="unknown"/>
<arg name="output_bitrate" default="0"/>
<include file="$(find ros_deep_learning)/launch/video_output.ros1.launch">
<arg name="topic" value="/imagenet/overlay"/>
<arg name="output" value="$(arg output)"/>
<arg name="output_codec" value="$(arg output_codec)"/>
<arg name="output_bitrate" value="$(arg output_bitrate)"/>
</include>
</launch>
解释一下其中一些行都是什么意思:
<!-- IMAGENET -->中
<arg name="model_path" default="/home/nvidia/resnet18.onnx"/>
这一行是指出onnx文件的路径,我把它复制出来,放在了根目录下
<arg name="prototxt_path" default=""/>
这一行用不到
<arg name="class_labels_path" default="/home/nvidia/labels.txt"/>
这一行必须有,是分类的labels.txt文件,也复制出来放到和onnx文件同一目录下
<arg name="input_blob" default="input_0"/>
这个input_blob是之前用imagenet可执行文件做推理时起的名字,input_0,必须是这个名字
<arg name="output_blob" default="output_0"/>
同理
<remap from="/imagenet/image_in" to="/camera/image"/>
这一行是订阅的话题名
<!-- VIDEO OUTPUT -->中
<arg name="output" default="display://0"/>
作者README.md中说这是创建一个GUI界面,显示推理结果,在左上角
请忽略车道线识别结果,手头没有原始.bag了,就拿车道线识别结果实验一下
$ roslaunch ros_deep_learning imagenet.ros1.launch