更正一下!如果是针对Atlas500开发,请不要使用mind studio,请直接使用omg在命令行转化模型,mind studio不支持atlas500,不支持某些算子,所以如果使用mind studio转化,可能转化没问题,但是在atlas500上跑起来就会报错
纵观过去写的文章,我觉得最有价值的文章是元学习系列和分位数回归,以分位数回归为例,我记得写的时候网上还没多少中文的资料,只能谷歌一些英文的博客,加上上课的课件才写出来的,最后我觉得出来的文章还是能把分位数回归的思想说清楚的,像这种可能比较小众但是能确确实实帮到其他人的文章,对我来说价值才是最大的,而这次写的关于Atlas500的模型转化以及算子的修改也是如此。
首先来谈一下模型如何进行转化,第一步当然是要保存tensorflow模型,必须是保存为pb格式,然后,模型的转化有两种方法,一个是利用华为提供的mind studio,在ide进行转化,这种方式的优点在于转化报错的时候,如果是因为算子不支持的原因,可以在ide直接看清楚是哪些算子不支持,但是要安装mind studio也是比较麻烦的一件事,除此之外还可以在安装Atlas500 DDK后,用命令对模型进行转化,具体可看相关的文档,我觉得两者很难说谁更好,只是如果在服务器上进行模型转化就只能用后者了。
接下来我们看一下模型转化的详细过程:
主要包含五个步骤,其中往往在解析模型和生成算子离线结构的过程中,因为算子不支持的问题而报错。
接下来看看如何用mind studio转化模型。首先在chrome浏览器打开mind studio,新建项目(new project),导入我们的项目:
点击tool,选择convert model转化离线模型:
顺利的话即可成功转化:
可是如果那么容易就不会有这篇文章了,所以接下来就看一下会在哪里出错,以及有什么解决思路。
当在解析模型的过程中报错,mind studio会直接显示出有哪些算子是不支持的:
这里的解决思路比较简单,根据OperatorName定位出算子在模型中的位置,或者说直接在网上查找算子对应什么函数,比如LeakyRelu算子对应了tf.nn.leaky_relu()这个函数,然后我们就可以用其他类似的函数代替,或者用atlas 500支持的算子去编写一个LeakyRelu函数。
下面再举些例子分析如何解决算子不支持的问题。
针对AddV2算子,对应yolov3.py中的“+”运算符,可使用tf.add()替换。
针对SplitV算子,对应代码中的tf.split()函数,它的功能是对tensor进行分割,这里我直接分开取tensor中的某一列,实现分割效果:
最后为了保持维度一致使用了expand_dims函数。
在生成算子离线结构时出错,mind studio不会显示是因为什么算子问题而出错,而是输出一个log文件,所以我们需要利用这个log文件去定位出错的地方,再进行修改。Log文件内容很多,但是我们需要关注的是文件的最后部分,直接定位到[ERROR]位置:
以这个log文件为例,可以看到第一个ERROR显示BroadcastOutputTensor5D……Invalid dim,这里就可以初步判断,是模型进行到某一步的时候,广播操作出错了,而且是5维张量的广播操作出错,翻看atlas 500算子清单就可知道,其实atlas 500中的算子是不支持5维张量的。
继续看下一行ERROR,提到了node:Add,也就是说,是模型中的某一步5维张量的加法,因为进行加法的两个张量维度不一致,需要进行广播操作,但是atlas 500不支持这种5维张量的广播操作,所以就报错了。
这时候,我们就可以回到原代码中查找模型中哪里进行了加法,也就是查找tf.add函数,但是往往这样找也会找到数个候选项,当然我们也可以逐个分析它们是不是5维张量的乘法,但是也可以利用ERROR上方的INFO信息,进一步判断报错的具体位置。
需要注意的是这部分,它提到了一个对4位的张量进行的加操作,而4维分别是131332,回到YOLO模型本身,1313意味着feature map的cell,每个cell有3个anchor,2就有很多种可能,比如边界框的坐标,或者边界框的宽高等等,但是这里的信息也足够去判断,其实出错的地方是比较接近模型的输出的,然后就可以找到报错的位置了:
我们计得的边界框坐标是相对于cell而言的,所以需要加上cell的左上角坐标才能得到相对于整幅图像的坐标,而这里因为两个张量维度不一致,就需要进行广播操作。
这里再说明一下,虽然看到的张量是4维,实际上因为还有一个batch维,所以对box_center来说,它的张量尺寸应该是batch131332,而x_y_offset则是13132(每个cell一个坐标)。
虽然atlas 500不支持5维张量的广播操作,但是它支持4维的,所以这里的解决思路就是先把x_y_offset拼接三次,把维度转化成131332,然后对box_center、x_y_offset降维,转化成batch13136、13136,这时候就可以直接进行广播加法,得到batch13136,最后再升维,变成batch13133*2:
因为Atlas 500不支持5维的操作,所以这种先降维操作后再升维的方法是很常用的。
总的来说,转化模型的难点一个是定位报错的地方,一个是根据Atlas500的要求写代码,有些地方了解得不够深入,或许说得不够准确,欢迎指出。
视频分析的项目代码我放在了Github,欢迎交流:ObjectDetection-YOLOv3