使用Flask部署Keras模型执行预测时出现报错求助
解决Keras模型Flask部署时的Tensor图错误与JSON解析问题
嘿,这个问题我太熟了!这是Keras在Flask这类多线程Web框架里部署的典型坑,咱们一步步把它搞定:
问题根源分析
首先看服务器端的报错 ValueError: Tensor ... is not an element of this graph:
- Keras加载模型时会把模型绑定到主线程的默认TensorFlow图上,但Flask的debug模式默认是多线程的,当预测请求过来时,会在子线程处理,子线程没有继承主线程的图上下文,就会出现这个“Tensor不在当前图”的错误。
- 另外,
model.predict_classes在新版TensorFlow(2.x+)的Keras里已经被弃用了,用这个方法也可能带来版本兼容问题。
而请求端的JSONDecodeError是连锁反应:服务器端抛出异常后,没有返回合法的JSON响应,请求端拿到空内容自然解析失败。
修复后的服务器代码(server.py)
咱们直接修改代码解决核心问题,同时让API更健壮:
from flask import Flask, request, jsonify import numpy as np from tensorflow.keras.models import load_model import tensorflow as tf app = Flask(__name__) # 加载模型时保存全局图和会话,确保后续预测用同一个上下文 model_path = 'dom-loc.h5' model = load_model(model_path) graph = tf.get_default_graph() session = tf.Session(graph=graph) @app.route('/api', methods=['POST']) def predict(): try: data = request.get_json(force=True) dompath = np.array(data['dompath']) # 在保存的图和会话上下文里执行预测 with graph.as_default(): with session.as_default(): # 用argmax替代已弃用的predict_classes,兼容性更好 predictions = model.predict(dompath) location = np.argmax(predictions, axis=1) output = location[0] print('OUTPUT', output) # 返回标准JSON对象,避免解析问题 return jsonify({'result': output}) except Exception as e: print(f'Error occurred: {str(e)}') # 错误时返回带信息的JSON,方便调试 return jsonify({'error': str(e)}), 500 if __name__ == '__main__': app.run(port=5000, debug=True)
关键修改点说明
- 保存了模型加载时的TensorFlow图和会话,预测时强制在这个上下文里执行,解决多线程图不匹配的问题。
- 移除了不必要的
GET方法,预测接口用POST更合理。 - 用
np.argmax(model.predict(...), axis=1)替代predict_classes,适配新版TensorFlow。 - 添加了异常捕获,错误时返回合法的JSON响应,避免请求端解析失败。
- 返回的JSON用键值对包装,符合API规范,也避免了单独返回数字可能导致的解析问题。
请求端代码优化(request.py)
其实原请求代码没问题,但加个异常处理会更健壮:
import requests url = 'http://localhost:5000/api' try: r = requests.post(url, json={'dompath':[[2, 3, 5, 1, 3, 3, 1, 5, 6, 8, 4, 8]]}) r.raise_for_status() # 检查请求是否成功(比如4xx/5xx错误) print(r.json()) except requests.exceptions.RequestException as e: print(f'Request failed: {str(e)}') except ValueError as e: print(f'JSON parse error: {str(e)}')
这样修改后,两个错误都会解决,你可以重新启动服务器再测试请求~
内容的提问来源于stack exchange,提问作者zengod
相关产品推荐
相关产品推荐

