Keras中layer.get_output_shape_at()报无输出形状异常的原因及解决方法
解决Keras中layer.get_output_shape_at()抛出RuntimeError的问题
前阵子我在Kaggle用TensorFlow 2.3.1复现代码时,碰到了一个挺典型的错误,先把当时的代码片段和报错信息贴出来:
复现代码片段
input_shape = (size, size, 3) in_lay = tf.keras.layers.Input(shape = input_shape) # 此处重复定义in_lay不影响核心问题 in_lay = tf.keras.layers.Input(shape = input_shape) base_pretrained_model = tf.keras.applications.VGG16(input_shape = input_shape, include_top = False, weights = 'imagenet') base_pretrained_model.trainable = False # 就是这行代码抛出了错误 pt_depth = base_pretrained_model.get_output_shape_at(0)[-1] pt_features = base_pretrained_model(in_lay) bn_features = tf.keras.layers.BatchNormalization()(pt_features) # ... 后续代码
报错信息
pt_depth = base_pretrained_model.get_output_shape_at(0)[-1] File "/home/xxxx/anaconda3/envs/py36/lib/python3.6/site-packages/tensorflow/python/keras/engine/base_layer.py", line 2030, in get_output_shape_at 'output shape') File "/home/xxxx/anaconda3/envs/py36/lib/python3.6/site-packages/tensorflow/python/keras/engine/base_layer.py", line 2603, in _get_node_attribute_at_index 'and thus has no defined ' + attr_name + '.') RuntimeError: The layer has never been called and thus has no defined output shape.
错误原因
这个错误的本质很简单:get_output_shape_at()方法依赖于层已经被实际调用过(也就是有输入张量流过该层)。在你的代码里,你先创建了VGG16模型,紧接着就调用get_output_shape_at(0),但此时这个模型还没有处理过任何输入——pt_features = base_pretrained_model(in_lay)这行代码是在获取输出形状之后才执行的,所以Keras不知道这个模型的输出形状是什么,自然就抛出了RuntimeError。
解决方法
这里有两个简单可行的解决思路:
方法一:调整代码顺序,先让模型处理输入
只需要把调用模型的代码移到获取输出形状之前,让模型先“跑”一次输入,这样它就会记录下输出形状了:
input_shape = (size, size, 3) in_lay = tf.keras.layers.Input(shape = input_shape) base_pretrained_model = tf.keras.applications.VGG16(input_shape = input_shape, include_top = False, weights = 'imagenet') base_pretrained_model.trainable = False # 先让模型处理输入,生成输出张量 pt_features = base_pretrained_model(in_lay) # 现在就可以正常获取输出形状了 pt_depth = base_pretrained_model.get_output_shape_at(0)[-1] bn_features = tf.keras.layers.BatchNormalization()(pt_features) # ... 后续代码
方法二:直接访问模型的output_shape属性
对于像VGG16这种已经指定了input_shape的预训练模型,其实不需要调用模型也能获取输出形状,直接访问output_shape属性就行,这样更简洁:
input_shape = (size, size, 3) in_lay = tf.keras.layers.Input(shape = input_shape) base_pretrained_model = tf.keras.applications.VGG16(input_shape = input_shape, include_top = False, weights = 'imagenet') base_pretrained_model.trainable = False # 直接用output_shape获取输出通道数 pt_depth = base_pretrained_model.output_shape[-1] pt_features = base_pretrained_model(in_lay) bn_features = tf.keras.layers.BatchNormalization()(pt_features) # ... 后续代码
这两种方法都能解决这个问题,我个人更推荐方法二,因为不需要调整代码顺序,逻辑上也更直接。
内容的提问来源于stack exchange,提问作者passinger
相关产品推荐
相关产品推荐

