自助收款机项目记录与总结

研一主要做了两件事情,一是收款机项目,二是6Dpose估计的比赛,这两块做的都不好。
我是跨专业进来的,考完研之后学了一点吴恩达的网课,来了之后就直接安排进入项目了,

收款机项目


过程总览

先是做的tensorRT的优化,然后是边缘设备的移植


tensorRT

先说结果,没搞出来,用的剪枝模型代替

tensorRT需要将权重文件转化为ONNX格式,然后再将ONNX转换成trt格式。

在接手tensorrt的处理后,想通过之前的同学提供的 model转onnx 和 onnx转trt 程序对剪枝后的yolo进行处理,第一步model转onnx顺利进行,但到了第二部转trt发现无法将onnx序列化。

model转onnx问题

起初,认为是 onnx转trt 程序有问题,之后查阅网上资料,但发现网上的PyTorch框架转trt的程序都大同小异,几乎都一样,此时,怀疑是 model转onnx 程序转出来的 onnx 文件有问题。

为了验证怀疑是否正确,从网上下载了一个训练mnist的onnx文件,发现可成功转为trt文件。

初步认为是 model转onnx 程序有问题,但为了巩固此结论,将官方的yolov3.onnx文件拿来试验,但是运行报错:
image.png
经搜索,是batch_size过大的问题,官方的batch_size是64,如图
自助收款机项目记录与总结_第1张图片
而我们平时用的batch_size是1,机器支持不起来这个大的batch_size,此时无法验证官方onnx是否能转rtr。

此时我换了一种方法,通过Nerotn可视化来比较官方onnx和我们自己转出来的onnx的差别,差别如下:
我们自己的onnx(用的原版cfg和best.pt, 是未剪枝的,所以所用的资源是和官方相同的)的最后几层:

自助收款机项目记录与总结_第2张图片
官方的onnx的最后几层如下:
自助收款机项目记录与总结_第3张图片
初步断定是 model转onnx程序出了问题,开始查阅资料,但是此时又发现,PyTorch框架的写法也基本都是一样的,其他人都可顺利转换至最后。
尝试用官方的tensorrt写的解析器转换model,但是报错(python2.7版本,直接复制过来的,只修改了读取cfg和weight的地址),错误尚未找到解决方法。

此时,问题开始焦灼,对于如何解决问题,现有一些几个思路

  1. 通读官方tensorrt写的关于yolov3的解析器(python2.7版本,近800行),然后对其进行改进(改进后不知和框架直接写的能有多少差别,时间成本高,可能收益也不好)
  2. 直接使用官方的trt来加速,如果对 未剪枝的yolo加速后的效果 比 剪枝后但未加速的yolo 好,那或许可能采用这种方法
  3. 用其他框架来转换,如tensorflow,tensorflow框架是不需要转onnx的,可直接用tensorrt加速推理,但是也可能遇到新的tensorflow难题(网上多是用tensorrt加速PyTorch框架写的yolo,一方面说明PyTorch框架的优越性,一方面是否也说明其他框架在tensorrt加速方面表现没有PyTorch好?)

为了解决问题,我找了个新的开源项目,作者是在官方转换sample(手写解析器)上进行改动的,添加了1_batch_size和multi_size的代码,因此上个周的64_batch_size无法处理得问题就解决了。

作者的cfg和weights解析器和官方相同,但这次我找到了读取cfg文件报错的原因,就是剪枝的cfg文件最后少了一个\n。

项目1地址:https://github.com/Cw-zero/TensorRT_yolo3_module

这个项目带来的价值:解决了官方代码只能处理64_batch_size, 无法处理1_batch_size的问题

利用该项目的代码,可完整将原版和剪枝的cfg和weights -> onnx ->trt(利用的是官方手写yolo解析器相关代码,不是用的Pytorch框架)

对剪枝模型的加速 :

之后,试了一下这个项目的tensorrt推理,没有计算速度,只是检测能否顺利运行,结果是运行蛮顺利的。
下一步,将该项目的利用tensorrt推理的代码移植到了剪枝的yolo上,发现竟然画不出任何bounding_box
然后将原版yolo的trt也放到用于处理剪枝的代码中,虽然精度不高但是能顺利画出bounding_box。
输出剪枝的trt推导出的detection,发现全都是0,而原版的trt推导出来的不是。
回头检查问题,发现剪枝的onnx可视化后,有几个数据是独立于整个框架的,仔细观察剪枝的cfg,发现其中有maxpool层,然而原版yolo中并没有maxpool层,
所以官方给出的解析器也无法处理maxpool层,只是跳过了。

出现这种情况的问题在于我不了解该剪枝算法,我原本以为只是减掉了几个层,又合并了几个层,没有加额外的其它层,这时开始寻找新的方法。

两个思路:
一、用Pytorch框架转换onnx,然后又项目1的代码转trt(之所以不用pytorch一口气转,是因为tensorrt5.0不支持upsample层,而无论是剪枝还是原版yolo,都要用到upsample层,官方的没用框架的代码可以很好的解析upsample层,如果要用pytorch那么就得自己定义upsample层解析),之前失败的原因,经过这几天的查阅,发现确实是Pytorch版本的问题,tensorrt5.0出的时候是对应的Pytorch0.4.1的,从0.4.1到1.0,Pytroch中带的ONNX已经升级了,tensorrt未必能解读新版本的ONNX。
但相对应的问题有是:需要装双版本cuda,现安装版本是10.0,而Pytorch0.4.1要求的是cuda9.0。

二、找新的剪枝模型,和原版结构相同的那种
项目2地址:https://github.com/Lam1360/YOLOv3-model-pruning
找到如上模型,原版的剪枝,层数更少,没有maxpool层,而且还是检测手的,已经训练好可以直接使用。
相对应的问题:需要在python3.6环境运行,Pytorch1.0及以上版本

一开始先以第一个为执行方案,先在自己电脑的虚拟机中安装pytorch0.4.1和cuda,但是cuda安装失败了,经查阅,发现虚拟机中无法安装cuda, 硬安装的方法也有,但很麻烦,而装双版本cuda也很麻烦,所以先执行第二个思路试试

将项目2的cgf和pth文件放到项目1的转换代码中,顺利的转出onnx和trt文件,可视化onnx文件,发现这次没有奇怪的层和脱离框架的数据,很欣慰。
然后建立python3.6的虚拟环境,安装pytorch时出现Bug,发现服务器cuda10.0的软连接没有了,可能是之前换pytorch版本时搞坏了

这个周在进行项目2的tensorrt加速,换了多种方法,改动shape也无法正确用tensorrt推理,折腾多天无果。后来看了下这个剪枝模型参考的论文,发现与原版相比,减掉了很多CNN的channel,可能这就是我使用的tensorrt加速代码无法正常运行的原因,这个代码是针对原版yolo写的,或许对层进行了改动会无法识别?
在陷入困难之际,决定试试项目2在tx2上的速度,发现最高能达到9 fps,所以之后就没有继续搞tensorrt了


边缘设备

在这个项目的时间里,大部分时间都是在搞移植,一共接触了四块板子:Nano,TX1,TX2,rk3399pro。其中前三块板子还好,支持pytorch模型(我们的代码就是pytorch写的),但是第四块就有点拉跨了,而且公司那边还就想用第四块(便宜,有NPU,计算速度稍快)。

公司那边提出用rk3399pro,经调研,发现当其GPU和NPU同时运行时,速度能达到Nano的二倍左右,然后用新的模型在Nano上试了一下,能达到4帧,如果3399的效果真的能达到Nano二倍,或许可以试试,测试了下,rk3399 pro是可以运行tensorflow框架的yolo的,能跑到7帧左右,然后就开始着手模型转换的工作。

问题就在于第四块支持的框架有限(仅部分tensorflow,caffe,darknet,不支持pytorch)。

一开始的想法是,想直接用网上的代码将pytorch框架转换成tensorflow框架,经查阅后,发现有两种方式:

一、pytorch -> onnx -> keras -> tensorflow
由于之前研究tensorRT的时候用到了很多的onnx文件,而且现在还保存的,就先尝试了这种方法。
这是该方法用到的代码来源:https://github.com/nerox8664/onnx2keras
但是转换时发现了问题,就是只能转换layer,到了转换weight的时候就会卡住,keras model转换不出来
报错代码:TypeError: unhashable type:‘google.protobuf.pyext._message.RepeatedScalarContainer’
之后尝试更换多个protobuf版本,发现还是不可以,目前认为可能是onnx文件有些问题,但是还没找到解决的方法。就先尝试了另一种方法

二、pytorch -> keras -> tensorflow
这个方法用到的代码来源:https://github.com/nerox8664/pytorch2keras
查看更多的资料,发现这个代码并不支持yolo层的转换,所以这个方法也不能用。
解决问题的思路

  1. 用tensorflow复现剪枝和微调的代码(我们现在正在尝试,但是我觉得以我们现在的水平,不太可能)
  2. 在网上找一些tensorflow的yolo剪枝代码(这是我最开始尝试的方法,但是没找到,下个周再仔细看看)

尝试了使用ONNX模型和Darknet模型来让之前的剪枝yolo能在rk3399 pro上运行,遇到的问题:
ONNX模型:
将之前搞tensorrt的时候用的onnx放到rk3399提供的 onnx转rknn 代码中转换,转出来不能用。剪枝和原版的都试过了,判断不是剪枝的问题,原版的也不能用,网上说这个rk3399只对tensorflow有完整支持,而对其他模型支持不全,这可能是个原因。
Darknet框架:
我之前使用的权重文件是.pth文件,Darknet需要.weights文件,我是用之前代码自带的转换函数来转换:
model = Darknet(‘prune_yolov3-hand.cfg’)
weights = ‘prune_yolov3_ckpt.pth’
model.load_state_dict(torch.load(weights, map_location=‘cpu’))
model.save_darknet_weights(path=‘converted.weights’)
但是也报错
IndexError: index 1 is out of range
还没找到那里出了问题,这些转换看起来不是怎么靠谱

尝试了对yolo剪掉用不掉的小尺度来提高速度,后来发现无论只保留那个尺度,都能检测出近距离和远距离的手
自助收款机项目记录与总结_第4张图片
自助收款机项目记录与总结_第5张图片
这两张手分别是只保留大尺度和只保留小尺度检测出来的,按理来讲不应该这样,但是运行起来三种尺度除了最大框的大小以外几乎没什么区别。

开始着手Darknet框架的处理,主要使用到了两个网站的内容:
ToyBrick社区:http://t.rock-chips.com/forum.php?mod=viewthread&tid=184
yolov3官网:https://pjreddie.com/darknet/train-cifar/

过程:

  1. 一开始直接对cfg进行改动,然后使用原版的weights,在pytorch框架下的yolov3是可以运行这样的文件并进行预测的。但是在Darknet框架中,这样没有用。
  2. 后来使用原版的weights,对cfg进行修改,然后提取相应的卷积层参数进行训练,这里只用了3张图片epoch了8次,训练的classes只有3种,只为尝试该思路的可行性。
  3. 成功训练之后,将其放到rk3399的darknet网络中,rknn的inference能顺利执行,并输出最后卷积层输出的参数。
  4. 之后对inference之后的数据维度处理进行了调整,使用图片进行测试,可以执行完检测程序(但是是没有检测效果的),证明darknet的修改基本没有什么问题了。
  5. 对视频进行测试,能够达到10 FPS

先是训练了单尺度的yolov3,但是效果奇差,根本检测不出东西来;现在在训完整的单分类yolov3,如果效果好,就提取前82层(单尺度)的网络再试试。

完整的尺度的yolov3训练出来了,但是仍然发现什么都检测不到,一开始以为是训练的不好,后来将权重放到服务器上,发现可以正常预测,精度还可以。
因此,回头看了下官方提供的yolo_demo的代码,感觉他写的不太对,训练的单尺度权重放上去什么都跑不出来,object_threshold计算用了一种没见过的公式,跟之前看过的一些yolov3源码不太一样:
obj_thresh = -np.log(1/OBJ_THRESH - 1)
之后尝试用tensorflow的代码,但是因为对tensorflow不够了解,改起来很吃力,就尝试在服务器的代码中,将Pytorch实现的部分用Numpy来写,但是我对这两个也不是很熟,改起来比较慢,比较花费时间。

将Pytorch模型改为Numpy的工作已经完成了,但是预测的效果还是很差

自助收款机项目记录与总结_第6张图片

自助收款机项目记录与总结_第7张图片

那么大的模型想要在小的板子上运行,必然是要量化的,将文件大小从200+MB压缩到50+MB,必然会损失一些精度。而我遇到的问题是,检测不出任何的手,精度损失巨大,如何去处理这个量化损失精度问题就不懂了,这个交给专业移植人士了。

总结
刚来的时候什么也不懂,也没能对这个项目面临的问题提出一些有效的方法,所以感觉在这一块收获不是很大,但是作为一个入门我感觉还是蛮好的,如果是已经学了半年,而且一开始就是我们处理的话,我感觉是能做出些好的效果的。
在这个项目中获得的提升:

  1. 对yolov3的代码的理解加深
  2. 对于神经网络的检测效果有一定了解,在这个项目里跟手相似的颜色都很用被误检,且背景颜色对检测效果也有较大影响,色差越大越好
  3. 熟悉各个板子的刷机和环境配置 ( 汗 - -!)
  4. 熟悉了numpy、darknet的部分使用方法

需求:基于单目RGB摄像头和超市扫码器实现自助收银的需求,摄像头位于扫码器的上方,客户使用时将购物物品放于桌上的指定位置,然后依次拿起物品经过扫码器,然后放到桌上另一端的指定位置,设计算法判断该过程有无漏扫、偷拿等行为。

整体流程:摄像头监控一个长桌,摄像头的视野对应长桌被分为三个部分,一部分是未扫描商品放置区,一部分是执行商品扫描区域,一部分是扫描后的商品放置区。该过程执行过程中,有可能商品直接从一个放置区到另一个放置区,没经过扫码区,这样是违规的会触发警报。还有可能从一个放置区拿起,然后直接出了摄像头视野,这也是违法的,还有一些其他的逻辑判断是否违法,而我负责的工作是目标检测算法的训练和边缘设备的移植。

我的工作:一开始是算法的改动,使用检测算法检测手里是否存在物品,我们自己做了一些数据集然后标注,使用的是yolov3算法,然后利用TensorRT进行加速,但是原版的yolov3加速后在边缘设备上还是达不到要求,每秒只有不到3帧的速度,之后又在在github上找了剪枝的yolov3,但是使用TensorRT加速这个剪枝代码后,检测不到任何bounding_box,分析了原版的yolov3和剪枝的yolov3的网络结构之后,发现剪枝的版本里面有原版没有的maxpool层,而TensorRT需要将原本的权重文件转换成ONNX文件,ONNX当时并不支持maxpool层,所以不能用TensorRT加速。这个时候TensorRT加速原版能到3帧,剪枝的yolov3能到4帧,我们就换了设备,换了之后发现剪枝的代码是可以在tx2上达到9帧的,能满足实时的要求,所以此时暂时选用这个方案。

但是公司嫌tx2太贵了,又搞了个rk3399pro板子来让我们做,但是这个板子不支持pytorch模型,只支持tensorflow,而且还支持的不完整,当时网上并没有tensorflow版本的剪枝带啊吗,所以我尝试了一些pytorch权重文件转tensorflow的方法,都不行。不过这个板子支持Darknet框架,我就配上剪枝yolov3的网络配置文件,使用Darknet来训练出Darknet格式的权重文件,然后把pytorch的输出处理代码改成了Numpy的,但是速度不行,只有4帧。然后我分析了一下检测的结果还有网络的结构,发现在当前场景下,手和摄像头的距离基本是固定的,而yolov3有三个检测尺度,然后我将两个尺度砍掉了,再训练,在服务器上效果相同,在rk3399pro上速度能达到10帧。但是又出现了新的问题,同样的代码,原本的权重文件在服务器上效果不错,但是将这个权重文件使用设备提供的代码进行压缩,在边缘设备上却检测效果很差。然后查了下量化的文件,权重大小从200MB压缩到了50MB,实在是不能用,这个量化算法我解决不了,当时找了个专门负责移植的公司,打算让他们来做量化。

后来这个公司用这个项目申请青岛创新项目,只拿了第三名,第一第二被海尔海信拿走了,然后资金不够了,就没继续做了。

你可能感兴趣的:(Detection,项目经验)