TensorFlow:如何以及为啥要使用 SavedModel

Posted

技术标签:

【中文标题】TensorFlow:如何以及为啥要使用 SavedModel【英文标题】:TensorFlow: How and why to use SavedModelTensorFlow:如何以及为什么要使用 SavedModel 【发布时间】:2018-03-12 20:10:15 【问题描述】:

我有几个关于SavedModel API 的问题,我发现它的documentation 留下了很多无法解释的细节。

前三个问题是关于将什么传递给tf.saved_model.builder.SavedModelBuilderadd_meta_graph_and_variables() 方法的参数,而第四个问题是关于为什么要使用SavedModel API 而不是tf.train.Saver

    signature_def_map 参数的格式是什么?保存模型时一般需要设置这个参数吗?

    同样,assets_collection 参数的格式是什么?

    为什么要保存带有元图的标签列表,而不是只给它一个名称(即只附加一个唯一的标签)?为什么要向给定的元图添加多个标签?如果我尝试通过某个标签从pb 加载metagrpah,但pb 中的多个metagrpah 与该标签匹配怎么办?

    文档认为建议使用SavedModel 将整个模型(而不是仅变量)保存在独立文件中。但tf.train.Saver 除了将变量保存在.meta 文件中之外,还会保存图形。那么使用SavedModel有什么好处呢?文档说

当您要保存和加载变量时,图表和图表的 元数据——基本上,当你想保存或恢复你的模型时——我们 推荐使用 SavedModel。 SavedModel 是一种语言中立的, 可恢复的密封序列化格式。 SavedModel 启用 用于生产、消费和转型的更高层次的系统和工具 TensorFlow 模型。

但是这个解释很抽象,并不能真正帮助我理解SavedModel 的优点是什么。使用SavedModel(而不是tf.train.Saver)会更好的具体例子是什么?

请注意,我的问题与this question 不重复。我不是在问如何保存模型,而是在问关于 SavedModel 属性的非常具体的问题,这只是 TensorFlow 提供的用于保存和加载模型的多种机制之一。链接问题中的答案均未涉及SavedModel API(这又与tf.train.Saver 不同)。

【问题讨论】:

@WendingPeng 这不是链接问题的副本,请参阅我在问题中添加的最后一段。请仔细阅读,不要轻易标记为重复。 如果您在使用 API 时遇到了问题,请将其包含在内。要求我们完整记录 API 可能对 SO 来说过于宽泛。 @E_net4 询问signature_def_map 参数的格式是一个非常具体的问题,我的其他三个问题也是如此。在我的问题中,您在哪里读到我要求任何人“完整记录”API? 再次考虑缩小范围。你有 4 个枚举点,其中至少有一个问题。当然,我们将此解释为“请比 TensorFlow 开发人员更好地记录此 API”。另一方面,拥有minimal reproducible example 让这更容易回答。 @E_net4 即使是对这四点之一的回答也会有所帮助。前三个问题都涉及相同的方法(我编辑了我的原始问题以使其更清晰),所以我希望你同意它们在主题上属于一起。再次以第一个问题为例:我在问signature_def_map 参数的输入是什么样的,因为我不明白格式。这不是一个明确的问题吗?对于任何知道这个答案的人来说,一个简单的例子,“这就是这个参数的输入看起来像这样”将是一个简单的答案。 【参考方案1】:

编辑:这是我在 TensorFlow 1.4 时写的。截至今天(TensorFlow 1.12 是稳定的,有一个 1.13rc 和 2.0 指日可待)问题中链接的文档得到了很大改进。


我正在尝试使用tf.saved_model 并且还发现文档非常(太)抽象。这是我对您问题的完整回答:

1。 signature_def_map:

一个。格式 请参阅 Tom 对Tensorflow: how to save/restore a model 的回答。 (Ctrl-F 代表“tf.saved_model”——目前,该问题上该短语的唯一用途是在他的回答中)。

b.需要 据我了解,您通常确实需要它。如果您打算使用该模型,则需要知道图形的输入和输出。我认为它类似于 C++ 函数签名:如果您打算在调用函数后或在另一个 C++ 文件中定义函数,则需要在主文件(即原型或头文件)中进行签名。

2。 assets_collection:

格式: 找不到明确的文档,所以我去了构建器source code。看来该参数是dtype=tf.string 的张量的可迭代,其中每个张量都是资产目录的路径。因此,TensorFlow Graph collection 应该可以工作。我想这是参数的同名,但从源代码中我希望 Python list 也可以工作。

(您没有问是否需要设置它,但从 Zoe 对What are assets in tensorflow? 的回答和 iga 对切线相关的Tensorflow serving: “No assets to save/writes” when exporting models 的回答来看,它通常不需要设置.)

3。标签:

一个。为什么要列出 我不知道为什么您必须传递一个列表,但您可以传递一个包含一个元素的列表。例如,在我当前的项目中,我只使用[tf...tag_constants.SERVING] 标签。

b.何时使用多个 假设您正在使用显式设备放置进行操作。也许您想保存图形的 CPU 版本和 GPU 版本。显然你想保存每个的服务版本,并说你想保存训练检查点。您可以使用 CPU/GPU 标签和训练/服务标签来管理所有案例。 docs 提示:

添加到 SavedModel 的每个 MetaGraphDef 都必须使用用户指定的标签进行注释。标签提供了一种方法来识别要加载和恢复的特定 MetaGraphDef,以及共享的变量和资产集。这些标签通常使用 MetaGraphDef 的功能(例如,服务或训练)以及可选的硬件特定方面(例如,GPU)来注释 MetaGraphDef。

c.碰撞 我懒得自己去强制碰撞——我看到两个需要解决的案例——我去了装载机source code。在def load 内部,你会看到:

saved_model = _parse_saved_model(export_dir)
found_match = False
for meta_graph_def in saved_model.meta_graphs:
  if set(meta_graph_def.meta_info_def.tags) == set(tags):
    meta_graph_def_to_load = meta_graph_def
    found_match = True
    break

if not found_match:
  raise RuntimeError(
      "MetaGraphDef associated with tags " + str(tags).strip("[]") +
      " could not be found in SavedModel. To inspect available tag-sets in"
      " the SavedModel, please use the SavedModel CLI: `saved_model_cli`"
  )

在我看来,它正在寻找完全匹配。例如。假设您有一个带有标签“GPU”和“Serving”的元图以及一个带有标签“Serving”的元图。如果您加载“服务”,您将获得后一个元图。另一方面,假设您有一个元图“GPU”和“Serving”以及一个元图“CPU”和“Serving”。如果您尝试加载“服务”,则会收到错误消息。如果您尝试在同一个文件夹中保存两个具有完全相同标签的元图,我希望您会覆盖第一个。构建代码似乎没有以任何特殊方式处理此类冲突。

4。 SavedModeltf.train.Saver:

这也让我很困惑。 wicke 对Should TensorFlow users prefer SavedModel over Checkpoint or GraphDef? 的回答为我澄清了这一点。我会投入我的两分钱:

在本地Python+TensorFlow的范围内,可以让tf.train.Saver做所有事情。但是,这会让你付出代价。让我概述一下保存训练模型并部署的用例。你需要你的保护对象。最简单的设置是保存完整的图表(每个变量)。您可能不想一直保存.meta,因为您使用的是静态图。您需要在训练钩子中指定它。你可以阅读on cv-tricks。训练完成后,您需要将检查点文件转换为 pb 文件。这通常意味着清除当前图表,恢复检查点,使用tf.python.framework.graph_util 将变量冻结为常量,然后使用tf.gfile.GFile 编写它。你可以阅读on medium。之后,您想在 Python 中部署它。您将需要输入和输出张量名称 - 图形定义中的字符串名称。您可以阅读on metaflow (实际上是tf.train.Saver 方法的一篇非常好的博文)。一些操作节点可以让您轻松地将数据输入其中。有些不是那么多。我通常放弃寻找合适的节点,并添加了一个tf.reshape,它实际上并没有对图形定义进行任何重塑。那是我的临时输入节点。输出也一样。最后,您可以部署您的模型,至少在 Python 中本地部署。

或者,您可以使用我在第 1 点中链接的答案,通过 SavedModel API 完成所有这些操作。由于汤姆的回答 ,减少了头痛 。如果有适当的文档记录,您将来会获得更多支持和功能。看起来使用命令行服务更容易(中间链接涵盖了使用Saver 执行此操作 - 看起来很难,祝你好运!)。它实际上已融入新的 Estimators。根据文档,

SavedModel 是一种语言中立、可恢复、封闭的序列化格式。

我的重点是:看起来您可以更轻松地将经过训练的模型放入不断增长的 C++ API。

在我看来,它就像 Datasets API。它只是比旧方法更容易

SavedModeltf.train.Saver 的具体示例而言:如果“基本上,当你想保存或恢复你的模型”对你来说不够清楚:使用它的正确时间是它使你的生活更轻松。对我来说,这看起来总是如此。尤其是当您使用 Estimator、在 C++ 中部署或使用命令行服务时。

这就是我对你的问题的研究。或四个列举的问题。呃,八个问号。希望这会有所帮助。

【讨论】:

我希望我能多次投票给你的好答案。非常感谢,真的。

以上是关于TensorFlow:如何以及为啥要使用 SavedModel的主要内容,如果未能解决你的问题,请参考以下文章

YII - 当你可以在 Save() 函数之前编码时,为啥要使用 beforeSave()

了解 tensorflow 中 tf.slice 的参数以及为啥我不能更改它

tensorflow训练好的模型,怎么调用?

转载:tensorflow保存训练后的模型

为啥TensorFlow要重新实现很多数学方程?

如何在 TensorFlow 中恢复多个神经网络模型?