前幾天忙著參加一個AI Challenger比賽,一直沒有更新博客,忙了將近一個月的時間,也沒有取得很好的成績,不過這這段時間內的確學到了很多,就在決賽結束的前一天晚上,準備復現使用一個新的網絡UPerNet的時候出現了一個很匪夷所思,莫名其妙的一個問題。谷歌很久都沒有解決,最后在一個日語網站上看到了解決方法。
事后想想,這個問題在后面搭建網絡的時候會很常見,但是網上卻沒有人提出解決辦法,So, I think that's very necessary for me to note this.
背景
分割網絡在進行上采樣的時候我用的是雙線性插值上采樣的,而Keras里面并沒有實現雙線性插值的函數,所以要自己調用tensorflow里面的tf.image.resize_bilinear()函數來進行resize,如果直接用tf.image.resize_bilinear()函數對Keras張量進行resize的話,會報出異常,大概意思是tenorflow張量不能轉換為Keras張量,要想將Kears Tensor轉換為 Tensorflow Tensor需要進行自定義層,Keras自定義層的時候需要用到Lambda層來包裝。
大概源碼(只是大概意思)如下:
1
2
3
4
5
6
7
|
from keras.layers import Lambda import tensorflow as tf first_layer = Input (batch_shape = ( None , 64 , 32 , 3 )) f = Conv2D(filters, 3 , activation = None , padding = 'same' , kernel_initializer = 'glorot_normal' ,name = 'last_conv_3' )(x) upsample_bilinear = Lambda( lambda x: tf.image.resize_bilinear(x,size = first_layer.get_shape().as_list()[ 1 : 3 ])) f = upsample_bilinear(f) |
然后編譯 這個源碼:
1
2
3
|
optimizer = SGD(lr = 0.01 , momentum = 0.9 ) model.save( 'model.hdf5' ) |
其中要注意到這個tf.image.resize_bilinear()里面的size,我用的是根據張量(first_layer)的形狀來做為reshape后的形狀,保存模型用的是model.save().然后就會出現以下錯誤!
異常描述:
在一個epoch完成后保存model時出現下面錯誤,五個錯誤提示隨機出現:
TypeError: cannot serialize ‘_io.TextIOWrapper' object
TypeError: object.new(PyCapsule) is not safe, use PyCapsule.new()
AttributeError: ‘NoneType' object has no attribute ‘update'
TypeError: cannot deepcopy this pattern object
TypeError: can't pickle module objects
問題分析:
這個有兩方面原因:
tf.image.resize_bilinear()中的size不應該用另一個張量的size去指定。
如果用了另一個張量去指定size,用model.save()來保存model是不能序列化的。那么保存model的時候只能保存權重——model.save_weights('mode_weights.hdf5')
解決辦法(兩種):
1.tf.image.resize_bilinear()的size用常數去指定
upsample_bilinear = Lambda(lambda x: tf.image.resize_bilinear(x,size=[64,32]))
2.如果用了另一個張量去指定size,那么就修改保存模型的函數,變成只保存權重
model.save_weights('model_weights.hdf5')
總結:
????我想使用keras的Lambda層去reshape一個張量
如果為重塑形狀指定了張量,則保存模型(保存)將失敗
您可以使用save_weights而不是save進行保存
補充知識:Keras 添加一個自定義的loss層(output及compile中,輸出及loss的表示方法)
例如:
計算兩個層之間的距離,作為一個loss
distance=keras.layers.Lambda(lambda x: tf.norm(x, axis=0))(keras.layers.Subtract(Dense1-Dense2))
這是添加的一個loss層,這個distance就直接作為loss
model=Model(input=[,,,], output=[distance])
model.compile(....., loss=lambda y_true, y_pred: ypred)
以上這篇解決Keras的自定義lambda層去reshape張量時model保存出錯問題就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支持服務器之家。
原文鏈接:https://blog.csdn.net/mieleizhi0522/article/details/83057946