我使用Django来托管机器学习服务,该服务在使用参数查询时返回预测。
我的问题是,每当有新请求进入时,它都必须import tensorflow
以及所有各种库。这使它真的很慢。 (Tensorflow会在导入时发出大量消息,加载时间为4秒)
有没有办法让库和模型持久化?
当前架构(仅限该服务):
main_app/
manage.py
classifiers/
__init__.py
util.py
views.py
lstm_predictor.py
util.py :(每次有新请求进入时都会重新加载Tensorflow!)
from sklearn.externals import joblib
import pandas as pd
import xgboost as xgb
from keras.models import load_model
from keras.preprocessing import sequence
from nltk.corpus import stopwords
import os,calendar,re
import logging
from lstm_predictor import lstm_predict
logger = logging.getLogger(__name__)
# Load models here to avoid reload every time
ensemble_final_layer = joblib.load("final_ensemble_layer.pkl")
text_processor = joblib.load("text_processor.pkl")
lstm = load_model("LSTM_2017-07-18_V0")
views.py
import json, pdb, os, hashlib
import logging
from django.core.serializers.json import DjangoJSONEncoder
from django.http.response import HttpResponse
from django.shortcuts import render
from django.views.decorators.csrf import csrf_exempt
from classifiers.util import *
logger = logging.getLogger(__name__)
@csrf_exempt
def predict(request):
result = get_prediction(params)
result_hash = {"routing_prediction":result}
data = json.dumps(result_hash, cls = jangoJSONEncoder)
return HttpResponse(data, content_type="application/json")
我是否可以将导入转移到某个地方,以便在应用启动时仅加载一次?
谢谢! :)
答案 0 :(得分:2)
这不是一个直接解决问题的答案,但是在制作依赖于直接在Django视图中执行内存和/或耗时的进程的web apis时指出了一个潜在的关键问题。
Web apis应该很轻,并尽可能快地响应。它们也应该易于使用更多流程进行扩展,而不会花费太多资源。
当直接在django中使用tensorflow时,每个django进程都会初始化自己的tensorflow模块和数据文件。这些过程也倾向于根据主进程中的规则重新启动,但我不知道Heroku上的默认行为是什么。 (我猜他们使用uwsgi
或gunicorn
)
更好的方法是将工作转移到单独的工作进程。这些进程等待队列上的传入工作。您的predict
视图只会将新作业推送到队列,并在响应中返回唯一的job_id
(仅需几毫秒)。然后,使用api的客户端可以定期提取job_id
的状态。成功完成作业后,将返回json结果。
通过这种方式,您可以拥有一台非常轻便且响应迅速的api服务器。工人数量可根据需要按比例增加和减少。工作人员也可以在不同的服务器/容器上运行。
实现此目的的一种方法是使用django_celery
,但可能还有许多其他选项。
答案 1 :(得分:1)
Django在每个请求上都不导入模块。它为每个进程记录一次。通常,您的服务器将启动多个进程来为您的站点提供服务;每一个都只会导入tensorflow - 以及任何其他模块。