使 Netron 支持 PaddlePaddle 模型子图显示

先介绍一下什么是 PaddlePaddle 的模型子图。一般的神经网络都可以表示成一张由算子组成的计算图,但是对一些较为复杂的神经网络,可能会存在一些条件分支。PaddlePaddle 在构建这种条件分支的网络时,会把分支内的计算图单独保存成一张子图。

具体到 PaddlePaddle 的内部数据结构时,每个子图就是 Program 内的一个 Block。这个 Block 内包含该子图的所有中间变量,op 算子和参数等。

目前 PaddlePaddle 的模型可视化主要是依赖 Netron,包括 PadddlePaddle 提供的 VisualDL 工具里内嵌的也是 Netron。

我最近在研究 PaddlePaddle 模型优化的时候,发现 VisualDL 完全不支持子图的可视化。我稍微研究了一下 Netron 的代码,想把子图的可视化给加上。但没想到的是,其实 Netron 本身已经做了 PaddlePaddle 子图结构的解析,只是代码上存在一点儿 bug,导致子图无法被选择出来。

我就修复了一下这个 BUG,提交了一个 PR: https://github.com/lutzroeder/netron/pull/588 。希望对 PaddlePaddle 的用户能有所帮助。

只是 Netron 项目的 Owner lutzroeder 有些奇怪。他不是直接接受这个 PR,而是自己做一些修改后提交一个新的 commit 引用了这个 PR,不知道出于什么目的。这个习惯会让人很难分析出来对 PaddlePaddle 模型解析代码感兴趣的人都是谁,对于维护并不便利。

神经网络图像输入的 resize 问题

这个标题在我的博客后台躺了快一年了,但一直没想好该怎么写。主要是没有深入地去研究这里面的问题,就随便谈谈一点粗浅的认知吧。这些认知可能不对,仅供参考,并且欢迎批评。

一、不同的 resize 方式对最终的结果有一定的影响,尤其是用随机图片评估时会更加明显。

看似用的是同一个神经网络,同一个训练集,但在输入的处理上仍然会有各种不同。比如 Inception 要求 299x299,你可以直接用 ImageMagick 将原始图片处理成 299x299 再输入,也可以用 OpenCV 读入图片后再转成 299x299,还可以直接用深度学习框架(TensorFlow/Caffe)进行 resize。甚至同一种方法也可能有各种不同的参数控制,比如最邻近插值、双线性插值、双立方插值等。通过不同的 resize 方法训练出来的网络参数,或者同一张图片不同方法 resize 后预测的输出,数值是存在差异的。如果使用的是质量较低的大规模数据集,差异可能会非常明显。

二、不同的 resize 方式对最终结果的影响无法确定。

换种说法,这可能是个玄学。这算是一个经验总结,就不多讲了。也就是说,某种 resize 方式有时可能让结果变好,有时也可能让结果变差。

三、训练、评估和线上预测时统一图片处理方式有一些好处。

有的公司在训练神经网络时使用一种框架,上线时使用另一种框架;或者训练时采取一种输入,上线时采取另一种输入。都会导致线上服务的预测结果跟评估结果不一致,导致排查问题较为复杂。

有时候为了性能考虑,必须在客户端完成图片处理,resize 成较小图片后再传给服务端。而客户端往往使用的不同的库,比如 iOS 可以使用 Core Graphics 库或者 UIKit 库,Android 的 Bitmap 库,这些库在服务端是基本上无法使用的。这时候就需要知道这可能会导致线上效果与评估结果有不一致的可能,并且采取一定的措施来消减这样的不同。