Python Machine Learning Prediction cu un API REST Flask

Publicat: 2022-03-11

Acest articol este despre utilizarea Python în contextul unui sistem de învățare automată sau inteligență artificială (AI) pentru a face predicții în timp real, cu un API REST Flask. Arhitectura expusă aici poate fi văzută ca o modalitate de a trece de la proof of concept (PoC) la minim viable product (MVP) pentru aplicațiile de învățare automată.

Python nu este prima alegere la care se poate gândi atunci când proiectați o soluție în timp real. Dar, deoarece Tensorflow și Scikit-Learn sunt unele dintre cele mai utilizate biblioteci de învățare automată susținute de Python, este folosit convenabil în multe PoC-uri Jupyter Notebook.

Ceea ce face ca această soluție să fie fezabilă este faptul că antrenamentul necesită mult timp în comparație cu predicția. Dacă te gândești la antrenament ca la procesul de vizionare a unui film și de prezicere a răspunsurilor la întrebările despre acesta, atunci pare destul de eficient să nu fii nevoit să revii filmul după fiecare întrebare nouă.

Antrenamentul este un fel de vizualizare comprimată a acelui „film”, iar predicția înseamnă preluarea informațiilor din vizualizarea comprimată. Ar trebui să fie foarte rapid, indiferent dacă filmul a fost complex sau lung.

Să implementăm asta cu un exemplu rapid [Flask] în Python!

Arhitectură generică de învățare automată

Să începem prin a sublinia un flux de arhitectură de instruire și predicție generic:

text alt imagine

În primul rând, este creată o conductă de antrenament pentru a afla despre datele trecute în funcție de o funcție obiectivă.

Aceasta ar trebui să scoată două elemente cheie:

  1. Funcții de inginerie a caracteristicilor: transformările utilizate în timpul antrenamentului ar trebui reutilizate la momentul predicției.
  2. Parametrii modelului : algoritmul și hiperparametrii selectați în final ar trebui să fie salvați, astfel încât să poată fi reutilizați la momentul predicției

Rețineți că ingineria caracteristicilor efectuate în timpul antrenamentului trebuie salvată cu atenție pentru a fi aplicabilă predicției. O problemă obișnuită printre multe altele care pot apărea pe parcurs este scalarea caracteristicilor, care este necesară pentru mulți algoritmi.

Dacă caracteristica X1 este scalată de la valoarea 1 la 1000 și este rescalată la intervalul [0,1] cu o funcție f(x) = x/max(X1) , ce s-ar întâmpla dacă setul de predicție are o valoare de 2000?

Unele ajustări atente ar trebui gândite în avans, astfel încât funcția de mapare să returneze rezultate consistente care vor fi calculate corect la momentul predicției.

Training Machine Learning vs Predicting

Există o întrebare majoră care trebuie abordată aici. De ce separăm antrenamentul și predicția pentru început?

Este absolut adevărat că, în contextul exemplelor și cursurilor de învățare automată, în care toate datele sunt cunoscute în prealabil (inclusiv datele care urmează să fie prezise), o modalitate foarte simplă de a construi predictorul este să stivuiți datele de antrenament și predicție (numite de obicei un set de testare).

Apoi, este necesar să te antrenezi pe „setul de antrenament” și să prezici pe „setul de testare” pentru a obține rezultate, în același timp, să faci inginerie de caracteristici atât pe datele trenului, cât și pe cele de testare, antrenând și predicând în același și unic conductă. .

Cu toate acestea, în sistemele din viața reală, aveți de obicei date de antrenament, iar datele care trebuie prezise vin exact în momentul în care sunt procesate. Cu alte cuvinte, vizionați filmul la un moment dat și aveți câteva întrebări despre el mai târziu, ceea ce înseamnă că răspunsurile ar trebui să fie simple și rapide.

Mai mult, de obicei nu este necesar să reantrenați întregul model de fiecare dată când apar date noi, deoarece antrenamentul necesită timp (ar putea fi săptămâni pentru unele seturi de imagini) și ar trebui să fie suficient de stabil în timp.

De aceea antrenamentul și predicția pot fi, sau chiar ar trebui să fie, clar separate pe multe sisteme, iar acest lucru reflectă, de asemenea, mai bine modul în care un sistem inteligent (artificial sau nu) învață.

Conexiunea cu supraadaptarea

Separarea antrenamentului și a predicției este, de asemenea, o modalitate bună de a aborda problema supraadaptării.

În statistică, supraadaptarea este „producția unei analize care corespunde prea aproape sau exact unui anumit set de date și, prin urmare, poate să nu se potrivească cu date suplimentare sau să prezică în mod fiabil observațiile viitoare”.

text alt imagine

Linia verde reprezintă un model suprainstalat, iar linia neagră reprezintă un model regularizat. În timp ce linia verde urmărește cel mai bine datele de antrenament, este prea dependentă de acele date și este probabil să aibă o rată de eroare mai mare la datele noi nevăzute, în comparație cu linia neagră._

Supraadaptarea este observată în special în seturile de date cu multe caracteristici sau în seturile de date cu date de antrenament limitate. În ambele cazuri, datele au prea multe informații în comparație cu ceea ce poate fi validat de predictor, iar unele dintre ele ar putea să nu fie nici măcar legate de variabila prezisă. În acest caz, zgomotul în sine ar putea fi interpretat ca un semnal.

O modalitate bună de a controla supraajustarea este să antrenăm o parte din date și să prezicem o altă parte asupra căreia avem adevărul de bază. Prin urmare, eroarea așteptată asupra datelor noi este aproximativ eroarea măsurată pe acel set de date, cu condiția ca datele pe care le antrenăm să fie reprezentative pentru realitatea sistemului și a stărilor sale viitoare.

Deci, dacă proiectăm o conductă adecvată de instruire și predicție împreună cu o împărțire corectă a datelor, nu numai că abordăm problema supraadaptarii, ci și putem reutiliza acea arhitectură pentru a prezice date noi.

Ultimul pas ar fi controlul ca eroarea de pe datele noi să fie aceeași cu cea așteptată. Există întotdeauna o schimbare (eroarea reală este întotdeauna sub cea așteptată) și ar trebui să se determine care este o schimbare acceptabilă, dar nu acesta este subiectul acestui articol.

O API REST pentru predicție

Acolo este utilă separarea clară a antrenamentului și a predicțiilor. Dacă am salvat metodele noastre de inginerie a caracteristicilor și parametrii modelului, atunci putem construi un API REST simplu cu aceste elemente.

text alt imagine

Cheia aici este să încărcați modelul și parametrii la lansarea API-ului. Odată lansat și stocat în memorie, fiecare apel API declanșează calculul de inginerie a caracteristicilor și metoda „predict” a algoritmului ML. Ambele sunt de obicei suficient de rapide pentru a asigura un răspuns în timp real.

API-ul poate fi proiectat pentru a accepta un exemplu unic de prezis sau mai multe diferite (predicții pe lot).

Iată codul minim Python/Flask care implementează acest principiu, cu JSON introdus și JSON afară (întrebare, răspuns):

 app = Flask(__name__) @app.route('/api/makecalc/', methods=['POST']) def makecalc(): """ Function run at each API call No need to re-load the model """ # reads the received json jsonfile = request.get_json() res = dict() for key in jsonfile.keys(): # calculates and predicts res[key] = model.predict(doTheCalculation(key)) # returns a json file return jsonify(res) if __name__ == '__main__': # Model is loaded when the API is launched model = pickle.load(open('modelfile', 'rb')) app.run(debug=True)

Rețineți că API-ul poate fi folosit pentru a prezice din date noi, dar nu recomand să îl folosiți pentru antrenamentul modelului. Ar putea fi folosit, dar acest lucru complexifică codul de antrenament al modelului și ar putea fi mai solicitant în ceea ce privește resursele de memorie.

Exemplu de implementare - Bike Sharing

Să luăm ca exemplu un set de date Kaggle, bike sharing. Să presupunem că suntem o companie de bike sharing care dorește să prognozeze numărul de închirieri de biciclete în fiecare zi pentru a gestiona mai bine întreținerea bicicletei, logistica și alte aspecte ale afacerii.

text alt imagine

Închirierile depind în principal de condițiile meteorologice, așa că, odată cu prognoza meteo, acea companie ar putea să-și facă o idee mai bună când va atinge vârful chiriilor și să încerce să evite întreținerea în aceste zile.

În primul rând, antrenăm un model și îl salvăm ca obiect murat, care poate fi văzut în caietul Jupyter.

Antrenamentul și performanța modelului nu sunt tratate aici, acesta este doar un exemplu pentru înțelegerea întregului proces.

Apoi scriem transformarea datelor care se va face la fiecare apel API:

 import numpy as np import pandas as pd from datetime import date def doTheCalculation(data): data['dayofyear']=(data['dteday']- data['dteday'].apply(lambda x: date(x.year,1,1)) .astype('datetime64[ns]')).apply(lambda x: x.days) X = np.array(data[['instant','season','yr','holiday','weekday','workingday', 'weathersit','temp','atemp','hum','windspeed','dayofyear']]) return X

Acesta este doar un calcul al unei variabile (ziua anului) pentru a include atât luna, cât și ziua exactă. Există, de asemenea, o selecție de coloane și ordinea acestora care urmează să fie păstrate.

Trebuie, atunci, să scriem API-ul REST cu Flask:

 from flask import Flask, request, redirect, url_for, flash, jsonify from features_calculation import doTheCalculation import json, pickle import pandas as pd import numpy as np app = Flask(__name__) @app.route('/api/makecalc/', methods=['POST']) def makecalc(): """ Function run at each API call """ jsonfile = request.get_json() data = pd.read_json(json.dumps(jsonfile),orient='index',convert_dates=['dteday']) print(data) res = dict() ypred = model.predict(doTheCalculation(data)) for i in range(len(ypred)): res[i] = ypred[i] return jsonify(res) if __name__ == '__main__': modelfile = 'modelfile.pickle' model = pickle.load(open(modelfile, 'rb')) print("loaded OK") app.run(debug=True)

Rulați acest program, acesta va servi implicit API-ul pe portul 5000.

Dacă testăm o solicitare local, tot cu Python:

 import requests, json url = '[http://127.0.0.1:5000/api/makecalc/](http://127.0.0.1:5000/api/makecalc/)' text = json.dumps({"0":{"instant":1,"dteday":"2011-01-01T00:00:00.000Z","season":1,"yr":0,"mnth":1,"holiday":0,"weekday":6,"workingday":0,"weathersit":2,"temp":0.344167,"atemp":0.363625,"hum":0.805833,"windspeed":0.160446}, "1":{"instant":2,"dteday":"2011-01-02T00:00:00.000Z","season":1,"yr":0,"mnth":1,"holiday":0,"weekday":3,"workingday":0,"weathersit":2,"temp":0.363478,"atemp":0.353739,"hum":0.696087,"windspeed":0.248539}, "2":{"instant":3,"dteday":"2011-01-03T00:00:00.000Z","season":1,"yr":0,"mnth":1,"holiday":0,"weekday":1,"workingday":1,"weathersit":1,"temp":0.196364,"atemp":0.189405,"hum":0.437273,"windspeed":0.248309}})

Solicitarea conține toate informațiile care au fost transmise modelului. Prin urmare, modelul nostru va răspunde cu o prognoză de închiriere de biciclete pentru datele specificate (aici avem trei dintre ele).

 headers = {'content-type': 'application/json', 'Accept-Charset': 'UTF-8'} r = requests.post(url, data=text, headers=headers) print(r,r.text) <Response [200]> { "0": 1063, "1": 1028, "2": 1399 }

Asta e! Acest serviciu poate fi utilizat cu ușurință în aplicația oricărei companii, pentru planificarea întreținerii sau pentru ca utilizatorii să fie conștienți de traficul de biciclete, cererea și disponibilitatea bicicletelor de închiriat.

Punând totul împreună

Defectul major al multor sisteme de învățare automată, și în special al PoC-urilor, este combinarea antrenamentului și predicției.

Dacă sunt separate cu grijă, predicțiile în timp real pot fi efectuate destul de ușor pentru un MVP, la un cost și efort de dezvoltare destul de scăzut cu Python/Flask, mai ales dacă, pentru multe PoC-uri, a fost dezvoltat inițial cu Scikit-learn, Tensorflow, sau orice altă bibliotecă Python de învățare automată.

Cu toate acestea, acest lucru s-ar putea să nu fie fezabil pentru toate aplicațiile, în special pentru aplicațiile în care ingineria caracteristicilor este grea sau pentru aplicațiile care preiau cea mai apropiată potrivire și care trebuie să aibă cele mai recente date disponibile la fiecare apel.

În orice caz, trebuie să vizionezi filme din nou și din nou pentru a răspunde la întrebări despre ele? Aceeași regulă se aplică învățării automate!