1. 程式人生 > 程式設計 >解決Keras的自定義lambda層去reshape張量時model儲存出錯問題

解決Keras的自定義lambda層去reshape張量時model儲存出錯問題

前幾天忙著參加一個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層來包裝。

大概原始碼(只是大概意思)如下:

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)

然後編譯 這個原始碼:

optimizer = SGD(lr=0.01,momentum=0.9)
model.compile(optimizer = optimizer,loss = model_dice,metrics = ['accuracy'])
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儲存出錯問題就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支援我們。