Beste praksis for belastningstesting av Amazon SageMaker sanntidsslutningsendepunkter

Beste praksis for belastningstesting av Amazon SageMaker sanntidsslutningsendepunkter

Kilde node: 1889926

Amazon SageMaker er en fullstendig administrert maskinlæringstjeneste (ML). Med SageMaker kan dataforskere og utviklere raskt og enkelt bygge og trene ML-modeller, og deretter distribuere dem direkte i et produksjonsklart vertsmiljø. Den gir en integrert Jupyter-forfatternotatbok-instans for enkel tilgang til datakildene dine for utforskning og analyse, slik at du ikke trenger å administrere servere. Det gir også felles ML-algoritmer som er optimalisert for å kjøre effektivt mot ekstremt store data i et distribuert miljø.

SageMaker sanntidsslutning er ideell for arbeidsbelastninger som har sanntids, interaktive krav med lav latens. Med SageMaker sanntidsslutning kan du distribuere REST-endepunkter som støttes av en spesifikk forekomsttype med en viss mengde databehandling og minne. Å distribuere et SageMaker-endepunkt i sanntid er bare det første trinnet i veien til produksjon for mange kunder. Vi ønsker å være i stand til å maksimere ytelsen til endepunktet for å oppnå et mål for transaksjoner per sekund (TPS) mens vi overholder latenskrav. En stor del av ytelsesoptimalisering for slutninger er å sørge for at du velger riktig forekomsttype og teller for å gå tilbake til et endepunkt.

Dette innlegget beskriver de beste fremgangsmåtene for belastningsteste et SageMaker-endepunkt for å finne riktig konfigurasjon for antall forekomster og størrelse. Dette kan hjelpe oss med å forstå minimumskravene til klargjort forekomst for å oppfylle våre latens- og TPS-krav. Derfra dykker vi inn i hvordan du kan spore og forstå beregningene og ytelsen til SageMaker-endepunktet ved å bruke Amazon CloudWatch beregninger.

Vi måler først ytelsen til modellen vår på en enkelt forekomst for å identifisere TPS-en den kan håndtere i henhold til våre akseptable latenskrav. Deretter ekstrapolerer vi funnene for å bestemme antall instanser vi trenger for å håndtere produksjonstrafikken vår. Til slutt simulerer vi trafikk på produksjonsnivå og setter opp belastningstester for et sanntids SageMaker-endepunkt for å bekrefte at endepunktet vårt kan håndtere belastningen på produksjonsnivå. Hele settet med kode for eksempelet er tilgjengelig i det følgende GitHub repository.

Oversikt over løsning

For dette innlegget distribuerer vi en forhåndsutdannet Hugging Face DistilBERT modell fra Klemmer Face Hub. Denne modellen kan utføre en rekke oppgaver, men vi sender en nyttelast spesielt for sentimentanalyse og tekstklassifisering. Med denne prøvelasten streber vi etter å oppnå 1000 TPS.

Distribuer et endepunkt i sanntid

Dette innlegget forutsetter at du er kjent med hvordan du distribuerer en modell. Referere til Lag endepunktet ditt og distribuer modellen din for å forstå det interne bak å være vert for et endepunkt. Foreløpig kan vi raskt peke på denne modellen i Hugging Face Hub og distribuere et sanntidsendepunkt med følgende kodebit:

# Hub Model configuration. https://huggingface.co/models
hub = { 'HF_MODEL_ID':'distilbert-base-uncased', 'HF_TASK':'text-classification'
} # create Hugging Face Model Class
huggingface_model = HuggingFaceModel(
transformers_version='4.17.0',
pytorch_version='1.10.2',
py_version='py38',
env=hub,
role=role,
) # deploy model to SageMaker Inference
predictor = huggingface_model.deploy(
initial_instance_count=1, # number of instances
instance_type='ml.m5.12xlarge' # ec2 instance type
)

La oss raskt teste endepunktet vårt med prøvenyttelasten som vi vil bruke for lasttesting:


import boto3
import json
client = boto3.client('sagemaker-runtime')
content_type = "application/json"
request_body = {'inputs': "I am super happy right now."}
data = json.loads(json.dumps(request_body))
payload = json.dumps(data)
response = client.invoke_endpoint(
EndpointName=predictor.endpoint_name,
ContentType=content_type,
Body=payload)
result = response['Body'].read()
result

Merk at vi støtter endepunktet ved å bruke en singel Amazon Elastic Compute Cloud (Amazon EC2) forekomst av typen ml.m5.12xlarge, som inneholder 48 vCPU og 192 GiB minne. Antall vCPUer er en god indikasjon på samtidigheten instansen kan håndtere. Generelt anbefales det å teste ulike forekomsttyper for å sikre at vi har en forekomst som har ressurser som er riktig utnyttet. For å se en fullstendig liste over SageMaker-forekomster og deres tilsvarende datakraft for sanntidsinferens, se Amazon SageMaker-priser.

Beregninger å spore

Før vi kan gå inn i belastningstesting, er det viktig å forstå hvilke beregninger som skal spores for å forstå ytelsessammenbruddet til SageMaker-endepunktet. CloudWatch er det primære loggingsverktøyet som SageMaker bruker for å hjelpe deg med å forstå de forskjellige beregningene som beskriver endepunktets ytelse. Du kan bruke CloudWatch-logger til å feilsøke endepunktsoppfordringene dine; alle logg- og utskriftsoppgaver du har i slutningskoden din, fanges opp her. For mer informasjon, se Hvordan Amazon CloudWatch fungerer.

Det er to forskjellige typer beregninger CloudWatch dekker for SageMaker: forekomstnivå og invokasjonsberegninger.

Beregninger på forekomstnivå

Det første settet med parametere å vurdere er beregningene på forekomstnivå: CPUUtilization og MemoryUtilization (for GPU-baserte forekomster, GPUUtilization). Til CPUUtilization, kan du først se prosenter over 100 % i CloudWatch. Det er viktig å innse for CPUUtilization, vises summen av alle CPU-kjernene. For eksempel, hvis forekomsten bak endepunktet ditt inneholder 4 vCPUer, betyr dette at bruksområdet er opptil 400 %. MemoryUtilization, derimot, er i området 0–100 %.

Nærmere bestemt kan du bruke CPUUtilization for å få en dypere forståelse av om du har tilstrekkelig eller til og med en overflødig mengde maskinvare. Hvis du har en underutnyttet forekomst (mindre enn 30 %), kan du potensielt skalere ned forekomsttypen. Omvendt, hvis du er rundt 80–90 % utnyttelse, vil det være en fordel å velge en instans med større databehandling/minne. Fra våre tester foreslår vi rundt 60–70 % utnyttelse av maskinvaren din.

Påkallingsberegninger

Som antydet av navnet, er påkallingsberegninger der vi kan spore ende-til-ende-forsinkelsen til alle påkallinger til endepunktet ditt. Du kan bruke påkallingsberegningene til å fange opp feiltellinger og hvilken type feil (5xx, 4xx, og så videre) som endepunktet ditt kan oppleve. Enda viktigere, du kan forstå latenssammenbruddet til endepunktsamtalene dine. Mye av dette kan fanges med ModelLatency og OverheadLatency beregninger, som illustrert i følgende diagram.

ventetider

De ModelLatency metrikk fanger opp tiden som inferens tar innenfor modellbeholderen bak et SageMaker-endepunkt. Merk at modellbeholderen også inkluderer egendefinert slutningskode eller skript som du har sendt for slutning. Denne enheten fanges opp i mikrosekunder som en invokasjonsberegning, og generelt kan du tegne en persentil på tvers av CloudWatch (p99, p90, og så videre) for å se om du når målforsinkelsen. Merk at flere faktorer kan påvirke modell- og beholderforsinkelse, for eksempel følgende:

  • Egendefinert slutningsskript – Enten du har implementert din egen beholder eller brukt en SageMaker-basert beholder med tilpassede slutningsbehandlere, er det beste praksis å profilere skriptet ditt for å fange opp alle operasjoner som spesifikt legger mye tid til ventetiden din.
  • Kommunikasjonsprotokoll – Vurder REST vs. gRPC-tilkoblinger til modellserveren i modellbeholderen.
  • Modellrammeoptimaliseringer – Dette er rammebestemt, for eksempel med tensorflow, er det en rekke miljøvariabler du kan justere som er TF-serveringsspesifikke. Sørg for å sjekke hvilken beholder du bruker, og hvis det er noen rammespesifikke optimaliseringer du kan legge til i skriptet eller som miljøvariabler for å injisere i beholderen.

OverheadLatency måles fra det tidspunktet SageMaker mottar forespørselen til den returnerer et svar til klienten, minus modellforsinkelsen. Denne delen er stort sett utenfor din kontroll og faller inn under tiden som SageMaker-kostnader tar.

End-to-end latens som helhet avhenger av en rekke faktorer og er ikke nødvendigvis summen av ModelLatency i tillegg til OverheadLatency. For eksempel, hvis klienten din lager InvokeEndpoint API-anrop over internett, fra klientens perspektiv, vil ende-til-ende-forsinkelsen være internett + ModelLatency + OverheadLatency. Som sådan, når du belastningstester endepunktet ditt for å nøyaktig benchmarke selve endepunktet, anbefales det å fokusere på endepunktberegningene (ModelLatency, OverheadLatencyog InvocationsPerInstance) for å nøyaktig benchmarke SageMaker-endepunktet. Eventuelle problemer knyttet til ende-til-ende-latens kan deretter isoleres separat.

Noen spørsmål å vurdere for ende-til-ende-forsinkelse:

  • Hvor er klienten som påkaller endepunktet ditt?
  • Er det noen mellomliggende lag mellom klienten din og SageMaker-kjøringen?

Automatisk skalering

Vi dekker ikke automatisk skalering spesifikt i dette innlegget, men det er en viktig vurdering for å kunne levere riktig antall forekomster basert på arbeidsmengden. Avhengig av trafikkmønsteret ditt kan du legge ved en retningslinjer for automatisk skalering til SageMaker-endepunktet. Det finnes ulike skaleringsalternativer, som f.eks TargetTrackingScaling, SimpleScalingog StepScaling. Dette gjør at endepunktet ditt kan skaleres inn og ut automatisk basert på trafikkmønsteret ditt.

Et vanlig alternativ er målsporing, hvor du kan spesifisere en CloudWatch-beregning eller tilpasset beregning som du har definert og skalere ut basert på det. En hyppig bruk av automatisk skalering er å spore InvocationsPerInstance metrisk. Etter at du har identifisert en flaskehals ved en bestemt TPS, kan du ofte bruke den som en beregning for å skalere ut til et større antall forekomster for å kunne håndtere toppbelastninger med trafikk. For å få en dypere oversikt over SageMaker-endepunkter for automatisk skalering, se Konfigurering av autoskalering av slutningsendepunkter i Amazon SageMaker.

Lasttesting

Selv om vi bruker Locust for å vise hvordan vi kan laste test i skala, hvis du prøver å rette størrelsen på forekomsten bak endepunktet ditt, SageMaker Inference Recommender er et mer effektivt alternativ. Med tredjeparts verktøy for belastningstesting må du manuelt distribuere endepunkter på tvers av forskjellige forekomster. Med Inference Recommender kan du ganske enkelt bestå en rekke av instanstypene du vil lastetest mot, og SageMaker vil spinne opp jobber for hvert av disse tilfellene.

Locust

For dette eksempelet bruker vi Locust, et åpen kildekode-lasttestingsverktøy som du kan implementere ved hjelp av Python. Locust ligner på mange andre åpen kildekode-lasttestverktøy, men har noen spesifikke fordeler:

  • Enkel å sette opp – Som vi demonstrerer i dette innlegget, sender vi et enkelt Python-skript som enkelt kan refaktoreres for ditt spesifikke endepunkt og nyttelast.
  • Distribuert og skalerbar – Locust er hendelsesbasert og bruker gavt under panseret. Dette er veldig nyttig for å teste svært samtidige arbeidsbelastninger og simulere tusenvis av samtidige brukere. Du kan oppnå høy TPS med en enkelt prosess som kjører Locust, men den har også en distribuert lastgenerering funksjon som lar deg skalere ut til flere prosesser og klientmaskiner, som vi vil utforske i dette innlegget.
  • Locust-beregninger og brukergrensesnitt – Locust fanger også opp ende-til-ende-latens som en beregning. Dette kan bidra til å supplere CloudWatch-beregningene dine for å tegne et fullstendig bilde av testene dine. Alt dette fanges opp i Locust UI, der du kan spore samtidige brukere, arbeidere og mer.

For å forstå Locust ytterligere, sjekk ut deres dokumentasjon.

Amazon EC2 oppsett

Du kan sette opp Locust uansett hvilket miljø som er kompatibelt for deg. For dette innlegget setter vi opp en EC2-forekomst og installerer Locust der for å utføre testene våre. Vi bruker en c5.18xlarge EC2-instans. Beregningskraften på klientsiden er også noe å vurdere. Til tider når du går tom for datakraft på klientsiden, blir dette ofte ikke fanget opp, og blir forvekslet som en SageMaker-endepunktfeil. Det er viktig å plassere klienten på et sted med tilstrekkelig datakraft som kan håndtere belastningen du tester på. For vår EC2-forekomst bruker vi en Ubuntu Deep Learning AMI, men du kan bruke hvilken som helst AMI så lenge du kan sette opp Locust på maskinen riktig. For å forstå hvordan du starter og kobler til EC2-forekomsten din, se veiledningen Kom i gang med Amazon EC2 Linux-forekomster.

Locust UI er tilgjengelig via port 8089. Vi kan åpne dette ved å justere våre innkommende sikkerhetsgrupperegler for EC2-forekomsten. Vi åpner også port 22 slik at vi kan SSH inn i EC2-forekomsten. Vurder å begrense kilden til den spesifikke IP-adressen du får tilgang til EC2-forekomsten fra.

Sikkerhetsgrupper

Etter at du er koblet til EC2-forekomsten, setter vi opp et virtuelt Python-miljø og installerer åpen kildekode Locust API via CLI:

virtualenv venv #venv is the virtual environment name, you can change as you desire
source venv/bin/activate #activate virtual environment
pip install locust

Vi er nå klare til å jobbe med Locust for lasttesting av endepunktet vårt.

Græshopptesting

Alle Locust-belastningstester er utført basert på en Locust fil som du gir. Denne Locust-filen definerer en oppgave for belastningstesten; det er her vi definerer vår Boto3 invoke_endpoint API-kall. Se følgende kode:

config = Config(
retries = { 'max_attempts': 0, 'mode': 'standard'
}
) self.sagemaker_client = boto3.client('sagemaker-runtime',config=config)
self.endpoint_name = host.split('/')[-1]
self.region = region
self.content_type = content_type
self.payload = payload

I den foregående koden, juster parametrene for påkalling av endepunktanrop for å passe til din spesifikke modellanrop. Vi bruker InvokeEndpoint API som bruker følgende kodebit i Locust-filen; dette er vårt lastetestkjøringspunkt. Locust-filen vi bruker er locust_script.py.

def send(self): request_meta = { "request_type": "InvokeEndpoint", "name": "SageMaker", "start_time": time.time(), "response_length": 0, "response": None, "context": {}, "exception": None,
}
start_perf_counter = time.perf_counter() try:
response = self.sagemaker_client.invoke_endpoint(
EndpointName=self.endpoint_name,
Body=self.payload,
ContentType=self.content_type
)
response_body = response["Body"].read()

Nå som vi har Locust-skriptet vårt klart, ønsker vi å kjøre distribuerte Locust-tester for å stressteste vår enkeltforekomst for å finne ut hvor mye trafikk forekomsten vår kan håndtere.

Locust-distribuert modus er litt mer nyansert enn en enkelt-prosess Locust-test. I distribuert modus har vi én primær og flere arbeidere. Den primære arbeideren instruerer arbeiderne om hvordan de skal spawn og kontrollere de samtidige brukerne som sender en forespørsel. I vår distributed.sh skript, ser vi som standard at 240 brukere vil bli fordelt på de 60 arbeiderne. Merk at --headless flagget i Locust CLI fjerner UI-funksjonen til Locust.

#replace with your endpoint name in format https://<<endpoint-name>>
export ENDPOINT_NAME=https://$1 export REGION=us-east-1
export CONTENT_TYPE=application/json
export PAYLOAD='{"inputs": "I am super happy right now."}'
export USERS=240
export WORKERS=60
export RUN_TIME=1m
export LOCUST_UI=false # Use Locust UI .
.
. locust -f $SCRIPT -H $ENDPOINT_NAME --master --expect-workers $WORKERS -u $USERS -t $RUN_TIME --csv results &
.
.
. for (( c=1; c<=$WORKERS; c++ ))
do
locust -f $SCRIPT -H $ENDPOINT_NAME --worker --master-host=localhost &
done

./distributed.sh huggingface-pytorch-inference-2022-10-04-02-46-44-677 #to execute Distributed Locust test

Vi kjører først den distribuerte testen på en enkelt forekomst som støtter endepunktet. Tanken her er at vi ønsker å fullt ut maksimere en enkelt forekomst for å forstå antall forekomster vi trenger for å oppnå vårt mål-TPS samtidig som vi holder oss innenfor latenskravene våre. Merk at hvis du vil ha tilgang til brukergrensesnittet, endrer du Locust_UI miljøvariabelen til True og ta den offentlige IP-en til EC2-forekomsten din og tilordne port 8089 til URL-en.

Følgende skjermbilde viser CloudWatch-beregningene våre.

CloudWatch-beregninger

Etter hvert legger vi merke til at selv om vi i utgangspunktet oppnår en TPS på 200, begynner vi å legge merke til 5xx-feil i våre EC2-klientsidelogger, som vist i følgende skjermbilde.

Vi kan også verifisere dette ved å se nærmere på beregningene våre på forekomstnivå CPUUtilization.

CloudWatch-beregningerHer merker vi CPUUtilization på nesten 4,800 %. Vår ml.m5.12x.large-instans har 48 vCPUer (48 * 100 = 4800~). Dette metter hele forekomsten, noe som også bidrar til å forklare 5xx-feilene våre. Vi ser også en økning i ModelLatency.

Det virker som om enkeltforekomsten vår blir veltet og ikke har data til å opprettholde en last forbi de 200 TPS som vi observerer. Målet vårt for TPS er 1000, så la oss prøve å øke antallet forekomster til 5. Dette må kanskje være enda mer i en produksjonsinnstilling, fordi vi observerte feil ved 200 TPS etter et visst tidspunkt.

Innstillinger for endepunkt

Vi ser i både Locust UI- og CloudWatch-loggene at vi har en TPS på nesten 1000 med fem forekomster som støtter endepunktet.

Locust

CloudWatch-beregningerHvis du begynner å oppleve feil selv med dette maskinvareoppsettet, sørg for å overvåke CPUUtilization for å forstå hele bildet bak endepunktverten din. Det er avgjørende å forstå maskinvarebruken din for å se om du trenger å skalere opp eller til og med ned. Noen ganger fører problemer på beholdernivå til 5xx-feil, men hvis CPUUtilization er lav, indikerer det at det ikke er maskinvaren din, men noe på beholder- eller modellnivå som kan føre til disse problemene (riktig miljøvariabel for antall arbeidere som ikke er angitt, for eksempel). På den annen side, hvis du merker at forekomsten din blir fullstendig mettet, er det et tegn på at du enten må øke gjeldende forekomstflåte eller prøve ut en større forekomst med en mindre flåte.

Selv om vi økte antall forekomster til 5 for å håndtere 100 TPS, kan vi se at ModelLatency metrikken er fortsatt høy. Dette skyldes at forekomstene er mettet. Generelt foreslår vi å ta sikte på å utnytte instansens ressurser mellom 60–70 %.

Rydd opp

Etter lasttesting, sørg for å rydde opp i alle ressurser du ikke vil bruke via SageMaker-konsollen eller gjennom delete_endpoint Boto3 API-kall. Sørg i tillegg for å stoppe EC2-forekomsten din eller hvilket klientoppsett du måtte ha for å ikke pådra deg ytterligere kostnader der også.

Oppsummering

I dette innlegget beskrev vi hvordan du kan lastetest ditt SageMaker-endepunkt i sanntid. Vi diskuterte også hvilke beregninger du bør evaluere når du laster endepunktet for å forstå ytelsessammenbruddet. Sørg for å sjekke ut SageMaker Inference Recommender for ytterligere å forstå forekomster av riktig størrelse og flere teknikker for ytelsesoptimalisering.


Om forfatterne

Marc Karp er en ML-arkitekt med SageMaker Service-teamet. Han fokuserer på å hjelpe kunder med å designe, distribuere og administrere ML-arbeidsmengder i stor skala. På fritiden liker han å reise og utforske nye steder.

Ram Vegiraju er en ML-arkitekt med SageMaker Service-teamet. Han fokuserer på å hjelpe kunder med å bygge og optimalisere sine AI/ML-løsninger på Amazon SageMaker. På fritiden elsker han å reise og skrive.

Tidstempel:

Mer fra AWS maskinlæring