背景
分割網絡在進行上採樣的時候我用的是雙線性插值上採樣的,而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進行保存