我的编程空间,编程开发者的网络收藏夹
学习永远不晚

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

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

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

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

作者:京东AI研究院 张建浩

炼丹师在转换模型的时候,经常会发现给转换前后的模型输入同样的图片,模型结果有微小的差别。其中的原因有数值算法的误差、不同 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 操作,经过分析各个框架的源代码,我发现它的流程可以总结如下:

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

1

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

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

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

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

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

(这很符合直觉)。另一个是仍让w(i)=i,但改变函数f,使

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

仍以长度为 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 已经修复了这个问题。

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

2

接下来讨论另外两个函数g和h,nearest, linear, cubic 这三种常见的 resize 的不同方式,是在g和h上有所不同。如上文所述,函数 是什么引起了各个框架 Resize 操作的结果不同?——来自 ONNX 的标准化尝试 得到离 是什么引起了各个框架 Resize 操作的结果不同?——来自 ONNX 的标准化尝试 最近的像素点,nearest 只需要找最近的一个像素点,linear 要找最近的两个(左右各一个),cubic 要找最近的四个(左右各两个);函数h(a,r)是计算这一个/两个/四个像素点的加权平均值,其中权值是由r确定的(如上文所述,r是 是什么引起了各个框架 Resize 操作的结果不同?——来自 ONNX 的标准化尝试距左侧像素点的距离)。对 nearest/linear/cubic 的每一种来说,如何从r得到各个像素点的权值都有各自标准的实现,nearest resize 不必说,对于 linear resize,两个像素点的权值是 是什么引起了各个框架 Resize 操作的结果不同?——来自 ONNX 的标准化尝试 。对 cubic 来说,四个像素点的权值是

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


[1]其中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 需要找到 是什么引起了各个框架 Resize 操作的结果不同?——来自 ONNX 的标准化尝试 的左右各两个最相邻的像素点,但 是什么引起了各个框架 Resize 操作的结果不同?——来自 ONNX 的标准化尝试 左右两侧不一定能保证各有两个像素点(假设某种情况下计算得到 是什么引起了各个框架 Resize 操作的结果不同?——来自 ONNX 的标准化尝试 ,那么它左边只有一个像素点),此时也有两种现存的不同方法,一种是对图像做 edge padding,即认为仍从左边找到了两个像素点,并且这两个像素点的值都是第一个像素点的值;另一种是认为找到了三个而不是四个像素点,并对三个像素点的权值做归一化。

3

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

小结

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

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

是否自动取整等等。

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

其中比较核心的属性 coordinate_transformation_mode 是把w、f和 是什么引起了各个框架 Resize 操作的结果不同?——来自 ONNX 的标准化尝试 复合得到的单个函数 是什么引起了各个框架 Resize 操作的结果不同?——来自 ONNX 的标准化尝试,即

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

在这里没有用独立的函数w和f的原因除了看起来更简单之外,也有解决现实问题的考虑——有一些框架的某些 resize 实现没有使用

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

的形式,而是直接让

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

虽然这显然是不合理的(coordinate_transformation_mode=tf_half_pixel_for_nn 就描述了这样一个不合理的实现),但也只能承认它们的存在。相比起来,上一个版本的 ONNX Resize 算子 spec 的制定者没有意识到 Resize 算子的复杂性,完全模仿了 TensorFlow 的实现,不仅和其它框架的结果不一致,而且连 TensorFlow 的 bug 也一并模仿了。

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

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

欢迎点击“京东智联云”了解更多精彩内容!

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

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

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

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

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

作者:京东AI研究院 张建浩炼丹师在转换模型的时候,经常会发现给转换前后的模型输入同样的图片,模型结果有微小的差别。其中的原因有数值算法的误差、不同 jpeg 解码库产生的结果不同等等,也有不同框架内部对某些算子的实现差异。在给 ONNX
2023-06-06

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录