Susiduriate su sunkumais dirbtinio intelekto arba viso paketo kūrimo srityje? Mūsų ekspertai padės jums: teiksime pritaikytus patarimus, techninę integraciją ir dar daugiau. Kreipkitės į [email protected].

Paruošta gamybai mašininio mokymosi natūralios kalbos apdorojimo API klasifikavimui su FastAPI ir transformatoriais

Išleista pirmoji FastAPI versija 2018 m. pabaigoje ir nuo to laiko ji vis dažniau naudojama daugelyje gamybinių programų. (žr. "FastAPI" svetainę). Tai tai, ką naudojame "NLP Cloud". Tai puikus būdas lengvai ir efektyviai aptarnauti mūsų šimtus natūralios kalbos apdorojimo modelių, skirtų esybių išskyrimui (NER), teksto klasifikavimui, nuotaikų analizei, klausimų atsakymams, apibendrinimui... Nustatėme, kad FastAPI yra puikus būdas aptarnauti transformatoriais pagrįstus giliuosius mokymosi modelius.

Šiame straipsnyje manėme, kad būtų įdomu parodyti, kaip įgyvendiname natūralios kalbos apdorojimo API, pagrįstą "Hugging Face" transformatoriais su FastAPI.

Kodėl verta naudoti FastAPI?

Prieš FastAPI savo "Python" API iš esmės naudojome "Django Rest Framework", tačiau greitai susidomėjome FastAPI dėl šių priežasčių:

Dėl šių puikių savybių FastAPI puikiai tinka mašinų mokymosi API, teikiančioms transformatoriais pagrįstus modelius, tokius kaip mūsų.

Įdiekite FastAPI

Kad FastAPI veiktų, mes jį siejame su "Uvicorn" ASGI serveriu, kuris yra šiuolaikinis būdas natūraliai tvarkyti asinchronines Python užklausas su asyncio. Galite nuspręsti įdiegti FastAPI su Uvicorn rankiniu būdu arba atsisiųsti paruoštą naudoti Docker atvaizdą. Parodykime pirmiausia rankinį diegimą:

pip install fastapi[all]

Tada galite pradėti nuo:

uvicorn main:app

"FastAPI" kūrėjas Sebastiánas Ramírezas pateikia keletą paruoštų naudoti "Docker" atvaizdų, kurie leidžia labai lengva naudoti FastAPI gamyboje. Uvicorn + Gunicorn + FastAPI atvaizdas naudoja Gunicorn privalumus, kad būtų galima lygiagrečiai naudoti kelis procesus (žr. paveikslėlį čia). Galiausiai, dėka Uvicorn galite valdyti kelis FastAPI egzempliorius tame pačiame Python procese, o dėl Gunicorn galite sukurti kelis "Python" procesus.

Jūsų FastAPI programa bus automatiškai paleista paleidžiant "Docker" konteinerį su: docker run.

Svarbu tinkamai perskaityti šių "Docker" atvaizdų dokumentaciją, nes yra tam tikrų nustatymų, kuriuos pavyzdžiui, "Gunicorn" sukurtų lygiagrečiųjų procesų skaičių. Pagal numatytuosius nustatymus, atvaizdas sukuria tiek procesų, kiek jūsų kompiuteryje yra procesoriaus branduolių. Tačiau, jei reikia daug mašininio mokymosi modelius, pavyzdžiui, natūralios kalbos apdorojimo transformatorius, tai gali greitai lemti dešimtis GB naudojamos atminties. Vienas strategija būtų pasinaudoti parinktimi Gunicorn (--preload), kad būtų galima įkelti modelį į atmintį įkelti tik vieną kartą ir dalytis juo su visais FastAPI Python procesais. Kita galimybė būtų būtų apriboti "Gunicorn" procesų skaičių. Abu šie būdai turi privalumų ir trūkumų, bet tai jau ne šios šio straipsnio apimtis.

Paprasta "FastAPI" ir transformatorių API teksto klasifikavimui

Teksto klasifikavimas - tai procesas, kurio metu nustatoma, apie ką kalbama tekste (Erdvė? Verslas? Apie maistą?...). Daugiau informacijos apie tekstą klasifikacija čia.

Norime sukurti API galinį tašką, kuris atliktų teksto klasifikavimą naudodamas "Facebook" Bart Large MNLI modelį, kuris yra iš anksto apmokytas modelis, pagrįstas "Hugging Face" transformatoriais, puikiai tinkantis tekstui teksto klasifikavimui.

Mūsų API galiniame taške kaip įvestis bus priimamas teksto fragmentas ir galimos kategorijos (vadinamos etiketėmis), ir grąžins kiekvienos kategorijos balą (kuo didesnis, tuo didesnė tikimybė).

Galutinį tašką užklausime POST užklausomis taip:

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"]
}'

O atsakydami gaudavome tokį atsakymą:

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

Štai kaip tai pasiekti naudojant FastAPI ir transformatorius:

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)

Pirmiausia įkeliame "Facebook" Bart Large MNLI iš "Hugging Face" saugyklos ir tinkamai inicializuojame jį klasifikavimo tikslais, dėka Transformer Pipeline:

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

Vėliau mes naudojame modelį, tai darydami:

classifier(user_request_in.text, user_request_in.labels)

Antras svarbus dalykas: "Pydantic" dėka atliekame duomenų patvirtinimą. Pydantic priverčia jus iš anksto deklaruoti savo API įvesties ir išvesties formatą, o tai labai naudinga dokumentacijos požiūriu. požiūriu, bet ir dėl to, kad tai apriboja galimas klaidas. Go kalboje darytumėte beveik tą patį su JSON išskyrimu naudojant struktūras. Čia pateikiamas paprastas būdas deklaruoti, kad laukas "tekstas" turėtų turėti bent 1 simbolį: constr(min_length=1). Toliau nurodyta, kad įvesties etikečių sąraše turėtų būti vienas elementas: conlist(str, min_items=1). Ši eilutė reiškia, kad išvesties laukas "Labels" turėtų būti eilučių sąrašas: List[str]. O šis reiškia, kad balai turėtų būti kintamųjų sąrašas: List[float]. Jei modelis grąžina rezultatus, kurie neatitinka šio formato, FastAPI automatiškai iškels klaidą.

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

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

Galiausiai, naudojant šį dekoratorių lengva nurodyti, kad priimamos tik POST užklausos konkrečiame galiniame taške: @app.post("/entities", response_model=EntitiesOut).

Pažangesnis duomenų patvirtinimas

Galite atlikti daug sudėtingesnių patvirtinimo veiksmų, pavyzdžiui, kompoziciją. Pavyzdžiui, tarkime, kad atliekate įvardytų esybių atpažinimą (NER), taigi jūsų modelis grąžina esybių sąrašą. Kiekviena esybė turėtų 4 laukus: text, type, start ir position. Štai kaip galėtumėte tai padaryti:

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

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

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

Iki šiol leidome "Pydantic" atlikti patvirtinimą. Daugeliu atvejų tai veikia, tačiau kartais galite norėti dinamiškai iškelti klaidą patys, remdamiesi sudėtingomis sąlygomis, kurių iš prigimties nesugeba apdoroti Pydantic. Pavyzdžiui, jei norite rankiniu būdu grąžinti HTTP 400 klaidą, galite padaryti taip:

from fastapi import HTTPException

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

Žinoma, galite padaryti daug daugiau!

Šaknies kelio nustatymas

Jei naudojate "FastAPI" už atvirkštinio tarpinio serverio, greičiausiai reikės keisti šakninį kelią.

Sudėtinga tai, kad už atvirkštinio tarpinio serverio programa nežino viso URL kelio, todėl turime aiškiai nurodyti, kuris tai yra.

Pavyzdžiui, šiuo atveju pilnas mūsų galinio taško URL gali būti ne tik /classification. Tačiau tai gali būti kažkas panašaus į /api/v1/classification. Nenorime užkoduoti šio pilno URL adreso, kad mūsų API kodas būtų laisvai susietas su likusia programos dalimi. Galėtume padaryti taip:

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

Arba galite perduoti parametrą "Uvicorn" paleidimo metu:

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

Išvada

Tikiuosi, kad sėkmingai parodėme, kokia patogi FastAPI gali būti natūralios kalbos apdorojimo API. Pydantic leidžia kodą labai išraiškingas ir mažiau linkęs į klaidas.

"FastAPI" pasižymi puikiomis savybėmis ir leidžia naudoti "Python" asyncio iškart, o tai yra puiku. reikliems mašininio mokymosi modeliams, pavyzdžiui, transformatoriais pagrįstiems natūralios kalbos apdorojimo modeliams. Mes naudojome FastAPI NLP Cloud beveik 1 metus ir iki šiol niekada nenusivylėme.

Jei turite klausimų, nedvejodami klauskite, bus malonu komentuoti!

Julien Salinas
NLP Cloud techninis direktorius