日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

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

發布時間:2024/7/23 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 小心使用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相關。

總結

以上是生活随笔為你收集整理的小心使用tf.image.resize_images,填坑经验分享给你的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。