Byla vydána první verze rozhraní FastAPI koncem roku 2018 a od té doby se stále častěji používá v mnoha produkčních aplikacích. (viz webové stránky FastAPI). To je to, co používáme za kapotou v NLP Cloud. Je to skvělý způsob, jak snadno a efektivně obsluhovat naše stovky modelů pro zpracování přirozeného jazyka, pro extrakci entit (NER), klasifikaci textu, analýzu sentimentu, analýzu otázek a další. odpovídání na otázky, shrnutí... Zjistili jsme, že FastAPI je skvělý způsob, jak obsluhovat hluboké procesy založené na transformátorech. učení.
V tomto článku jsme si řekli, že by bylo zajímavé ukázat vám, jak implementujeme rozhraní API pro zpracování přirozeného jazyka založené na. na transformátorech Hugging Face s rozhraním FastAPI.
Před FastAPI jsme pro naše rozhraní API v jazyce Python používali v podstatě Django Rest Framework, ale rychle jsme se naučili FastAPI zaujalo z následujících důvodů:
Díky těmto skvělým parametrům se rozhraní FastAPI dokonale hodí pro rozhraní API pro strojové učení. založené na transformátorech, jako je ten náš.
Aby FastAPI fungovalo, spojujeme jej se serverem ASGI společnosti Uvicorn, což je moderní způsob, jak. nativně zpracovávat asynchronní požadavky Pythonu pomocí asyncio. Můžete se buď rozhodnout FastAPI s Uvicornem nainstalovat ručně, nebo si stáhnout hotový obraz Docker. Ukažme si nejprve ruční instalaci:
pip install fastapi[all]
Pak ji můžete začít:
uvicorn main:app
Sebastián Ramírez, tvůrce FastAPI, poskytuje několik hotových obrazů Dockeru, díky nimž je možné velmi dobře FastAPI v produkčním prostředí. Uvicorn + Gunicorn + FastAPI využívá výhod Gunicornu k paralelnímu použití několika procesů. (viz obrázek zde). Nakonec se díky Uvicorn můžete obsluhovat několik instancí FastAPI v rámci jednoho procesu Pythonu a díky Gunicorn můžete spustit několik procesů Pythonu.
Vaše aplikace FastAPI se automaticky spustí při spuštění kontejneru Docker s následujícím:
docker run.
Je důležité si řádně přečíst dokumentaci k těmto obrazům Dockeru, protože existují některá nastavení, která můžete
například počet paralelních procesů vytvořených nástrojem Gunicorn. Ve výchozím nastavení,
obraz vytváří tolik procesů, kolik je jader procesoru ve vašem počítači. Ale v případě náročných
modelů strojového učení, jako jsou Transformátory zpracování přirozeného jazyka, to může rychle vést k desítkám GB využité paměti. Jedna stránka
strategií by mohlo být využití možnosti Gunicorn. (--preload), aby bylo možné načíst
model do paměti pouze jednou a sdílet jej mezi všemi procesy FastAPI Python. Další možností je
je omezit počet procesů Gunicorn. Obě varianty mají své výhody i nevýhody, ale to už je mimo rámec tohoto článku
rozsahu tohoto článku.
Klasifikace textu je proces určování toho, o čem text vypovídá (Prostor? Obchod? O jídle?...). Další podrobnosti o textu klasifikace zde.
Chceme vytvořit koncový bod API, který provede klasifikaci textu pomocí Bart Large MNLI společnosti Facebook. což je předem natrénovaný model založený na transformátorech Hugging Face, který se dokonale hodí pro textovou klasifikaci. pro klasifikaci textů.
Náš koncový bod rozhraní API přijme jako vstup kus textu spolu s potenciálními kategoriemi (tzv. štítky), a vrátí skóre pro každou kategorii (čím vyšší, tím pravděpodobnější).
Koncový bod vyžádáme pomocí požadavků POST takto:
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"]
}'
A na oplátku bychom dostali odpověď jako:
{
"labels": [
"job",
"space",
"nature"
],
"scores": [
0.9258803129196167,
0.19384843111038208,
0.010988432914018631
]
}
Zde je návod, jak toho dosáhnout pomocí rozhraní FastAPI a Transformers:
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)
Nejdřív to nejdůležitější: načítáme Facebook's Bart Large MNLI z úložiště Hugging Face a. správně inicializujeme pro účely klasifikace díky Transformer Pipeline:
classifier = pipeline("zero-shot-classification",
model="facebook/bart-large-mnli")
A později používáme tento model:
classifier(user_request_in.text, user_request_in.labels)
Druhá důležitá věc: díky Pydanticu provádíme validaci dat. Pydantic vás nutí
předem deklarovat vstupní a výstupní formát vašeho rozhraní API, což je z hlediska dokumentace skvělé.
hlediska, ale také proto, že omezuje možné chyby. V jazyce Go byste udělali v podstatě totéž
s JSON unmarshalling pomocí struktur. Zde je jednoduchý způsob, jak
deklarovat, že pole "text" by mělo mít alespoň 1 znak: constr(min_length=1).
A následující příkaz určuje, že vstupní seznam štítků by měl v seznamu obsahovat jeden prvek:
conlist(str,
min_items=1).
Tento řádek znamená, že výstupní pole "labels" by mělo být seznamem řetězců: List[str].
A to znamená, že skóre by mělo být seznamem floatů: List[float].
Pokud model vrátí výsledky, které tento formát nedodržují, FastAPI automaticky vyhodnotí chybu.
class UserRequestIn(BaseModel):
text: constr(min_length=1)
labels: conlist(str, min_items=1)
class ScoredLabelsOut(BaseModel):
labels: List[str]
scores: List[float]
Následující dekorátor umožňuje snadno určit, že přijímáte pouze požadavky POST na konkrétním koncovém bodě:
@app.post("/entities", response_model=EntitiesOut).
Můžete provádět mnoho složitějších validací, jako je například kompozice. Řekněme například, že
provádíte rozpoznávání pojmenovaných entit (NER), takže váš model vrací seznam entit. Každá entita
bude mít 4 pole: text, type, start a position. Zde je návod, jak to můžete udělat:
class EntityOut(BaseModel):
start: int
end: int
type: str
text: str
class EntitiesOut(BaseModel):
entities: List[EntityOut]
@app.post("/entities", response_model=EntitiesOut)
# [...]
Až dosud jsme nechávali ověřování na společnosti Pydantic. Ve většině případů to funguje, ale někdy můžete chtít. dynamicky vyvolat chybu sami na základě složitých podmínek, které nejsou nativně zpracovány v systému Pydantic. Pokud například chcete ručně vrátit chybu HTTP 400, můžete postupovat následovně:
from fastapi import HTTPException
raise HTTPException(status_code=400,
detail="Your request is malformed")
Samozřejmě můžete udělat mnohem víc!
Pokud používáte rozhraní FastAPI za reverzním proxy serverem, budete si pravděpodobně muset pohrát s kořenovou cestou.
Problém je v tom, že za reverzním proxy serverem aplikace nezná celou cestu URL, takže jí musíme explicitně sdělit, která to je.
Například zde nemusí být celá adresa URL našeho koncového bodu jednoduše následující. /classification. Ale mohlo by to být něco jako /api/v1/classification. Nechceme tuto úplnou adresu URL zadávat natvrdo, aby bylo možné
aby byl náš kód API volně propojen se zbytkem aplikace. Mohli bychom to udělat takto:
app = FastAPI(root_path="/api/v1")
Případně můžete Uvicornu při spuštění předat parametr:
uvicorn main:app --root-path /api/v1
Doufám, že jsme vám úspěšně ukázali, jak výhodné může být FastAPI pro API pro zpracování přirozeného jazyka. Pydantic umožňuje kód velmi expresivní a méně náchylný k chybám.
FastAPI má skvělý výkon a umožňuje používat asyncio Pythonu hned po vybalení z krabice, což je skvělé. pro náročné modely strojového učení, jako jsou modely zpracování přirozeného jazyka založené na transformátorech. FastAPI jsme používali pro NLP Cloud téměř 1 rok a zatím nás nikdy nezklamalo.
Pokud máte nějaký dotaz, neváhejte se zeptat, bude mi potěšením se k němu vyjádřit!
Julien Salinas
Technický ředitel společnosti NLP Cloud