tensorflow keras save error: Failed to add concrete function

tensorflow keras save error: Failed to add concrete function

问题:

我在 colab 上有一个成功的 运行 最近邻张量流模型,名为 top_classify。但是在保存时,收到以下错误消息:

KeyError: "Failed to add concrete function 
'b'__inference_model_layer_call_fn_158405'' to object-based SavedModel as it captures 
tensor <tf.Tensor: shape=(), dtype=resource, value=<Resource Tensor>> which is 
unsupported or not reachable from root. One reason could be that a stateful object or 
a variable that the function depends on is not assigned to an attribute of the 
serialized trackable object (see SaveTest.test_captures_unreachable_variable)."

详情:

感兴趣的最近邻模型正在使用已训练模型 (embedding_network) 的输出。并将输入的输出与训练数据集的输出(最近距离)进行比较。我的意思是我们不是直接比较图像,比较它们的输出。通常我不会费心在 tensorflow 上编写 NN 代码,因为模型不是迭代的,但我需要一个 tflite 模型才能在 android 应用程序上使用。所以,我没有太多选择。

首先,我训练了 embedding_network 模型(通过迁移学习和 siamese),输出大小为 (None, 27)。 xc 是整个训练集(752 个样本,大小为 (752, 27) )的恒定输出矩阵,yc 是训练集的正确标签。两者都是 tf 常量。下面的示例是最佳匹配 (1NN)。也可以修改代码以适用于任意数量的所需匹配项 (KNN)。

xc = tf.constant(embedding_network(x_train))
yc = tf.constant(y_train)
inputs = keras.Input(shape=(TARGET_SIZE, TARGET_SIZE, 3))

x0 = embedding_network(inputs, training=False) 
distance = tf.reduce_sum(tf.abs(tf.add(xc, tf.negative(x0))), axis=1)
findKClosestTrImages = tf.argsort(distance, direction='ASCENDING') 
closest0 = tf.gather(yc, findKClosestTrImages[0]) 
out=tf.one_hot(closest0, DEPTH)

top_classify = keras.Model(inputs=inputs, outputs=out)
top_classify.summary()

如您所见,我没有对模型进行任何训练,没有损失函数,也没有编译和拟合。因为我只会在推理时使用它。

这里是新近邻模型的总结,top_classify:

Model: "model_3"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 input_6 (InputLayer)        [(None, 224, 224, 3)]     0         
                                                                 
 model (Functional)          (None, 27)                2292571   
                                                                 
 tf.math.negative_1 (TFOpLam  (None, 27)               0         
 bda)                                                            
                                                                 
 tf.math.add_1 (TFOpLambda)  (752, 27)                 0         
                                                                 
 tf.math.abs_1 (TFOpLambda)  (752, 27)                 0         
                                                                 
 tf.math.reduce_sum_1 (TFOpL  (752,)                   0         
 ambda)                                                          
                                                                 
 tf.argsort_1 (TFOpLambda)   (752,)                    0         
                                                                 
 tf.__operators__.getitem_1   ()                       0         
 (SlicingOpLambda)                                               
                                                                 
 tf.compat.v1.gather_1 (TFOp  ()                       0         
 Lambda)                                                         
                                                                 
 tf.one_hot_1 (TFOpLambda)   (27,)                     0         
                                                                 
=================================================================
Total params: 2,292,571
Trainable params: 0
Non-trainable params: 2,292,571
_________________________________________________________________

无论如何,模型在 colab 上很有用。我得到了非常好的结果。但我无法保存模型,无论我使用 tf.saved_model.save 还是 top_classify.save

错误如果尝试tf.saved_model.save

---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
/usr/local/lib/python3.7/dist-packages/tensorflow/python/saved_model/function_serialization.py in serialize_concrete_function(concrete_function, node_ids, coder)
     64     for capture in concrete_function.captured_inputs:
---> 65       bound_inputs.append(node_ids[capture])
     66   except KeyError:

7 frames
/usr/local/lib/python3.7/dist-packages/tensorflow/python/util/object_identity.py in __getitem__(self, key)
    138   def __getitem__(self, key):
--> 139     return self._storage[self._wrap_key(key)]
    140 

KeyError: <_ObjectIdentityWrapper wrapping <tf.Tensor: shape=(), dtype=resource, value=<Resource Tensor>>>

During handling of the above exception, another exception occurred:

KeyError                                  Traceback (most recent call last)
<ipython-input-33-13ced446758f> in <module>()
     15 TOP_CLASSIFY_SAVE_LOC = "/content/top_classify"
     16 #top_classify.save("/content/top_classify")
---> 17 tf.saved_model.save(top_classify, TOP_CLASSIFY_SAVE_LOC)
     18 #top_classify.save("/content/top_classify", save_format='h5')
     19 # Convert the model

/usr/local/lib/python3.7/dist-packages/tensorflow/python/saved_model/save.py in save(obj, export_dir, signatures, options)
   1278   # pylint: enable=line-too-long
   1279   metrics.IncrementWriteApi(_SAVE_V2_LABEL)
-> 1280   save_and_return_nodes(obj, export_dir, signatures, options)
   1281   metrics.IncrementWrite(write_version="2")
   1282 

/usr/local/lib/python3.7/dist-packages/tensorflow/python/saved_model/save.py in save_and_return_nodes(obj, export_dir, signatures, options, experimental_skip_checkpoint)
   1313 
   1314   _, exported_graph, object_saver, asset_info, saved_nodes, node_paths = (
-> 1315       _build_meta_graph(obj, signatures, options, meta_graph_def))
   1316   saved_model.saved_model_schema_version = (
   1317       constants.SAVED_MODEL_SCHEMA_VERSION)

/usr/local/lib/python3.7/dist-packages/tensorflow/python/saved_model/save.py in _build_meta_graph(obj, signatures, options, meta_graph_def)
   1485 
   1486   with save_context.save_context(options):
-> 1487     return _build_meta_graph_impl(obj, signatures, options, meta_graph_def)

/usr/local/lib/python3.7/dist-packages/tensorflow/python/saved_model/save.py in _build_meta_graph_impl(obj, signatures, options, meta_graph_def)
   1449 
   1450   object_graph_proto = _serialize_object_graph(
-> 1451       saveable_view, asset_info.asset_index)
   1452   meta_graph_def.object_graph_def.CopyFrom(object_graph_proto)
   1453 

/usr/local/lib/python3.7/dist-packages/tensorflow/python/saved_model/save.py in _serialize_object_graph(saveable_view, asset_file_def_index)
   1015     name = saveable_view.function_name_map.get(name, name)
   1016     serialized = function_serialization.serialize_concrete_function(
-> 1017         concrete_function, saveable_view.captured_tensor_node_ids, coder)
   1018     if serialized is not None:
   1019       proto.concrete_functions[name].CopyFrom(serialized)

/usr/local/lib/python3.7/dist-packages/tensorflow/python/saved_model/function_serialization.py in serialize_concrete_function(concrete_function, node_ids, coder)
     66   except KeyError:
     67     raise KeyError(
---> 68         f"Failed to add concrete function '{concrete_function.name}' to object-"
     69         f"based SavedModel as it captures tensor {capture!r} which is unsupported"
     70         " or not reachable from root. "

KeyError: "Failed to add concrete function 
'b'__inference_model_layer_call_fn_158405'' to object-based SavedModel as it captures 
tensor <tf.Tensor: shape=(), dtype=resource, value=<Resource Tensor>> which is 
unsupported or not reachable from root. One reason could be that a stateful object or 
a variable that the function depends on is not assigned to an attribute of the 
serialized trackable object (see SaveTest.test_captures_unreachable_variable)."

错误如果尝试 top_classify.save:

WARNING:tensorflow:Compiled the loaded model, but the compiled metrics have yet to be built. `model.compile_metrics` will be empty until you train or evaluate the model.
/usr/local/lib/python3.7/dist-packages/keras/engine/functional.py:1410: CustomMaskWarning: Custom mask layers require a config and must override get_config. When loading, the custom mask layer must be passed to the custom_objects argument.
  layer_config = serialize_layer_fn(layer)
---------------------------------------------------------------------------
OSError                                   Traceback (most recent call last)
<ipython-input-34-7275f8fa7bba> in <module>()
     18 top_classify.save("/content/top_classify", save_format='h5')
     19 # Convert the model
---> 20 converter = tf.lite.TFLiteConverter.from_saved_model(TOP_CLASSIFY_SAVE_LOC) # path to the SavedModel directory
     21 tflite_model = converter.convert()
     22 

4 frames
/usr/local/lib/python3.7/dist-packages/tensorflow/lite/python/lite.py in from_saved_model(cls, saved_model_dir, signature_keys, tags)
   1603 
   1604     with context.eager_mode():
-> 1605       saved_model = _load(saved_model_dir, tags)
   1606     if not signature_keys:
   1607       signature_keys = saved_model.signatures

/usr/local/lib/python3.7/dist-packages/tensorflow/python/saved_model/load.py in load(export_dir, tags, options)
    898     ValueError: If `tags` don't match a MetaGraph in the SavedModel.
    899   """
--> 900   result = load_internal(export_dir, tags, options)["root"]
    901   return result
    902 

/usr/local/lib/python3.7/dist-packages/tensorflow/python/saved_model/load.py in load_internal(export_dir, tags, options, loader_cls, filters)
    911     tags = nest.flatten(tags)
    912   saved_model_proto, debug_info = (
--> 913       loader_impl.parse_saved_model_with_debug_info(export_dir))
    914 
    915   if (len(saved_model_proto.meta_graphs) == 1 and

/usr/local/lib/python3.7/dist-packages/tensorflow/python/saved_model/loader_impl.py in parse_saved_model_with_debug_info(export_dir)
     58     parsed. Missing graph debug info file is fine.
     59   """
---> 60   saved_model = _parse_saved_model(export_dir)
     61 
     62   debug_info_path = file_io.join(

/usr/local/lib/python3.7/dist-packages/tensorflow/python/saved_model/loader_impl.py in parse_saved_model(export_dir)
    117   else:
    118     raise IOError(
--> 119         f"SavedModel file does not exist at: {export_dir}{os.path.sep}"
    120         f"{{{constants.SAVED_MODEL_FILENAME_PBTXT}|"
    121         f"{constants.SAVED_MODEL_FILENAME_PB}}}")

OSError: SavedModel file does not exist at: /content/top_classify/{saved_model.pbtxt|saved_model.pb}

如果您能提出解决方案或建议,我们将不胜感激。泰

经过多次详细的搜索和尝试,我找到了这个论坛post:

https://github.com/keras-team/keras/issues/15699 (在 Tensorflow 2.7 上使用数据增强层保存模型时出错 #15699)。其中指出,数据扩充可能会产生一些保存问题。

问题中没有说明,但这里是 embedding_network 的详细信息,在我的 tf 代码中:

inputs = tf.keras.Input(shape=(TARGET_SIZE, TARGET_SIZE, 3))
x0 = rescale(inputs)
x0 = data_augmentation(x0)
x0 = base_model(x0, training=False)
x0 = tf.keras.layers.GlobalAveragePooling2D()(x0)
x0 = tf.keras.layers.Dropout(DROPOUT_VAL)(x0)
outputs = tf.keras.layers.Dense(NUM_CLASSES)(x0)
embedding_network = tf.keras.Model(inputs, outputs)

如您所见,它有一个增强层,它阻止了保存。所以我创建了一个非常相似的模型,称为 embedding_network_cleany,没有增强。

inputs = tf.keras.Input(shape=(TARGET_SIZE, TARGET_SIZE, 3))
x0 = rescale(inputs)
x2 = base_model(x0, training=False)
x3 = tf.keras.layers.GlobalAveragePooling2D()(x2)
x4 = tf.keras.layers.Dropout(DROPOUT_VAL)(x3)
outputs = tf.keras.layers.Dense(NUM_CLASSES)(x4)
embedding_network_cleany = tf.keras.Model(inputs, outputs)

用 embedding_network.save_weights 复制了 embedding_network 的权重,然后加载到 embedding_network_cleany。现在我可以同时保存 top_classify 和 embedding_network_cleany 模型。也可以转换为 tflite

一个新的解决方案:

可能 AloneTogether 在 link 中给出了更好的解决方案

“解决方法是简单地使用较旧的 Keras H5 格式保存模型 model.save("test", save_format='h5')"