我面临的情况是这样的:
我刚刚写了一个Flask应用程序,人们可以输入他们想要的文本评论,我的应用程序会从我们的数据集中返回最相似的评论。所以基本上这是一个自然语言处理项目,机器学习模型已经训练好了。现在的问题是模型大约2.5GB,每次用户输入一些东西时,它都会加载该模型来做一些计算。
我对机器学习的东西还行,但在web开发领域完全是个新手。经过一些谷歌搜索,我发现Flask中的缓存可能是解决方案,我尝试遵循本教程http://brunorocha.org/python/flask/using-flask-cache.html
然而,我未能实现它。谁能给我一些建议,告诉我正确的做法是什么?如果Flask缓存是"解决方案",我将继续关注这个东西,并希望我能做到。
我建议在运行应用程序时加载一次模型。它可以简单地在main函数中加载模型。当你第一次加载你的应用程序时,它会花一些时间,但每次当你调用预测API时,它会更快。
@app.route('/predict', methods=['POST', 'OPTIONS'])
def predict(tokenized):
global model
"do something"
return jsonify(result)
if __name__ == '__main__':
model = load_model('/model/files/model.h5')
app.run(host='0.0.0.0', port=5000)
显然,模型加载操作是时间密集且阻塞的,并且随着更新模型的大小而增加。默认情况下,Flask是阻塞的,除非你在它上面使用像uwsgi负载平衡器这样的东西,并部署n个线程或进程来确保一定程度的水平可伸缩性。假设你只有一个Flask Application的实例在运行,那么在初始化应用程序时(特别是在app.run()之前)加载更新后的模型是有意义的。您需要将其维护为全局变量,以便其上下文在整个应用程序实例中可用。您还可以添加/reload-model端点,该端点接受模型名称并更新内存中的引用,以指向已更新的模型。当然,您不会经常调用此端点,但会不时调用。
一个更好的解决方案是:
- 编写一些与主Flask应用一起运行的调度器(看看ApScheduler的BackgroundScheduler)。
- 这个调度器有一个作业,它定期轮询包含您训练过的模型的目录,并检查模型最近是否更改(使用类似https://pythonhosted.org/watchdog/的东西),如果文件已更改,调度器只是重新加载并更新全局引用变量中的模型实例引用。
我是这样做的:
- 为我的模型创建一个类文件,并加载
def __init__(self,...):
中的所有内容 - 我在全局作用域的主flask服务器文件中实例化类,在那里它可以用于我的所有函数(我从它自己的子目录中将它作为模块加载)
不确定这是不是最好的架构方式,但它很简单,在我的情况下工作得很好,我通常只需要为数据驱动模型公开几个路由,而不是根据坚实的原则设计复杂的软件!
您可以在脚本中初始化模型,而不是每次都在函数中加载模型,这样它就保留在内存中,而不必重新加载它。您可以先尝试上述方法,而不是使用flask-cache。
这是我的解决方案。
from flask import current_app
from flask import Flask
app = Flask(__name__)
@app.route("/")
def index():
current_app.model.predict_something()
if __name__ == '__main__':
with app.app_context():
current_app.model = load_your_model()
app.run()
使用global
变量不是一个好主意。