Auto Byte

专注未来出行及智能汽车科技

微信扫一扫获取更多资讯

Science AI

关注人工智能与其他前沿技术、基础学科的交叉研究与融合发展

微信扫一扫获取更多资讯

京东AI研究院 张建浩作者

是什么引起了各个框架Resize操作的结果不同?——来自ONNX的标准化尝试

简介各种 resize 操作的共同流程,并分析是哪些因素引起了不同框架 resize 操作的不同。

炼丹师在转换模型的时候,经常会发现给转换前后的模型输入同样的图片,模型结果有微小的差别。其中的原因有数值算法的误差、不同 jpeg 解码库产生的结果不同等等,也有不同框架内部对某些算子的实现差异。

在给 ONNX 贡献 Resize 算子的 spec 的时候,我发现 Resize 是一个突出体现了框架实现差异的算子——多种 Resize 类型、不统一的参数、将错就错的历史遗留 bug 和其它极易被忽略的问题集中在一起,导致几乎每个框架的 Resize 操作的结果都有差异,而 ONNX 是一个神经网络模型的中间格式,它应该尽量保留原始框架的算子的语义。经过查看相关论文和各种框架的源代码,我分析和总结了 Resize 操作众多的实现方式。最终为 ONNX 贡献了一个较为完善的、标准化的 Resize 算子的 spec,它包含多个(基本)正交的参数TensorFlow 1.x、TensorFlow 2.x、PyTorch、OpenCV 的 resize/interpolation 方法都可以用这个算子 100% 无损的表达。本文将简单介绍各种 resize 操作的共同流程,并分析是哪些因素引起了不同框架 resize 操作的不同。

多维 tensor (例如二维图像)的 resize 操作是用多个在一维 tensor 上进行的 resize 操作组合出来的,所以我们只讨论一维 tensor 上的 resize 操作,经过分析各个框架的源代码,我发现它的流程可以总结如下:

先讨论w和f,w(i)是第 i 个像素点的坐标,乍一看, w(i)完全可以等于i本身,其实没有这么简单。例如一个长度为 3 的 tensor,如果第i个像素点的坐标等于i本身,那么三个像素点在tensor 中的位置就如下图中最左边的样子,横线的长度代表一维 tensor 的长度,圆圈代表像素点:

222222.png

三个像素点没有对称地分布在 tensor 上,而是往左偏了。出于直觉,我们觉得这不是一件特别好的事情。在各种框架中,有两种常见的方法来解决这个问题:

一个是选取w(i)=i+0.5,以一个长度为 3 的一维 tensor 为例,它第 0 个像素点在 0.5 位置,第 1 个像素点在 1.5 位置,第 2 个像素点在 2.5 位置,这称为 half_pixel,也就是上图中中间的方法。这种方法中,3333.png(这很符合直觉)。

另一个是仍让w(i)=i,但改变函数f,使44444.png仍以长度为 3 的一维 tensor 为例,这种方法相当于在 resize 时砍掉了最右边长度为 1 的部分,使像素点的分布“被”对称了。这称为 align_corner,也就是上图中最右边的方法,在各种框架的 resize 方法的参数里常见的 align_corner=True/False 就是它了,它的名字来源于它可以让 tensor 中第一个和最后一个像素(即 corner)在缩放后保持不变。

那如果我们不采用这两种方法,一定要使用“直觉不好”的 asymmetric 方法,究竟会发生什么呢?TensorFlow 1.x 就给我们提供了这样一个反面典型,它在 align_corner=False 时的实现是错的,原因就是使用了上图中错误的 asymmetric 方法,这会导致奇怪的缩放结果,这篇博客中🔗https://hackernoon.com/how-tensorflows-tf-image-resize-stole-60-days-of-my-life-aba5eb093f35

作者用 TensorFlow 1.x 训练的超分辨率神经网络总是出现奇怪的问题,最终他发现问题根源是 TensorFlow 错误的 resize 实现,他还给了一个形象的例子:把 16x16 的下图左侧图像缩小到 4x4,本应得到如下图右侧所示的图像,而 TensorFlow 1.x 却给出了下图中间的奇怪结果,图像的对称性被完全破坏了,其中的原因就如上文所述。TensorFlow 1.x 的 resize 结果和其它框架不同的一大原因就是它错误的 resize 实现,好在 TensorFlow 2.x 已经修复了这个问题。

555555.png

接下来讨论另外两个函数g和h,nearest, linear, cubic 这三种常见的 resize 的不同方式,是在g和h上有所不同。如上文所述,函数g(i’)得到离i’最近的像素点,nearest 只需要找最近的一个像素点,linear 要找最近的两个(左右各一个),cubic 要找最近的四个(左右各两个);函数h(a,r)是计算这一个/两个/四个像素点的加权平均值,其中权值是由r确定的(如上文所述,r是i’距左侧像素点的距离)。对 nearest/linear/cubic 的每一种来说,如何从r得到各个像素点的权值都有各自标准的实现,nearest resize 不必说,对于 linear resize,两个像素点的权值是66666.png对 cubic 来说,四个像素点的权值是

7777777.png

其中A是一个固定的参数,它的取值却是每个框架不同,两个常见的选择是 -0.5 (TensorFlow 部分版本的实现)和 -0.75(PyTorch)。因为A没有统一的标准取值,所以各个框架的 cubic resize 结果不同是常见的事情。

补充一句题外话:cubic resize 的权值计算起来比 linear resize 复杂的多,所以它的耗时肯定会长一些,但产生的图像性质更好(这篇 paper 🔗https://arxiv.org/abs/1812.01187发现图片预处理使用 cubic resize 可以提升分类网络准确率)。

还有一个会引起 cubic resize 结果差异的细节是,cubic resize 需要找到i’的左右各两个最相邻的像素点,但i’左右两侧不一定能保证各有两个像素点(假设某种情况下计算得到i’=0.6,那么它左边只有一个像素点),此时也有两种现存的不同方法,一种是对图像做 edge padding,即认为仍从左边找到了两个像素点,并且这两个像素点的值都是第一个像素点的值;另一种是认为找到了三个而不是四个像素点,并对三个像素点的权值做归一化。

88888.png

小结

总结一下,各个框架 Resize 操作的结果不同的原因是多种多样的,例如 TensorFlow 用了自己发明的错误实现、cubic resize 中参数 A 没有固定的取值、非整数的是否自动取整等等。

ONNX Resize 算子的 spec 就是基于上面的分析写出来的,具体的描述在🔗https://github.com/onnx/onnx/blob/master/docs/Operators.md#Resize

Python 版的参考实现在 🔗https://github.com/onnx/onnx/blob/master/onnx/backend/test/case/node/resize.py

现在 TensorFlow、PyTorch 都支持了导出这一版本的 Resize 算子,TensorRT 等部署框架也支持导入和运行这个 Resize 算子。自己创造的东西能被众多知名的框架跟进,我感到非常大的成就感。

参考:https://ieeexplore.ieee.org/document/1163711

京东科技开发者
京东科技开发者

京东科技开发者是京东集团旗下为人工智能、大数据、云计算、物联网等相关领域开发者提供技术分享交流的平台。平台将发布产品技术信息、行业技术内容、技术活动及大赛等资讯。拥抱技术,与开发者携手预见未来!

入门ONNX标准化AI
3
相关数据
参数技术

在数学和统计学裡,参数(英语:parameter)是使用通用变量来建立函数和变量之间关系(当这种关系很难用方程来阐述时)的一个数量。

TensorFlow技术

TensorFlow是一个开源软件库,用于各种感知和语言理解任务的机器学习。目前被50个团队用于研究和生产许多Google商业产品,如语音识别、Gmail、Google 相册和搜索,其中许多产品曾使用过其前任软件DistBelief。

神经网络技术

(人工)神经网络是一种起源于 20 世纪 50 年代的监督式机器学习模型,那时候研究者构想了「感知器(perceptron)」的想法。这一领域的研究者通常被称为「联结主义者(Connectionist)」,因为这种模型模拟了人脑的功能。神经网络模型通常是通过反向传播算法应用梯度下降训练的。目前神经网络有两大主要类型,它们都是前馈神经网络:卷积神经网络(CNN)和循环神经网络(RNN),其中 RNN 又包含长短期记忆(LSTM)、门控循环单元(GRU)等等。深度学习是一种主要应用于神经网络帮助其取得更好结果的技术。尽管神经网络主要用于监督学习,但也有一些为无监督学习设计的变体,比如自动编码器和生成对抗网络(GAN)。

准确率技术

分类模型的正确预测所占的比例。在多类别分类中,准确率的定义为:正确的预测数/样本总数。 在二元分类中,准确率的定义为:(真正例数+真负例数)/样本总数

OpenCV技术

OpenCV的全称是Open Source Computer Vision Library,是一个跨平台的计算机视觉库。OpenCV是由英特尔公司发起并参与开发,以BSD许可证授权发行,可以在商业和研究领域中免费使用。OpenCV可用于开发实时的图像处理、计算机视觉以及模式识别程序。

京东机构

京东(股票代码:JD),中国自营式电商企业,创始人刘强东担任京东集团董事局主席兼首席执行官。旗下设有京东零售、京东物流、京东科技子集团、印尼&泰国海外合资跨境电商等核心业务。2013年正式获得虚拟运营商牌照。2014年5月在美国纳斯达克证券交易所正式挂牌上市。 2016年6月与沃尔玛达成深度战略合作。

https://www.jd.com
相关技术
合合信息机构
推荐文章
暂无评论
暂无评论~