Megjelent a FastAPI első verziója 2018 végén, és azóta egyre több alkalmazásban használják gyártásban. (lásd a FastAPI weboldalát). Ez... Ezt használjuk a motorháztető mögött az NLP Cloudnál. Ez egy nagyszerű módja annak, hogy egyszerűen és hatékonyan szolgáljuk ki a több száz természetes nyelvfeldolgozó modellünknek, az entitások kinyeréséhez (NER), a szövegosztályozáshoz, az érzelemelemelemzéshez, a kérdések kérdések megválaszolása, összegzés... Megállapítottuk, hogy a FastAPI nagyszerű módja a transzformátor-alapú mély tanulási modellekhez.
Ebben a cikkben úgy gondoltuk, hogy érdekes lenne bemutatni, hogyan valósítunk meg egy természetes nyelvfeldolgozó API-t, amely a következőn alapul Hugging Face transzformátorokra épül a FastAPI segítségével.
A FastAPI előtt alapvetően a Django Rest Framework-et használtuk a Python API-khoz, de gyorsan a FastAPI a következő okok miatt:
Ezek a nagyszerű teljesítmények teszik a FastAPI-t tökéletesen alkalmassá a gépi tanulást szolgáló API-khoz. transzformátor-alapú modelleket, mint a miénk.
Ahhoz, hogy a FastAPI működjön, összekapcsoljuk az Uvicorn ASGI szerverrel, ami a modern módja annak, hogy aszinkron Python kérések natív kezelésére az asyncio segítségével. Dönthet úgy is, hogy manuálisan telepíti a FastAPI-t az Uvicornnal, vagy letölti a kész Docker-képet. Mutassuk meg a manuális telepítést először:
pip install fastapi[all]
Akkor kezdheted el:
uvicorn main:app
Sebastián Ramírez, a FastAPI megalkotója, számos kész Docker-képet kínál, amelyekkel nagyon a FastAPI termelésben való használatát. Az Uvicorn + Gunicorn + FastAPI kép kihasználja a Gunicorn előnyeit annak érdekében, hogy több folyamatot használjon párhuzamosan. (lásd a képet itt). Végül, hála a Uvicornnak köszönhetően több FastAPI példányt is kezelhetünk egy Python folyamaton belül, a Gunicornnak köszönhetően pedig a több Python folyamatot is létrehozhatsz.
A FastAPI alkalmazás automatikusan elindul a Docker konténer indításakor a következőkkel:
docker run
.
Fontos, hogy megfelelően olvassa el ezeknek a Docker-képeknek a dokumentációját, mivel vannak olyan beállítások, amelyekkel
például a Gunicorn által létrehozott párhuzamos folyamatok számát. Alapértelmezés szerint,
a kép annyi folyamatot hoz létre, ahány CPU-mag van a gépen. De igényes
gépi tanulási modellek, például a természetes nyelvfeldolgozó transzformátorok esetében ez gyorsan több tíz GB-nyi memóriahasználatot eredményezhet. Egy
stratégia lehet a Gunicorn opció kihasználása. (--preload
), hogy betöltse
a modellt csak egyszer töltse be a memóriába, és ossza meg az összes FastAPI Python-folyamat között. Egy másik lehetőség
a Gunicorn-folyamatok számának korlátozása. Mindkettőnek vannak előnyei és hátrányai, de ez már túlmutat a
ennek a cikknek a keretein túlmutat.
A szövegosztályozás az a folyamat, amelynek során meghatározzuk, hogy egy szövegdarab miről szól (Tér? Üzletről? Élelmiszer?...). További részletek a szövegről osztályozás itt.
Olyan API végpontot szeretnénk létrehozni, amely a Facebook Bart Large MNLI segítségével végzi el a szövegosztályozást. modellt használja, amely egy előre betanított, Hugging Face transzformátorokon alapuló modell, amely tökéletesen alkalmas szöveges szövegosztályozásra.
Az API végpontunk bemenetként egy szövegdarabot fogad el, valamint lehetséges kategóriákat (úgynevezett címkéket), és minden egyes kategóriához egy pontszámot fog visszaadni (minél magasabb, annál valószínűbb).
A végpontot POST kérésekkel fogjuk lekérdezni, így:
curl "https://api.nlpcloud.io/v1/bart-large-mnli/classification" \
-H "Authorization: Token e7f6539e5a5d7a16e15" \
-X POST -d '{
"text":"John Doe is a Go Developer at Google. He has been working there for 10 years and has been awarded employee of the year.",
"labels":["job", "nature", "space"]
}'
És cserébe olyan választ kapnánk, mint:
{
"labels": [
"job",
"space",
"nature"
],
"scores": [
0.9258803129196167,
0.19384843111038208,
0.010988432914018631
]
}
Íme, hogyan érhetjük el ezt a FastAPI és a Transformers segítségével:
from fastapi import FastAPI
from pydantic import BaseModel, constr, conlist
from typing import List
from transformers import pipeline
classifier = pipeline("zero-shot-classification",
model="facebook/bart-large-mnli")
app = FastAPI()
class UserRequestIn(BaseModel):
text: constr(min_length=1)
labels: conlist(str, min_items=1)
class ScoredLabelsOut(BaseModel):
labels: List[str]
scores: List[float]
@app.post("/classification", response_model=ScoredLabelsOut)
def read_classification(user_request_in: UserRequestIn):
return classifier(user_request_in.text, user_request_in.labels)
Először is: betöltjük a Facebook Bart Large MNLI-jét a Hugging Face tárolóból, és megfelelően inicializáljuk az osztályozáshoz, hála a Transformer Pipeline-nak:
classifier = pipeline("zero-shot-classification",
model="facebook/bart-large-mnli")
Később pedig a modellt ezzel használjuk:
classifier(user_request_in.text, user_request_in.labels)
A második fontos dolog: a Pydanticnak köszönhetően elvégezzük az adatok érvényesítését. A Pydantic rákényszerít arra, hogy
előre deklarálni az API bemeneti és kimeneti formátumát, ami nagyszerű a dokumentáció szempontjából.
szempontból, de azért is, mert korlátozza a lehetséges hibákat. Go-ban nagyjából ugyanezt tennéd.
a JSON feloldásával a structokkal. Itt van egy egyszerű módja annak, hogy
deklarálni, hogy a "text" mezőnek legalább 1 karaktert kell tartalmaznia: constr(min_length=1)
.
A következő pedig azt határozza meg, hogy a címkék bemeneti listájának a listában egy elemet kell tartalmaznia:
conlist(str,
min_items=1)
.
Ez a sor azt jelenti, hogy a "labels" kimeneti mezőnek egy stringekből álló listának kell lennie: List[str]
.
Ez pedig azt jelenti, hogy a pontszámoknak lebegőlistának kell lenniük: List[float]
.
Ha a modell olyan eredményeket ad vissza, amelyek nem ezt a formátumot követik, a FastAPI automatikusan hibát jelez.
class UserRequestIn(BaseModel):
text: constr(min_length=1)
labels: conlist(str, min_items=1)
class ScoredLabelsOut(BaseModel):
labels: List[str]
scores: List[float]
Végül a következő dekorátorral könnyen megadhatjuk, hogy csak POST kéréseket fogadjunk el egy adott végponton:
@app.post("/entities", response_model=EntitiesOut)
.
Sok összetettebb érvényesítési dolgot is elvégezhet, mint például a kompozíció. Mondjuk például, hogy
Név szerinti entitások felismerését (NER) végzi, tehát a modellje egy listát ad vissza entitásokból. Minden egyes entitás
4 mezővel rendelkezik: text
, type
, start
és position
. A következő módon teheti ezt meg:
class EntityOut(BaseModel):
start: int
end: int
type: str
text: str
class EntitiesOut(BaseModel):
entities: List[EntityOut]
@app.post("/entities", response_model=EntitiesOut)
# [...]
Eddig a Pydanticra bíztuk az érvényesítést. Ez a legtöbb esetben működik, de néha szükség lehet arra, hogy a hogy dinamikusan hibát jelezzünk magunknak olyan összetett feltételek alapján, amelyeket a Pydantic nem kezel natívan. Pydantic. Ha például manuálisan szeretne egy HTTP 400 hibát visszaküldeni, akkor a következőket teheti:
from fastapi import HTTPException
raise HTTPException(status_code=400,
detail="Your request is malformed")
Természetesen sokkal többet is tehetsz!
Ha a FastAPI-t egy fordított proxy mögött használja, akkor valószínűleg a gyökér elérési útvonallal kell játszania.
A nehézséget az jelenti, hogy a fordított proxy mögött az alkalmazás nem ismeri a teljes URL-útvonalat, ezért kifejezetten meg kell mondanunk neki, hogy melyik az.
Itt például a végpontunk teljes URL címe nem egyszerűen a következő lehet /classification
. De lehet, hogy valami olyasmi, mint /api/v1/classification
. Nem akarjuk ezt a teljes URL-t keményen beprogramozni, hogy a
az API kódunk lazán kapcsolódjon az alkalmazás többi részéhez. Megtehetnénk ezt:
app = FastAPI(root_path="/api/v1")
Vagy átadhatsz egy paramétert az Uvicornnak indításkor:
uvicorn main:app --root-path /api/v1
Remélem, sikeresen megmutattuk, hogy a FastAPI milyen kényelmes lehet egy természetes nyelvi feldolgozó API számára. Pydantic teszi a kódot nagyon kifejezővé és kevésbé hibaérzékennyé teszi.
A FastAPI nagyszerű teljesítményt nyújt, és lehetővé teszi a Python asyncio használatát a dobozból, ami nagyszerű. igényes gépi tanulási modellekhez, például Transformer-alapú természetes nyelvfeldolgozási modellekhez. A FastAPI-t a következő célokra használjuk majdnem 1 éve használjuk az NLP Cloud-nál, és eddig még soha nem csalódtunk.
Ha bármilyen kérdésed van, kérlek ne habozz kérdezni, örömmel kommentálok!
Julien Salinas
CTO az NLP Cloud-nál