Vaikeuksia tekoälyn tai full-stack-kehityksen kanssa? Asiantuntijamme opastavat sinua: räätälöityjä neuvoja, teknistä integrointia ja paljon muuta. Ota yhteyttä osoitteessa [email protected].

Tuotantokelpoinen koneoppimisen luonnollisen kielen prosessointirajapinta luokittelua varten FastAPI:n ja muuntajien avulla

FastAPI:n ensimmäinen versio on julkaistu vuoden 2018 lopussa, ja sitä on sen jälkeen käytetty yhä useammin monissa tuotannossa olevissa sovelluksissa. (katso FastAPIn verkkosivusto). Se on Sitä me käytämme NLP Cloudin konepellin takana. Se on loistava tapa palvella helposti ja tehokkaasti meidän satoja luonnollisen kielen prosessointimalleja, joita käytetään entiteettien poimintaan (NER), tekstiluokitteluun, tunneanalyysiin, kysymysten vastaaminen, tiivistäminen... Huomasimme, että FastAPI on loistava tapa palvella muuntajapohjaisia syviä oppimismalleja.

Tässä artikkelissa ajattelimme, että olisi mielenkiintoista näyttää, miten toteutamme luonnollisen kielen prosessointirajapinnan, joka perustuu Hugging Face -muuntajiin FastAPI:n avulla.

Miksi käyttää FastAPI:tä?

Ennen FastAPI:tä olimme käyttäneet Django Rest Framework -ympäristöä Python-API-ohjelmistoihimme, mutta olimme nopeasti kiinnostuimme FastAPI:sta seuraavista syistä:

Näiden loistavien suorituskykyjen ansiosta FastAPI soveltuu täydellisesti koneoppimisliittymiin, jotka palvelevat muuntimiin perustuvia malleja, kuten meidän.

Asenna FastAPI

Jotta FastAPI toimisi, kytkemme sen Uvicornin ASGI-palvelimeen, joka on nykyaikainen tapa tehdä käsitellä asynkronisia Python-pyyntöjä asynciolla. Voit joko päättää käyttää asentaa FastAPI:n Uvicornin kanssa manuaalisesti tai ladata valmiin Docker-kuvan. Näytetään manuaalinen asennus ensin:

pip install fastapi[all]

Sitten voit aloittaa sen:

uvicorn main:app

Sebastián Ramírez, FastAPI:n luoja, tarjoaa useita valmiita Docker-kuvia, jotka tekevät siitä erittäin helppokäyttöisen. FastAPI:n käyttäminen tuotannossa on helppoa. Uvicorn + Gunicorn + FastAPI kuva hyödyntää Gunicornia useiden prosessien rinnakkaiskäytössä. (katso kuva täältä). Loppujen lopuksi, kiitos Uvicornin ansiosta voit käsitellä useita FastAPI-instansseja samassa Python-prosessissa, ja Gunicornin ansiosta voit luoda useita Python-prosesseja.

FastAPI-sovelluksesi käynnistyy automaattisesti, kun Docker-säiliö käynnistetään seuraavalla tavalla: docker run.

On tärkeää lukea kunnolla näiden Docker-kuvien dokumentaatio, sillä on olemassa joitakin asetuksia, jotka voit kuten esimerkiksi Gunicornin luomien rinnakkaisten prosessien määrä. Oletusarvoisesti, kuva synnyttää niin monta prosessia kuin koneessasi on prosessoriytimiä. Mutta vaativien koneoppimismalleja, kuten Natural Language Processing Transformers, se voi johtaa nopeasti kymmenien gigatavujen muistin käyttöön. Yksi strategia olisi hyödyntää Gunicorn-vaihtoehtoa (--preload), ladataksesi mallisi vain kerran muistiin ja jakaa sen kaikkien FastAPI Python -prosessien kesken. Toinen vaihtoehto olisi olisi rajoittaa Gunicorn-prosessien määrää. Molemmilla on hyvät ja huonot puolensa, mutta tämä ei kuulu tämän tämän artikkelin piiriin.

Yksinkertainen FastAPI + Transformers API tekstin luokitteluun

Tekstin luokittelu on prosessi, jossa määritetään, mistä tekstissä puhutaan (Space? Liiketoiminnasta? Ruoka?...). Lisätietoja tekstistä luokittelu täällä.

Haluamme luoda API-päätepisteen, joka suorittaa tekstin luokittelun Facebookin Bart Large MNLI:n avulla. mallia, joka on valmiiksi koulutettu malli, joka perustuu Hugging Face -muuntimiin ja sopii täydellisesti tekstin käsittelyyn. luokitteluun.

API-päätepisteemme ottaa syötteenä tekstin ja mahdolliset kategoriat (nimeltä labels), ja se palauttaa kullekin luokalle pistemäärän (mitä korkeampi, sitä todennäköisempi).

Pyydämme päätepistettä POST-pyynnöillä seuraavasti:

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

Ja vastineeksi saisimme vastauksen kuten:

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

Näin se onnistuu FastAPI:n ja Transformersin avulla:

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)

Ensimmäiset asiat ensin: lataamme Facebookin Bart Large MNLI:n Hugging Face -arkistosta, ja alustamme sen asianmukaisesti luokittelua varten Transformer Pipeline -ohjelman ansiosta:

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

Myöhemmin käytämme mallia tekemällä näin:

classifier(user_request_in.text, user_request_in.labels)

Toinen tärkeä asia: suoritamme tietojen validoinnin Pydanticin ansiosta. Pydantic pakottaa sinut ilmoittamaan etukäteen API:n syöttö- ja tulostusmuodot, mikä on hyvä asia dokumentoinnin kannalta. näkökulmasta, mutta myös siksi, että se rajoittaa mahdollisia virheitä. Go-kielessä tekisit melko lailla saman asian. JSONin purkamisen kanssa structs-rakenteiden avulla. Tässä on helppo tapa ilmoittaa, että "text"-kentässä on oltava vähintään 1 merkki: constr(min_length=1). Ja seuraavassa määritetään, että syöttöluettelon tarrojen tulisi listassa sisältää yksi elementti: conlist(str, min_items=1). Tämä rivi tarkoittaa, että "labels"-ulostekentän pitäisi olla merkkijonojen luettelo: List[str]. Ja tämä tarkoittaa, että pisteiden pitäisi olla luettelo kelluvista arvoista: List[float]. Jos malli palauttaa tuloksia, jotka eivät noudata tätä muotoa, FastAPI antaa automaattisesti virheen.

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

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

Viimeiseksi, seuraavan sisustajan avulla on helppo määrittää, että hyväksyt vain POST-pyyntöjä tietyssä päätepisteessä: @app.post("/entities", response_model=EntitiesOut).

Edistyneempi tietojen validointi

Voit tehdä monia monimutkaisempia validointiasioita, kuten esimerkiksi sommittelua. Sanotaan esimerkiksi, että teet nimettyjen entiteettien tunnistusta (NER), joten mallisi palauttaa luettelon entiteeteistä. Jokainen entiteetti on 4 kenttää: text, type, start ja position. Voit tehdä sen näin:

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

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

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

Tähän asti olemme antaneet Pydanticin hoitaa validoinnin. Se toimii useimmissa tapauksissa, mutta joskus saatat haluta, että dynaamisesti herättää virheen itse perustuen monimutkaisiin ehtoihin, joita Pydantic ei käsittele luonnostaan Pydantic. Jos haluat esimerkiksi palauttaa manuaalisesti HTTP 400 -virheen, voit tehdä seuraavasti:

from fastapi import HTTPException

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

Tietenkin voit tehdä paljon enemmän!

Juuripolun asettaminen

Jos käytät FastAPI:tä käänteisen välityspalvelimen takana, sinun on todennäköisesti pelattava juuripolun kanssa.

Vaikea asia on se, että käänteisen välityspalvelimen takana sovellus ei tiedä koko URL-polkua, joten meidän on nimenomaisesti kerrottava sille, mikä se on.

Esimerkiksi tässä tapauksessa päätepisteemme täydellinen URL-osoite ei välttämättä ole yksinkertaisesti seuraava. /classification. Mutta se voisi olla jotain sellaista kuin /api/v1/classification. Emme halua kovakoodata tätä koko URL-osoitetta, jotta API-koodimme on löyhästi kytketty muuhun sovellukseen. Voisimme tehdä näin:

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

Vaihtoehtoisesti voit antaa Uvicornille parametrin, kun se käynnistetään:

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

Päätelmä

Toivottavasti näytimme onnistuneesti, kuinka kätevä FastAPI voi olla luonnollisen kielen käsittelyä varten. Pydantic tekee koodista erittäin ilmaisuvoimaiseksi ja vähemmän virhealttiiksi.

FastAPI:lla on loistava suorituskyky ja se mahdollistaa Python asyncion käytön suoraan laatikosta, mikä on hienoa. vaativille koneoppimismalleille, kuten Transformer-pohjaisille luonnollisen kielen käsittelymalleille. Olemme käyttäneet FastAPI:tä lähes vuoden ajan NLP Cloud-sivustolla, emmekä ole tähän mennessä joutuneet pettymään.

Jos jokin kysymys, älä epäröi kysyä, se on ilo kommentoida!

Julien Salinas
teknologiajohtaja, NLP Cloud