2017-07-18 23 views
0

我使用Django來託管一個機器學習服務,該服務在使用參數查詢時返回預測結果。持久性庫而不是重複導入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

它只會加載一次,因爲模塊是單身人士,但是當您使用'uwsgi'或類似工具部署它時,您將運行多個進程,因此它將爲每個進程加載一次。 – Grimmy

+0

@Grimmy你好,謝謝你的回覆!它沒有。查看日誌,每當有新的請求進入時,tensorflow就會重新加載。(當您第一次導入時,Tensorflow會給出一串消息) – Wboy

+0

當您在'./manage.py shell'中多次導入'util'時是否也會發生這種情況?那會很奇怪。 – Grimmy

回答

2

這並不是直接回答這個問題的答案,但是指出了一個潛在的關鍵問題,即當網絡apis依賴直接在Django視圖中完成內存和/或耗時的進程時。

Web apis應該是亮的,並儘可能快地迴應。他們也應該可以輕鬆擴展更多流程,而不會花費太多資源。

當直接在django中使用tensorflow時,每個django進程都會初始化他們自己的tensorflow模塊和數據文件。這些進程也傾向於根據主進程中的規則重新啓動,但我不知道Heroku的默認行爲。 (我猜他們使用uwsgigunicorn

更好的辦法是將工作轉移到單獨的工作進程。這些進程等待隊列中的傳入工作。您的predict視圖只會將新作業推送到隊列中,並在響應中返回唯一的job_id(僅需幾毫秒)。然後使用api的客戶端可以定期提取該job_id的狀態。當作業成功完成時,它將返回json結果。

這樣你就可以擁有一個非常輕便和響應的api服務器。工人的數量可以根據需要放大和縮小。工作人員也可以在不同的服務器/容器上運行。

實現此目的的一種方法是使用django_celery,但可能有很多其他選項。

+0

明白了,謝謝! :) – Wboy

1

Django確實不是每個請求導入模塊。它爲每個進程記錄一次。通常,您的服務器將啓動多個進程來爲您的網站提供服務;每個人只會輸入張量流量和任何其他模塊。

+0

嗨@丹尼爾,所以如果我正確地理解你 - 即使我看到「使用tensorflow後端」消息與新的請求,它是因爲一個新的進程正在旋轉起來處理它? – Wboy

+0

@Wboy我會說這可能是這種情況。我在我的問題中也添加了一條評論。我懷疑Heroku可能會因爲速度緩慢或使用太多內存而殺死進程。規則可能可以配置。 – Grimmy