Flask 的坑记录

# Flask 获取前端传递的 JSON 的坑

import json
from flask import request, Flask
# ...
data = request.get_data()
obj = json.loads(data)
1
2
3
4
5

上面的代码在 Windows 下没有问题,但在 Linux 下报错!

Linux 下的代码需要额外申明 decode:

import json
from flask import request, Flask
# ...
data = request.get_data()
obj = json.loads(data.decode("utf-8"))
1
2
3
4
5

# Flask + Keras 神经网络部署服务遇到的坑

兴冲冲的用 Flask 调用做好的 Keras 模型,没想到报了如下的错误:

ValueError: Tensor Tensor("dense_5/Sigmoid:0", shape=(?, 1), dtype=float32) is not an element of this graph.

网上有人说是线程的问题,链接:https://blog.csdn.net/leon_wzm/article/details/78434432 (opens new window)

不过经过我的测试,并不能完全解决问题。

经过一番 Google 找到了这个:https://github.com/tensorflow/tensorflow/issues/14356 (opens new window)

解决方式如下:

When you create a Model, the session hasn't been restored yet. All placeholders, variables and ops that are defined in Model.init are placed in a new graph, which makes itself a default graph inside with block. This is the key line:

with tf.Graph().as_default():
  ...
1
2

This means that this instance of tf.Graph() equals to tf.get_default_graph() instance inside with block, but not before or after it. From this moment on, there exist two different graphs.

When you later create a session and restore a graph into it, you can't access the previous instance of tf.Graph() in that session. Here's a short example:

with tf.Graph().as_default() as graph:
  var = tf.get_variable("var", shape=[3], initializer=tf.zeros_initializer)
1
2

This works

with tf.Session(graph=graph) as sess:
  sess.run(tf.global_variables_initializer())
  print(sess.run(var))  # ok because `sess.graph == graph`
1
2
3

This fails

saver = tf.train.import_meta_graph('/tmp/model.ckpt.meta')
with tf.Session() as sess:
  saver.restore(sess, "/tmp/model.ckpt")
  print(sess.run(var))   # var is from `graph`, not `sess.graph`!
1
2
3
4

The best way to deal with this is give names to all nodes, e.g. 'input', 'target', etc, save the model and then look up the nodes in the restored graph by name, something like this:

saver = tf.train.import_meta_graph('/tmp/model.ckpt.meta')
with tf.Session() as sess:
  saver.restore(sess, "/tmp/model.ckpt")
  input_data = sess.graph.get_tensor_by_name('input')
  target = sess.graph.get_tensor_by_name('target')
1
2
3
4
5

This method guarantees that all nodes will be from the graph in session.

Try to start with:

import tensorflow as tf
global graph,model
graph = tf.get_default_graph()
1
2
3

When you need to use predict:

with graph.as_default():
     y = model.predict(X)
1
2