小心使用tf.image.resize_images,填坑经验分享给你

上上周,我在一个项目上线前对模型进行测试时出现了问题,这个问题困扰了我近两周,终于找到了问题根源,做个简短总结分享给你,希望对大家有帮助。

问题描述:

线上线下测试结果不一致,且差异很大

具体来说,
线下测试直接load由ckpt存储的模型,然后使用cv进行数据预处理,然后评估测试集上的准召,一切正常。
线上测试时,首先使用tf.image相关函数将预处理写死在模型中,将ckpt模型转为savemodel格式,然后使用tf-serving部署后,发送请求进行线上实测,此时和线下测试结果差异较大。

问题定位:

主要问题出在ckpt转savemodel时,预处理部分 tf.image.resize_images 和 tf.cast 两个函数的使用上
虽然问题发生在模型转换时,但真正的问题出在对于tf.image.resize_images函数的使用上,因此任何可能的使用场景,包括预处理,数据增强,模型转换等,都有可能被它坑到,这也是我写这篇文章的原因,提醒大家不要向我一样被它坑到。
小小吐槽: 在发现真正的问题所在之前,由于我大幅的修改了我的训练框架,所以我从模型结构到loss函数,再到数据增强方法,排查了一遍,最终才发现,问题的出现,仅仅是我将
tf.image.resize_images 的 method 参数:
tf.image.ResizeMethod.BILINEAR 修改为了 tf.image.ResizeMethod.BICUBIC

what?这样小的一个修改就崩了?
下面我将我的排查过程详细描述出来,希望对大家有所启发。

如果打印tf.image.resize_images函数前后的数据类型

print(img_decoded.dtype)
resized_image = tf.image.resize_images(img_decoded, [new_height, new_width], method=tf.image.ResizeMethod.BICUBIC)
print(resized_image.dtype)

可以观察到如下结果
tf.uint8
tf.float32

而如果打印resize后的数据范围
tf img max 294.077484131
tf img min -25.2455863953

可以看到本来是0-255的uint8数据处理后不但数据类型发生了变化,而且像素值越界了!

此外,在预处理结束后我还使用了tf.cast函数转换数据类型

padd_image = tf.cast(resized_image, tf.uint8)

如果输入数据已经越界,此时tf.cast函数的使用也存在问题:

为方便理解问题,观察以下可视化结果:
使用cv2进行预处理的结果
在这里插入图片描述
tf版本的预处理结果(resize_images + cast)
在这里插入图片描述
可以看到resize_images + cast 函数的使用对原图有很明显的破坏

我们找到越界的部分,对resize后越界的部分进行可视化(用255或0截断后显示,正常区域用黑色填充)
小于0的部分
在这里插入图片描述
超过255的部分
在这里插入图片描述
上面两张图是正常越界截断后的结果,为了观察与tf.cast函数处理的区别

将 resize+cast 后 >255 部分的像素值可视化出来(为了凸显这部分像素,正常区域改用白色填充)
在这里插入图片描述
通过上图可以观察到,tf.cast对越界的处理机制并不是截断,而是类似取余操作,或者类似变量赋值时超过数据类型取值范围时的处理机制。

具体来说,如果越界的像素值是256,得到的返回结果对应的像素值是0;如果是257,得到的像素值是1,以此类推。

从图中越界的黄色区域(255,255,0)被tf.cast函数处理后变为蓝色区域(0,0,255)可以印证这一说法。

解决方法:
首先这并不能算google工程师的一个bug,因为tf.image.resize_images函数并没有对返回值的取值范围做保证,本质它就是进行插值,插值结果它不管。只是cv2或者PIL的类似函数中帮我们做了很多的“保护“。

通过尝试,最简便的解决方法是修改插值方法,经验证:
在这里插入图片描述
上面两种插值方法都不会造成像素值越界
如果你需要确保你的返回结果是在正常范围内的,那就在上面两个方法中选一个。此外,最邻近插值会带来比较明显的“不连续感”,因此推荐选择双线性插值,同时它也是默认参数。三次样条,虽然平滑性好,但是tf的实现版本真的是坑到我了。。。

当然,单单使用tf.image.resize_images也仅仅是对图片造成了微弱的扰动,但是配合上tf.cast函数的特有机制,对模型的干扰就比较大了。

综上:

1.使用 tf.image.resize_images函数时,如果使用三次样条插值,不要想当然的认为返回值是0-255的。
2.tf.cast函数的处理机制要注意,类似取余,而不是截断

搜了一下,被其它和resize相关的问题困扰的人也不少😅
感兴趣可以探究下
How Tensorflow’s tf.image.resize stole 60 days of my life
tensorflow-issues-19627
tf-image-resize-bilinear-vs-cv2-resize
说明tf的resize实现多少有些问题,这些应该不是bug,但确实给tensorflow的使用者们造成了不少困扰
在这里插入图片描述
这些函数的使用并不像cv2的api那样安全可信任
因此使用tf.image系的函数要慎重,一定要check数据类型,check函数处理后是否在0-255的范围,尤其是resize相关。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/499478.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

PID控制器开发笔记之十:步进式PID控制器的实现

对于一般的PID控制系统来说,当设定值发生较大的突变时,很容易产生超调而使系统不稳定。为了解决这种阶跃变化造成的不利影响,人们发明了步进式PID控制算法。 1、步进式PID的基本思想 所谓步进式PID算法,实际就是在设定值发生阶跃…

AutoML 与 Bayesian Optimization 概述

1. AutoML 概述 AutoML是指对于一个超参数优化任务(比如规定计算资源内,调整网络结构找到准确率最高的网络),尽量减少人为干预,使用某种学习机制,来调节这些超参数,使得目标问题达到最优。 这…

使用Eclipse进行Makefile项目

最近在MCU on Eclipse网站上看到Erich Styger所写的一篇有关在Eclipse中使用Makefile创建项目的文章,文章讲解清晰明了非常不错,所以呢没人将其翻译过来供各位同仁参考。当然限于个人水平,有不当之处恳请指正。原文网址:https://m…

Git commit 常用表情快速查询

git commit 的时候,添加表情符号可以更好的表明本次提交的性质,也更有趣。 常用表情符号如下: emoji emoji代码 commit说明 🎨 (调色板) :art: 改进代码结构/代码格式 ⚡️ (闪电) :zap: 提升性能 🐎 (赛马)…

C语言学习及应用笔记之一:C运算符优先级及使用问题

C语言中的运算符绝对是C语言学习和使用的一个难点,因为在2011版的标准中,C语言的运算符的数量超过40个,甚至比关键字的数量还要多。这些运算符有单目运算符、双目运算符以及三目运算符,又涉及到左结合和右结合的问题,真…

Docker用法整理

Docker教程推荐 两个不错的参考资料&#xff1a; https://yeasy.gitbooks.io/docker_practice/content/introduction/ https://www.cnblogs.com/bethal/p/5942369.html 镜像&#xff1a; 查看镜像 docker images ls 删除镜像 docker image rm <image id> 拉取镜像 …

使用FreeRTOS进行性能和运行时分析

在MCU on Eclipse网站上看到Erich Styger在2月25日发的博文&#xff0c;一篇关于使用FreeRTOS进行性能和运行分析的文章&#xff0c;本人觉得很有启发&#xff0c;特将其翻译过来以备参考。当然限于个人水平&#xff0c;有描述不当之处恳请指正。原文网址&#xff1a;https://m…

生成微信公众号对应二维码的两种简单方法

方法1 在浏览器中打开下面的链接 https://open.weixin.qq.com/qr/code?usernameName 其中Name替换为对应公众号的微信号 例如&#xff0c;我们打算生成公众号 AI算法联盟 的二维码 只需首先关注这个公众号 在其详细信息中&#xff0c;查找到微信号信息&#xff1a;AIReport…

在Amazon FreeRTOS V10中使用运行时统计信息

在MCU on Eclipse网站上看到Erich Styger在8月2日发的博文&#xff0c;一篇关于在Amazon FreeRTOS V10中使用运行时统计信息的文章&#xff0c;本人觉得很有启发&#xff0c;特将其翻译过来以备参考。原文网址&#xff1a;https://mcuoneclipse.com/2018/08/02/tutorial-using-…

github无法加载图片的解决办法

最近发现我的github上面项目README里面的图片全裂了&#xff0c;一直以为是github最近服务器不稳定。今天通过简单的查询&#xff0c;发现原来这个问题可以解决&#xff0c;但是不能永久有效&#xff0c;之后还会用到&#xff0c;因此记录在这里&#xff0c; 也分享给大家。 解…

leetcode 1.两数之和

题目 链接&#xff1a;https://leetcode-cn.com/problems/two-sum 给定一个整数数组 nums 和一个目标值 target&#xff0c;请你在该数组中找出和为目标值的那 两个 整数&#xff0c;并返回他们的数组下标。 你可以假设每种输入只会对应一个答案。但是&#xff0c;你不能重复…

C语言学习及应用笔记之二:C语言static关键字及其使用

C语言有很多关键字&#xff0c;大多关键字使用起来是很明确的&#xff0c;但有一些关键字却要相对复杂一些。我们这里要说明的static关键字就是如此&#xff0c;它的功能很强大&#xff0c;相应的使用也就更复杂。 一般来说static关键字的常见用法有三种&#xff1a;一是用作局…

μCUnit,微控制器的单元测试框架

在MCU on Eclipse网站上看到Erich Styger在8月26日发布的博文&#xff0c;一篇关于微控制器单元测试的文章&#xff0c;有很高的参考价值&#xff0c;特将其翻译过来以备学习。原文网址&#xff1a;https://mcuoneclipse.com/2018/08/26/tutorial-%CE%BCcunit-a-unit-test-fram…

leetcode No.15-16 三数之和相关问题

leetcode 15. 三数之和 题目 链接&#xff1a;https://leetcode-cn.com/problems/3sum 给定一个包含 n 个整数的数组 nums&#xff0c;判断 nums 中是否存在三个元素 a&#xff0c;b&#xff0c;c &#xff0c;使得 a b c 0 &#xff1f;找出所有满足条件且不重复的三元组…

PID控制器开发笔记之十一:专家PID控制器的实现

前面我们讨论了经典的数字PID控制算法及其常见的改进与补偿算法&#xff0c;基本已经覆盖了无模型和简单模型PID控制经典算法的大部。再接下来的我们将讨论智能PID控制&#xff0c;智能PID控制不同于常规意义下的智能控制&#xff0c;是智能算法与PID控制算法的结合&#xff0c…

leetcode No.123 买卖股票的最佳时机 III

题目 链接&#xff1a;https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iii 给定一个数组&#xff0c;它的第 i 个元素是一支给定的股票在第 i 天的价格。 设计一个算法来计算你所能获取的最大利润。你最多可以完成 两笔 交易。 注意: 你不能同时参与多…

Modbus协议栈开发笔记之七:Modbus ASCII Slave开发

与Modbus RTU在串行链路上分为Slave和Master一样&#xff0c;Modbus ASCII也分为Slave和Master&#xff0c;这一节我们就来开发Slave。对于Modbus ASCII从站来说&#xff0c;需要实现的功能其实与Modbus RTU的Slave是一样的。其操作过程也是一样的。首先接收到主站的访问命令&a…

leetcode No.21 合并两个有序链表

题目 链接&#xff1a;https://leetcode-cn.com/problems/merge-two-sorted-lists 将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 示例&#xff1a; 输入&#xff1a;1->2->4, 1->3->4 输出&#xff1a;1-&…

Modbus协议栈开发笔记之八:Modbus ASCII Master开发

这一节我们来封装Modbus ASCII Master应用&#xff0c;Modbus ASCII主站的开发与RTU主站的开发是一致的。同样的我们也不是做具体的应用&#xff0c;而是实现ASCII主站的基本功能。我们将ASCII主站的功能封装为函数&#xff0c;以便在开发具体应用时调用。 对于ASCII主站我们主…

leetcode No.83 删除排序链表中的重复元素

题目 链接&#xff1a;https://leetcode-cn.com/problems/remove-duplicates-from-sorted-list 给定一个排序链表&#xff0c;删除所有重复的元素&#xff0c;使得每个元素只出现一次。 示例 1: 输入: 1->1->2 输出: 1->2 示例 2: 输入: 1->1->2->3-&…