在内存中序列化和反序列化Tensorflow模型并继续训练

Der*_*k_M 5 python serialization keras tensorflow

我见过这个问题的不同版本,但我还没有找到令人满意的答案。基本上,我想做从 keras model.to_json()model.get_weights()model.from_json()model.set_weights()到tensorflow 的等效操作。我想我已经接近目标了,但我却陷入了困境。我更希望能够在同一个字符串中获得权重和图表,但我知道这是否不可能。

目前,我所拥有的是:

g = optimizer.minimize(loss_op,
                       global_step=tf.train.get_global_step())
de = g.graph.as_graph_def()
json_string = json_format.MessageToJson(de)

gd = tf.GraphDef()
gd = json_format.Parse(json_string, gd)
Run Code Online (Sandbox Code Playgroud)

这似乎很好地创建了图,但显然元图不包含变量、权重等。还有元图,但我唯一看到的是export_meta_graph,它似乎没有以相同的方式序列化。我看到 MetaGraph 有一个原型函数,但我不知道如何序列化这些变量。

简而言之,如何获取张量流模型(权重、图形等模型),将其序列化为字符串(最好是 json),然后反序列化并继续训练或提供预测。

以下是让我接近目标并且我已经尝试过的事情,但大多数情况下在需要写入磁盘方面都有限制,在这种情况下我无法做到这一点:

GitHub 上的要点

这是我找到的最接近的一个,但是序列化元图的链接不存在。

Max*_*xim 3

如果您想要keras Model.get_weights()和的等效项Model.set_weights(),这些方法与 keras 内部并没有紧密联系,并且可以轻松提取。

原始代码

它们在 keras 源代码中的样子如下:

def get_weights(self):
  weights = []
  for layer in self.layers:
    weights += layer.weights
  return K.batch_get_value(weights)   # this is just `get_session().run(weights)`

def set_weights(self, weights):
  tuples = []
  for layer in self.layers:
    num_param = len(layer.weights)
    layer_weights = weights[:num_param]
    for sw, w in zip(layer.weights, layer_weights):
      tuples.append((sw, w))
    weights = weights[num_param:]
  K.batch_set_value(tuples)  # another wrapper over `get_session().run(...)`
Run Code Online (Sandbox Code Playgroud)

Kerasweights是 numpy 数组(不是 json)的列表。正如您所看到的,它利用了模型架构已知的事实 ( self.layers),这使得它能够重建从变量到值的正确映射。一些看似不平凡的工作是在 中完成的K.batch_set_value,但实际上它只是准备分配操作并在会话中运行它们。

在纯张量流中获取和设置权重

def tensorflow_get_weights():
  vars = tf.trainable_variables()
  values = tf.get_default_session().run(vars)
  return zip([var.name for var in vars], values)

def tensorflow_set_weights(weights):
  assign_ops = []
  feed_dict = {}
  for var_name, value in weights:
    var = tf.get_default_session().graph.get_tensor_by_name(var_name)
    value = np.asarray(value)
    assign_placeholder = tf.placeholder(var.dtype, shape=value.shape)
    assign_op = tf.assign(var, assign_placeholder)
    assign_ops.append(assign_op)
    feed_dict[assign_placeholder] = value
  tf.get_default_session().run(assign_ops, feed_dict=feed_dict)
Run Code Online (Sandbox Code Playgroud)

在这里,我假设您想要在默认会话中序列化/反序列化整个模型(即所有可训练变量)。如果不是这种情况,可以轻松定制上述功能。

测试

x = tf.placeholder(shape=[None, 5], dtype=tf.float32, name='x')
W = tf.Variable(np.zeros([5, 5]), dtype=tf.float32, name='W')
b = tf.Variable(np.zeros([5]), dtype=tf.float32, name='b')
y = tf.add(tf.matmul(x, W), b)

with tf.Session() as session:
  session.run(tf.global_variables_initializer())

  # Save the weights
  w = tensorflow_get_weights()
  print(W.eval(), b.eval())

  # Update the model
  session.run([tf.assign(W, np.ones([5, 5])), tf.assign(b, np.ones([5]) * 2)])
  print(W.eval(), b.eval())

  # Restore the weights
  tensorflow_set_weights(w)
  print(W.eval(), b.eval())
Run Code Online (Sandbox Code Playgroud)

如果运行此测试,您应该会看到模型被冻结在零,然后更新,然后恢复到零。