最近在搞Keras,训练完的模型要提供个预测服务出来。就想了个办法,通过Flask提供一个http服务,后来发现也能正常跑,但是每次预测都需要加载模型,效率非常低。

然后就把模型加载到全局,每次要用的时候去拿来用就行了,可是每次去拿的时候,都会报错.

如:

ValueError: Tensor Tensor(**************) is not an element of this graph.

这个问题就是在你做预测的时候,他加载的图,不是你第一次初始化模型时候的图,所以图里面没有模型里的那些参数和节点

在网上找了个靠谱的解决方案,亲测有效,原文:https://wolfx.cn/flask-keras-server/

解决方式如下:

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():
...

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)

This works

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

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`!

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')

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()

When you need to use predict:

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

------------------------------------------------------------华丽的分割线------------------------------------------------------------

下面就上我自己的代码,解释一下如何使用:

我原来的代码是这样的:

  

 def get_angiogram_time(video_path):
start = time.time()
global _MODEL_MA,_MODEL_TIME,_GRAPH_MA, _GRAPH_TIME
if _MODEL_MA == None:
model_ma = ma_ocr.Training_Predict()
model_time = time_ocr.Training_Predict() model_ma.build_model()
model_time.build_model() model_ma.load_model("./model/ma_gur_ctc_model.h5base")
model_time.load_model("./model/time_gur_ctc_model.h5base") _MODEL_MA = model_ma
_MODEL_TIME = model_time indexes = _MODEL_MA.predict(video_path)
time_dict = _MODEL_TIME.predict(video_path,indexes)
end = time.time()
print("耗时:%.2f s" % (end-start))
return json.dumps(time_dict)
     def predict(self, video_path):
start = time.time() vid = cv2.VideoCapture(video_path)
if not vid.isOpened():
raise IOError("Couldn't open webcam or video")
# video_fps = vid.get(cv2.CAP_PROP_FPS) X = self.load_video_data(vid)
y_pred = self.base_model.predict(X)
shape = y_pred[:, :, :].shape # 2:
out = K.get_value(K.ctc_decode(y_pred[:, :, :], input_length=np.ones(shape[0]) * shape[1])[0][0])[:,
:seq_len] # 2:
print()

当实行到第10行 :y_pred = self.base_model.predict(X)

就会抛错:Cannot use the given session to evaluate tensor: the tensor's graph is different from the session's graph.

大致意思就是:当前session里的图和模型中的图的各种参数不匹配

修改后代码:

 def get_angiogram_time(video_path):
start = time.time()
global _MODEL_MA,_MODEL_TIME,_GRAPH_MA, _GRAPH_TIME
if _MODEL_MA == None:
model_ma = ma_ocr.Training_Predict()
model_time = time_ocr.Training_Predict() model_ma.build_model()
model_time.build_model() model_ma.load_model("./model/ma_gur_ctc_model.h5base")
model_time.load_model("./model/time_gur_ctc_model.h5base") _MODEL_MA = model_ma
_MODEL_TIME = model_time
_GRAPH_MA = tf.get_default_graph()
_GRAPH_TIME = tf.get_default_graph() with _GRAPH_MA.as_default():
indexes = _MODEL_MA.predict(video_path)
with _GRAPH_TIME.as_default():
time_dict = _MODEL_TIME.predict(video_path,indexes)
end = time.time()
print("耗时:%.2f s" % (end-start))
return json.dumps(time_dict)

主要修改在第16,17,19,21行

定义了一个全局的图,每次都用这个图

完美解决~

PS:问了一下专门做AI的朋友,他们公司是用TensorFlow Server提供对外服务的,我最近也要研究一下Tensorflow Server,本人是个AI小白,刚刚入门,写的不对还请指正,谢谢!

Keras + Flask 提供接口服务的坑~~~的更多相关文章

  1. 开发FTP服务接口,对外提供接口服务

    注意:本文只适合小文本文件的上传下载,因为post请求是有大小限制的.默认大小是2m,虽然具体数值可以调节,但不适合做大文件的传输 最近公司有这么个需求:以后所有的项目开发中需要使用ftp服务器的地方 ...

  2. 获取 exception 对象的字符串形式(接口服务返回给调用者)

    工具类: package com.taotao.common.utils; import java.io.PrintWriter; import java.io.StringWriter; publi ...

  3. Python flask 基于 Flask 提供 RESTful Web 服务

    转载自 http://python.jobbole.com/87118/ 什么是 REST REST 全称是 Representational State Transfer,翻译成中文是『表现层状态转 ...

  4. windows下apache + mod_wsgi + python部署flask接口服务

    windows下apache + mod_wsgi + python部署flask接口服务 用python3安装虚拟环境 为啥要装虚拟环境? 原因1:安装虚拟环境是为了使项目的环境和全局环境隔离开,在 ...

  5. docker&flask快速构建服务接口(二)

    系列其他内容 docker快速创建轻量级的可移植的容器✓ docker&flask快速构建服务接口✓ docker&uwsgi高性能WSGI服务器生产部署必备 docker&g ...

  6. 怎样提供一个好的移动API接口服务/从零到一[开发篇]

    引语:现在互联网那么热,你手里没几个APP都不好意思跟别人打招呼!但是,难道APP就是全能的神吗?答案是否定的,除了优雅的APP前端展示,其实核心还是服务器端.数据的保存.查询.消息的推送,无不是在服 ...

  7. FF.PyAdmin 接口服务/后台管理微框架 (Flask+LayUI)

    源码(有兴趣的朋友请Star一下) github: https://github.com/fufuok/FF.PyAdmin gitee: https://gitee.com/fufuok/FF.Py ...

  8. 亿级用户下的新浪微博平台架构 前端机(提供 API 接口服务),队列机(处理上行业务逻辑,主要是数据写入),存储(mc、mysql、mcq、redis 、HBase等)

    https://mp.weixin.qq.com/s/f319mm6QsetwxntvSXpKxg 亿级用户下的新浪微博平台架构 炼数成金前沿推荐 2014-12-04 序言 新浪微博在2014年3月 ...

  9. springboot+CXF开发webservice对外提供接口(转)

    文章来源:http://www.leftso.com/blog/144.html 1.项目要对外提供接口,用webservcie的方式实现 2.添加的jar包 maven: <dependenc ...

随机推荐

  1. 动态设置html根字体大小(随着设备屏幕的大小而变化,从而实现响应式)

    代码如下:如果设置了根字体大小,font-size必须是rem var html =document.querySelector('html'); html.style.fontSize = docu ...

  2. SqlServer查看锁表与解锁

    某些情况下,sqlserver的表会被锁住,比如某个会话窗口有数据一直没提交,窗口又没关闭,这时表就会被锁住 其他任何连接查询表数据时都不会返回 这时需要手工杀掉产生死锁的会话ID,才能恢复正常 查看 ...

  3. android的文件操作

    http://blog.csdn.net/fenghome/article/details/5668598 android的文件操作要有权限: <uses-permission android: ...

  4. delphi http请求用到的编码方式

    uses HttpEncode: HttpEncode(AnsiToUtf8('***'))

  5. C# 绘制矩形方框读写内存类 cs1.6人物透视例子

     封装的有问题 其中方框可能在别的方向可能 会显示不出来建议不要下载了 抽时间我会用纯c#写一个例子的  其中绘制方框文字和直线调用的外部dll采用DX11(不吃CUP)绘制我封装成了DLL命名为 S ...

  6. Problem B: Bulbs

    Problem B: Bulbs Greg has an m×n grid of Sweet Lightbulbs of Pure Coolness he would like to turn on. ...

  7. windows中的运行命令

    首先按“开始”-“运行”,或按WIN键+R,进入『运行』窗口. 下面是常用的运行命令 (按英文字符顺序排列) appwize.cpl----添加.删除程序 access.cpl-----辅助功能选项 ...

  8. Ubuntu上安装tftp服务

    1. 安装 sudo apt install tftpd-hpa 2.设置工作目录 mkdir ~/tftpdroot tftpdroot 3.修改配置文件 sudo vi /etc/default/ ...

  9. 九十二、SAP中ALV事件之六,复制一个标准工具栏到自己的程序

    一.我们来到SE41,点击复制状态按钮 二.点击复制状态后,弹出一个框框,上面是模板内容,下面是我们自己的程序 三.我们根据上一篇的标准模板内容,填好相应的模板和我们的程序的内容 三.点击复制按钮 五 ...

  10. 七十一、SAP中内表的修改,改一行数据,或一行的某个字段

    一.SAP中内表的修改,只能通过工作区来修改,代码如下 二.效果如下