Máte problémy s AI alebo vývojom celého balíka? Naši odborníci sú tu, aby vám poradili: poradenstvo na mieru, technická integrácia a ďalšie služby. Obráťte sa na [email protected].

Rozhranie API na spracovanie prirodzeného jazyka na klasifikáciu pomocou FastAPI a transformátorov pripravené na produkciu

Bola vydaná prvá verzia FastAPI koncom roka 2018 a odvtedy sa čoraz častejšie používa v mnohých produkčných aplikáciách (pozrite si webovú stránku FastAPI). To je to, čo používame za kapotou v službe NLP Cloud. Je to skvelý spôsob, ako jednoducho a efektívne obsluhovať naše stovky modelov spracovania prirodzeného jazyka, na extrakciu entít (NER), klasifikáciu textov, analýzu nálad, analýzu otázok odpovedanie na otázky, sumarizáciu... Zistili sme, že FastAPI je skvelý spôsob, ako obsluhovať hĺbkové modely založené na transformátoroch učenia.

V tomto článku sme si mysleli, že by bolo zaujímavé ukázať vám, ako implementujeme API na spracovanie prirodzeného jazyka na základe na transformátoroch Hugging Face pomocou FastAPI.

Prečo používať FastAPI?

Pred FastAPI sme v podstate používali Django Rest Framework pre naše Python API, ale rýchlo sme FastAPI zaujalo z nasledujúcich dôvodov:

Vďaka týmto skvelým vlastnostiam sa FastAPI dokonale hodí pre rozhrania API pre strojové učenie. modely založené na transformátoroch, ako je ten náš.

Inštalácia FastAPI

Aby FastAPI fungovalo, spájame ho so serverom Uvicorn ASGI, čo je moderný spôsob, ako natívne spracúvať asynchrónne požiadavky jazyka Python pomocou asyncio. Môžete sa rozhodnúť buď pre nainštalovať FastAPI s Uvicorn ručne, alebo si stiahnuť obraz Docker pripravený na použitie. Ukážeme si najprv manuálnu inštaláciu:

pip install fastapi[all]

Potom ho môžete začať:

uvicorn main:app

Sebastián Ramírez, tvorca FastAPI, poskytuje niekoľko hotových obrazov Docker, vďaka ktorým je veľmi používať FastAPI v produkcii. Uvicorn + Gunicorn + FastAPI využíva výhody Gunicornu na paralelné používanie viacerých procesov (Pozrite si obrázok tu). Nakoniec sa vďaka Uvicorn môžete obsluhovať niekoľko inštancií FastAPI v rámci jedného procesu Python a vďaka Gunicorn môžete spustiť niekoľko procesov Python.

Vaša aplikácia FastAPI sa automaticky spustí pri spustení kontajnera Docker s nasledujúcim: docker run.

Je dôležité, aby ste si riadne prečítali dokumentáciu k týmto obrazom Docker, pretože existujú niektoré nastavenia, ktoré ako napríklad počet paralelných procesov vytvorených nástrojom Gunicorn. V predvolenom nastavení, obraz vytvára toľko procesov, koľko jadier procesora má váš počítač. Ale v prípade náročných modelov strojového učenia, ako sú transformátory spracovania prirodzeného jazyka, to môže rýchlo viesť k desiatkam GB použitej pamäte. Jedna stránka stratégiou by bolo využiť možnosť Gunicorn (--preload), na načítanie model do pamäte iba raz a zdieľať ho medzi všetkými procesmi FastAPI Python. Ďalšou možnosťou by bolo je obmedziť počet procesov Gunicorn. Obe možnosti majú svoje výhody aj nevýhody, ale to je už mimo rozsahu tohto článku.

Jednoduché rozhranie API FastAPI + Transformers na klasifikáciu textu

Klasifikácia textu je proces určovania, o čom sa v texte hovorí (Priestor? Obchod? O potravinách?...). Viac informácií o texte klasifikácia tu.

Chceme vytvoriť koncový bod API, ktorý vykonáva klasifikáciu textu pomocou aplikácie Bart Large MNLI spoločnosti Facebook ktorý je predtrénovaným modelom založeným na transformátoroch Hugging Face, ktorý sa dokonale hodí na textové na klasifikáciu textov.

Náš koncový bod API prijme ako vstup text spolu s potenciálnymi kategóriami (nazývanými štítky), a vráti skóre pre každú kategóriu (čím vyššie, tým pravdepodobnejšie).

Koncový bod budeme požadovať pomocou POST požiadaviek 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 by sme dostali odpoveď ako:

{
    "labels": [
        "job",
        "space",
        "nature"
    ],
    "scores": [
        0.9258803129196167,
        0.19384843111038208,
        0.010988432914018631
    ]
}

Tu je návod, ako to dosiahnuť pomocou 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)

Po prvé: načítame Facebook Bart Large MNLI z úložiska Hugging Face a správne ho inicializujeme na účely klasifikácie vďaka Transformer Pipeline:

classifier = pipeline("zero-shot-classification",
                model="facebook/bart-large-mnli")

A neskôr používame model týmto spôsobom:

classifier(user_request_in.text, user_request_in.labels)

Druhá dôležitá vec: vďaka Pydanticu vykonávame validáciu údajov. Pydantic vás núti vopred deklarovať vstupný a výstupný formát vášho API, čo je z hľadiska dokumentácie skvelé hľadiska, ale aj preto, že obmedzuje možné chyby. V jazyku Go by ste urobili takmer to isté s JSON unmarshalling pomocou štruktúr. Tu je jednoduchý spôsob, ako deklarovať, že pole "text" by malo mať aspoň 1 znak: constr(min_length=1). A nasledujúci príkaz určuje, že vstupný zoznam štítkov by mal v zozname obsahovať jeden prvok: conlist(str, min_items=1). Tento riadok znamená, že výstupné pole "labels" by malo byť zoznamom reťazcov: List[str]. A to znamená, že skóre by malo byť zoznamom plávajúcich hodnôt: List[float]. Ak model vracia výsledky, ktoré nedodržiavajú tento formát, FastAPI automaticky vyhlási chybu.

class UserRequestIn(BaseModel):
    text: constr(min_length=1)
    labels: conlist(str, min_items=1)

class ScoredLabelsOut(BaseModel):
    labels: List[str]
    scores: List[float]

Napokon, nasledujúci dekorátor umožňuje ľahko určiť, že prijímate len požiadavky POST na konkrétnom koncovom bode: @app.post("/entities", response_model=EntitiesOut).

Pokročilejšie overovanie údajov

Môžete vykonávať mnoho zložitejších overovacích úkonov, ako je napríklad zloženie. Povedzme napríklad, že robíte rozpoznávanie pomenovaných entít (NER), takže váš model vracia zoznam entít. Každá entita by mala 4 polia: text, type, start a position. Tu je návod, ako to môžete urobiť:

class EntityOut(BaseModel):
    start: int
    end: int
    type: str
    text: str

class EntitiesOut(BaseModel):
    entities: List[EntityOut]

@app.post("/entities", response_model=EntitiesOut) 
# [...]

Doteraz sme overovanie nechávali na Pydantic. Vo väčšine prípadov to funguje, ale niekedy môžete chcieť dynamicky vyvolať chybu sami na základe zložitých podmienok, ktoré nie sú natívne spracované Pydantic. Ak chcete napríklad ručne vrátiť chybu HTTP 400, môžete postupovať takto:

from fastapi import HTTPException

raise HTTPException(status_code=400, 
        detail="Your request is malformed")

Samozrejme, že môžete urobiť oveľa viac!

Nastavenie koreňovej cesty

Ak používate FastAPI za reverzným proxy serverom, pravdepodobne sa budete musieť pohrať s koreňovou cestou.

Problémom je, že za reverzným proxy serverom aplikácia nepozná celú cestu URL, takže jej musíme explicitne povedať, ktorá to je.

Napríklad tu nemusí byť úplná adresa URL nášho koncového bodu jednoducho /classification. Ale mohlo by to byť niečo ako /api/v1/classification. Túto úplnú adresu URL nechceme zakódovať napevno, aby aby bol náš kód API voľne previazaný so zvyškom aplikácie. Mohli by sme to urobiť takto:

app = FastAPI(root_path="/api/v1")

Prípadne môžete pri spustení programu Uvicorn odovzdať parameter:

uvicorn main:app --root-path /api/v1

Záver

Dúfam, že sme vám úspešne ukázali, aké pohodlné môže byť FastAPI pre API na spracovanie prirodzeného jazyka. Pydantic umožňuje kód veľmi expresívny a menej náchylný na chyby.

FastAPI má skvelý výkon a umožňuje používať asyncio Python z krabice, čo je skvelé pre náročné modely strojového učenia, ako sú modely spracovania prirodzeného jazyka založené na transformátore. FastAPI sme používali pre NLP Cloud takmer 1 rok a zatiaľ sme nikdy neboli sklamaní.

Ak máte akékoľvek otázky, neváhajte sa opýtať, bude nám potešením sa k nim vyjadriť!

Julien Salinas
Technický riaditeľ spoločnosti NLP Cloud