创建 Estimator 后更改 Keras 有状态 RNN 模型、层和方法的状态

Changing states of Keras stateful RNN model, layers and methods after creating an Estimator

与独立的 keras 模型相比,使用 tf.keras.estimator.model_to_estimator 有什么好处?例如,当我们希望实时为模型提供服务时?

让我们举个例子。我有一个 Keras RNN,它是一个 stateful 模型。这意味着当实时数据进入预测时,我需要执行以下步骤:

  1. 重置模型状态
  2. 根据我们上次对该用户的预测设置状态(如果这是老用户)
  3. 运行 predict(x=x) 并保存输出的状态,用于该用户未来的预测。

在 Keras 中,我使用以下方法执行这些步骤:

old_states = [state_h, state_c]
lstm_layer = model.get_layer('lstm')
lstm_layer.reset_states(states=old_states)
pred = model.predict(x=x)
new_states_to_save = [pred[1], pred[2]]

但是,如何使用估算器执行此过程?也就是说,在: tf.keras.estimator.model_to_estimator(model) 对象?

如何访问各个图层以及如何访问 .reset_states() 方法?

型号

num_input = tf.keras.layers.Input(shape=(None, no_of_features), name='num_input', batch_size=1)
lstm, state_h, state_c = tf.keras.layers.LSTM(units=320,
                                            return_sequences=True,
                                            return_state=True,
                                            stateful=True,
                                            name='lstm')(num_input)

dense = tf.keras.layers.Dense(1, activation='sigmoid', name='main_output')(lstm_3)

model = tf.keras.models.Model(num_input, [dense, state_h, state_c])

编辑 估计器层数

How can I access individual layers and how can I access the .reset_states() method?

估算器本身是建立在 tf.keras.layers 之上的,这就是您访问图层的方式。

Estimator API 在低级核心 Tensorflow API 上提供高级 API。目的是对最终用户隐藏图形和会话的详细信息。


为什么 tf.estimator 存在?

  • 您可以 运行 在本地主机或分布式多服务器环境中使用基于估计器的模型,而无需更改您的模型。此外,您可以在 CPU、GPU 或 TPU 上 运行 基于 Estimator 的模型,而无需重新编码您的模型。

  • 估算器简化了模型开发人员之间的共享实现。您可以使用高级直观代码开发最先进的模型。简而言之,使用 Estimator 创建模型通常比使用低级 TensorFlow APIs.

  • 容易得多
  • 估算器为您构建图表。

  • 估算器提供了一个安全的分布式训练循环来控制如何以及何时:

    • 构建图表

    • 初始化变量

    • 加载数据

    • 处理异常

    • 创建检查点文件并从故障中恢复

    • 保存 TensorBoard 的摘要


方便的是 the Estimator class 详细信息。

关于 tf.Estimator

好处的几点说明

What is the benefit of using tf.keras.estimator.model_to_estimator over a stand-alone keras model? For example, when we wish to serve the model in real time?

好吧,我宁愿加上我的两分钱也不愿复制文档:

  • You can run Estimator-based models on a local host or on a distributed multi-server environment without changing your model. Furthermore, you can run Estimator-based models on CPUs, GPUs, or TPUs without recoding your model.

嗯,Keras 模型可以在 CPU 和 GPU "without recoding" 上 运行。分布式训练是有道理的,如果你需要它,也许值得 tf.Estimator 麻烦。此外,作为Tensorflow 2.0 is coming,我不会那么依赖这个高级API。方向比较明确,Tensorflow会变得更加Keras和PyTorch导向(有tf.Eagerhigh-levelAPI当涉及到第二个框架时),tf.Estimator 与它面向功能的设计并不完全符合要求。

  • Estimators simplify sharing implementations between model developers.

我能说什么,他们不会,看看SavedModel docs。使用tf.SavedModel,导出tf.Estimator创建的模型更好玩,只是让大家看看'easy'是怎样的:

feature_spec = {'foo': tf.FixedLenFeature(...),
                'bar': tf.VarLenFeature(...)}

def serving_input_receiver_fn():
  """An input receiver that expects a serialized tf.Example."""
  serialized_tf_example = tf.placeholder(dtype=tf.string,
                                         shape=[default_batch_size],
                                         name='input_example_tensor')
  receiver_tensors = {'examples': serialized_tf_example}
  features = tf.parse_example(serialized_tf_example, feature_spec)
  return tf.estimator.export.ServingInputReceiver(features, receiver_tensors)

哦,别忘了这个文档不会告诉你如何加载这个模型并在之后使用它(例如,你可以加载到当前会话中,前提是你知道输入和输出节点的名称,很容易分享这些模型,喜欢它)。

  • You can develop a state of the art model with high-level intuitive code. In short, it is generally much easier to create models with Estimators than with the low-level TensorFlow APIs.

这一点已经涵盖了,确实 tf.Estimator 比低级 Tensorflow 更直观,但我怀疑它在面对 tf.keras 时是否成功。尽管如此,通过三种不同的模式,它毫无意义地以功能为导向的设计(+ 导出的所有乐趣),会让我说它是一个中等水平的 API(拥有多个 API 总是好的)

  • Estimators are themselves built on tf.keras.layers, which simplifies customization.

好吧,那是 1.9 或 1.8 中的 tf.layers,但它已被弃用,所以这就是长期 运行.

中 Tensorflow 的良好实践

总而言之: 我不太喜欢服务(不能把我的时间浪费在下一个名字像 tf.estimator.export.build_raw_serving_input_receiver_fn 的不直观的代码上),但是由于设计不佳,您最好避免使用它。

预测也可以用 Keras 模型完成,这会节省你一些时间,但这只是我的意见。

访问各个图层

首先:tf.Estimator不像Keras模型!

How can I access individual layers and how can I access the .reset_states() method?

好吧,这就是乐趣的开始。您必须在当前会话中获取模型(例如加载导出的 tf.Estimator)并迭代图中的操作。

示意图看起来像这样:

with tf.Session() as session:
    # Of course, your tag can be different
    tf.saved_model.loader.load(session, 
                               tf.saved_model.tag_constants.SERVING, 
                               "/here/is/mymodel/exported/with/SavedModel")
    graph = tf.get_default_graph()
    # Here are all the layers of your tf.Estimator, sorted in the order they exist
    # At least they were two versions back
    operations = graph.get_operations()
    # https://www.tensorflow.org/api_docs/python/tf/contrib/framework/get_variables this should work...
    variables = tf.contrib.get_variables()

你能用这些操作做什么?那些有非常可读的名字,也许你可以那样修改它(并重置 rnn 状态)。 在获得您的操作和变量后检查

虽然这是一个远景,因为不幸的是我还没有看到这样的用例。我认为 'simplified customization'.

就差不多了

预测

好吧,更简单一点(?),您只需在加载模型后将图形输入会话中,就像低级 Tensorflow 一样:

output_names = "your_output_operation"
input_names = "your_input_operation"

with tf.Session() as session:

    # Of course, your tag can be different
    tf.saved_model.loader.load(session, 
                               tf.saved_model.tag_constants.SERVING, 
                               "/here/is/mymodel/exported/with/SavedModel")
    x = obtain_your_example_as_numpy_array()
    results = session.run(output_names, feed_dict={input_names: x})

据我所知,您可以指定多个输出名称,这个方向可能是一个可行的解决方案。要获取输入和输出名称,可以使用 SavedModel CLI or print the operations and get the ones specifying input. Usually, those will be named like: input_1:0 (for explanation of naming convention you can check ) 作为输入,使用 predictions/Softmax:0 作为输出(如果是多类分类)。您的输出名称将根据导出的模型规格、确切层等而有所不同。

希望这篇post至少能对你有所帮助

PS。我认为你能做的最好的事情就是不理会 tf.Estimator,据我所知,它无法使用,看起来像是一堆乱七八糟的黑客代码。