Cele mai bune practici pentru testarea încărcării punctelor finale de inferență în timp real Amazon SageMaker

Cele mai bune practici pentru testarea încărcării punctelor finale de inferență în timp real Amazon SageMaker

Nodul sursă: 1889926

Amazon SageMaker este un serviciu de învățare automată (ML) complet gestionat. Cu SageMaker, oamenii de știință de date și dezvoltatorii pot construi și antrena rapid și ușor modele ML, apoi le pot implementa direct într-un mediu găzduit pregătit pentru producție. Oferă o instanță de notebook de autor Jupyter integrată pentru acces ușor la sursele de date pentru explorare și analiză, astfel încât să nu fie nevoie să gestionați serverele. De asemenea, oferă comun Algoritmi ML care sunt optimizate pentru a rula eficient împotriva datelor extrem de mari într-un mediu distribuit.

Inferența în timp real SageMaker este ideală pentru sarcinile de lucru care au cerințe în timp real, interactive și cu latență scăzută. Cu inferența în timp real SageMaker, puteți implementa puncte finale REST care sunt susținute de un anumit tip de instanță cu o anumită cantitate de calcul și memorie. Implementarea unui punct final în timp real SageMaker este doar primul pas în calea către producție pentru mulți clienți. Dorim să putem maximiza performanța punctului final pentru a atinge o țintă de tranzacții pe secundă (TPS), respectând în același timp cerințele de latență. O mare parte a optimizării performanței pentru inferență este să vă asigurați că selectați tipul de instanță adecvat și numărați pentru un punct final.

Această postare descrie cele mai bune practici pentru testarea încărcării unui punct final SageMaker pentru a găsi configurația potrivită pentru numărul de instanțe și dimensiune. Acest lucru ne poate ajuta să înțelegem cerințele minime ale instanțelor furnizate pentru a îndeplini cerințele noastre de latență și TPS. De acolo, analizăm cum puteți urmări și înțelege valorile și performanța punctului final SageMaker utilizând Amazon CloudWatch valori.

Mai întâi evaluăm performanța modelului nostru pe o singură instanță pentru a identifica TPS-ul pe care îl poate gestiona conform cerințelor noastre de latență acceptabile. Apoi extrapolăm rezultatele pentru a decide asupra numărului de instanțe de care avem nevoie pentru a gestiona traficul nostru de producție. În cele din urmă, simulăm traficul la nivel de producție și setăm teste de încărcare pentru un punct final SageMaker în timp real pentru a confirma că punctul nostru final poate gestiona sarcina la nivel de producție. Întregul set de cod pentru exemplu este disponibil în cele ce urmează GitHub depozit.

Prezentare generală a soluției

Pentru această postare, implementăm un pre-instruit Hugging Face model DistilBERT de la Hugging Face Hub. Acest model poate îndeplini o serie de sarcini, dar trimitem o sarcină utilă special pentru analiza sentimentelor și clasificarea textului. Cu acest exemplu de încărcare utilă, ne străduim să atingem 1000 TPS.

Implementați un punct final în timp real

Această postare presupune că sunteți familiarizat cu modul de implementare a unui model. A se referi la Creați punctul final și implementați modelul pentru a înțelege elementele interne din spatele găzduirii unui punct final. Pentru moment, putem indica rapid acest model în Hugging Face Hub și implementăm un punct final în timp real cu următorul fragment de cod:

# 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
)

Să ne testăm rapid punctul final cu exemplul de încărcare utilă pe care dorim să o folosim pentru testarea încărcării:


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

Rețineți că susținem punctul final folosind un singur Cloud Elastic de calcul Amazon (Amazon EC2) instanță de tip ml.m5.12xlarge, care conține 48 vCPU și 192 GiB de memorie. Numărul de vCPU-uri este un bun indiciu al concurenței pe care o poate gestiona instanța. În general, este recomandat să testați diferite tipuri de instanțe pentru a vă asigura că avem o instanță care are resurse care sunt utilizate corespunzător. Pentru a vedea o listă completă a instanțelor SageMaker și puterea lor de calcul corespunzătoare pentru Inferență în timp real, consultați Prețuri Amazon SageMaker.

Valori de urmărit

Înainte de a putea începe testarea încărcării, este esențial să înțelegem ce valori trebuie urmărite pentru a înțelege defalcarea performanței punctului final SageMaker. CloudWatch este instrumentul de înregistrare principal pe care SageMaker îl folosește pentru a vă ajuta să înțelegeți diferitele valori care descriu performanța punctului final. Puteți utiliza jurnalele CloudWatch pentru a depana invocările punctelor finale; toate declarațiile de înregistrare și tipărire pe care le aveți în codul de inferență sunt capturate aici. Pentru mai multe informații, consultați Cum funcționează Amazon CloudWatch.

Există două tipuri diferite de valori pe care CloudWatch acoperă pentru SageMaker: valori la nivel de instanță și invocare.

Valori la nivel de instanță

Primul set de parametri de luat în considerare sunt valorile la nivel de instanță: CPUUtilization și MemoryUtilization (pentru instanțe bazate pe GPU, GPUUtilization). Pentru CPUUtilization, este posibil să vedeți procente de peste 100% la început în CloudWatch. Este important să realizezi pentru CPUUtilization, este afișată suma tuturor nucleelor ​​CPU. De exemplu, dacă instanța din spatele punctului final conține 4 vCPU-uri, aceasta înseamnă că intervalul de utilizare este de până la 400%. MemoryUtilization, pe de altă parte, este în intervalul 0-100%.

Mai exact, puteți folosi CPUUtilization pentru a înțelege mai profund dacă aveți suficientă sau chiar exces de hardware. Dacă aveți o instanță subutilizată (mai puțin de 30%), ați putea reduce tipul de instanță. În schimb, dacă aveți o utilizare în jur de 80–90%, ar fi avantajos să alegeți o instanță cu calcul/memorie mai mare. Din testele noastre, vă sugerăm utilizarea în jur de 60–70% a hardware-ului dumneavoastră.

Valori de invocare

După cum sugerează și numele, valorile de invocare sunt locul în care putem urmări latența de la capăt la capăt a oricăror invocări către punctul dvs. final. Puteți utiliza valorile de invocare pentru a captura numărul de erori și ce tipuri de erori (5xx, 4xx și așa mai departe) le poate întâmpina punctul final. Mai important, puteți înțelege defalcarea latenței apelurilor dvs. terminale. Multe dintre acestea pot fi capturate cu ajutorul ModelLatency și OverheadLatency metrici, așa cum este ilustrat în diagrama următoare.

latențe

ModelLatency metrica surprinde timpul pe care îl ia inferența în containerul model din spatele unui punct final SageMaker. Rețineți că containerul de model include, de asemenea, orice cod de inferență personalizat sau scripturi pe care le-ați transmis pentru deducere. Această unitate este capturată în microsecunde ca măsurătoare de invocare și, în general, puteți reprezenta grafic o percentilă în CloudWatch (p99, p90 și așa mai departe) pentru a vedea dacă vă atingeți latența țintă. Rețineți că mai mulți factori pot afecta latența modelului și a containerului, cum ar fi următorii:

  • Script de inferență personalizat – Indiferent dacă ați implementat propriul container sau ați folosit un container bazat pe SageMaker cu handlere de inferență personalizate, cea mai bună practică este să vă profilați scriptul pentru a captura orice operațiuni care adaugă în mod special mult timp latenței.
  • Protocol de comunicare – Luați în considerare conexiunile REST vs. gRPC la serverul model din containerul model.
  • Optimizări ale cadrului de model – Acesta este specific cadrului, de exemplu cu TensorFlow, există o serie de variabile de mediu pe care le puteți regla, care sunt specifice Servirii TF. Asigurați-vă că verificați ce container utilizați și dacă există optimizări specifice cadrului pe care le puteți adăuga în script sau ca variabile de mediu de injectat în container.

OverheadLatency este măsurată din momentul în care SageMaker primește cererea până când returnează un răspuns clientului, minus latența modelului. Această parte este în mare parte în afara controlului dumneavoastră și se încadrează în timpul necesar cheltuielilor generale SageMaker.

Latența end-to-end în ansamblu depinde de o varietate de factori și nu este neapărat suma ModelLatency la care se adauga OverheadLatency. De exemplu, dacă clientul dvs. face InvokeEndpoint Apelul API prin internet, din perspectiva clientului, latența end-to-end ar fi internet + ModelLatency + OverheadLatency. Ca atare, atunci când testați încărcarea punctului final pentru a evalua cu exactitate punctul final în sine, este recomandat să vă concentrați pe valorile punctului final (ModelLatency, OverheadLatency, și InvocationsPerInstance) pentru a evalua cu precizie punctul final SageMaker. Orice probleme legate de latența end-to-end pot fi apoi izolate separat.

Câteva întrebări de luat în considerare pentru latența end-to-end:

  • Unde este clientul care vă invocă punctul final?
  • Există straturi intermediare între clientul dumneavoastră și runtime SageMaker?

Scalare automată

Nu acoperim în mod specific scalarea automată în această postare, dar este un aspect important pentru a furniza numărul corect de instanțe în funcție de volumul de lucru. În funcție de tiparele de trafic, puteți atașa un politica de scalare automată la punctul final SageMaker. Există diferite opțiuni de scalare, cum ar fi TargetTrackingScaling, SimpleScaling, și StepScaling. Acest lucru vă permite punctului final să crească și să reducă automat în funcție de modelul dvs. de trafic.

O opțiune obișnuită este urmărirea țintei, în care puteți specifica o valoare CloudWatch sau o măsură personalizată pe care ați definit-o și scala în funcție de aceasta. O utilizare frecventă a scalarii automate este urmărirea InvocationsPerInstance metric. După ce ați identificat un blocaj la un anumit TPS, îl puteți folosi adesea ca măsură pentru a scala la un număr mai mare de instanțe pentru a putea face față volumului de trafic maxim. Pentru a obține o defalcare mai detaliată a punctelor finale SageMaker cu scalare automată, consultați Configurarea punctelor finale de inferență cu scalare automată în Amazon SageMaker.

Testare de sarcină

Deși utilizăm Locust pentru a afișa modul în care putem încărca testul la scară, dacă încercați să dimensionați corect instanța din spatele punctului final, Recomandator SageMaker Inference este o varianta mai eficienta. Cu instrumente terțe de testare a încărcării, trebuie să implementați manual punctele finale în diferite instanțe. Cu Inference Recommender, puteți pur și simplu să treceți o serie de tipuri de instanțe cu care doriți să încărcați testul, iar SageMaker va apărea de locuri de muncă pentru fiecare dintre aceste cazuri.

roșcov

Pentru acest exemplu, folosim roșcov, un instrument open-source de testare a încărcării pe care îl puteți implementa folosind Python. Locust este similar cu multe alte instrumente de testare a încărcării open-source, dar are câteva beneficii specifice:

  • Ușor de configurat – După cum demonstrăm în această postare, vom transmite un script Python simplu care poate fi refactorizat cu ușurință pentru punctul final și sarcina utilă.
  • Distribuit și scalabil – Locust se bazează pe evenimente și folosește gevent sub capotă. Acest lucru este foarte util pentru testarea sarcinilor de lucru extrem de simultane și pentru simularea a mii de utilizatori concurenți. Puteți obține un TPS ridicat cu un singur proces care rulează Locust, dar are și un generarea de sarcină distribuită caracteristică care vă permite să scalați la mai multe procese și mașini client, așa cum vom explora în această postare.
  • Valori și interfață de utilizare Locust – Locust captează, de asemenea, latența de la capăt la capăt ca măsurătoare. Acest lucru vă poate ajuta să vă completați valorile CloudWatch pentru a vă prezenta o imagine completă a testelor dvs. Toate acestea sunt capturate în interfața de utilizare Locust, unde puteți urmări utilizatorii, lucrătorii și multe altele concurente.

Pentru a înțelege mai bine Locust, consultați-le documentaţie.

Configurare Amazon EC2

Puteți configura Locust în orice mediu este compatibil pentru dvs. Pentru această postare, am configurat o instanță EC2 și am instalat Locust acolo pentru a ne efectua testele. Folosim o instanță EC5.18 c2xlarge. Puterea de calcul la nivelul clientului este, de asemenea, ceva de luat în considerare. Uneori, când rămâneți fără putere de calcul din partea clientului, aceasta nu este adesea capturată și este confundată ca o eroare de punct final SageMaker. Este important să vă plasați clientul într-o locație cu o putere de calcul suficientă care poate face față sarcinii la care testați. Pentru instanța noastră EC2, folosim un Ubuntu Deep Learning AMI, dar puteți utiliza orice AMI atâta timp cât puteți configura corect Locust pe computer. Pentru a înțelege cum să lansați și să vă conectați la instanța dvs. EC2, consultați tutorialul Începeți cu instanțele Amazon EC2 Linux.

Interfața de utilizare Locust este accesibilă prin portul 8089. Putem deschide acest lucru ajustând regulile grupului de securitate de intrare pentru Instanța EC2. De asemenea, deschidem portul 22, astfel încât să putem SSH în instanța EC2. Luați în considerare limitarea sursei la adresa IP specifică de la care accesați instanța EC2.

Grupuri de securitate

După ce vă conectați la instanța dvs. EC2, configuram un mediu virtual Python și instalăm API-ul Locust cu sursă deschisă prin intermediul 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

Acum suntem gata să lucrăm cu Locust pentru a testa punctul nostru final.

Testarea lacustelor

Toate testele de sarcină Locust sunt efectuate pe baza a Dosar lăcuste pe care le oferi. Acest fișier Locust definește o sarcină pentru testul de încărcare; aici definim Boto3 apel API invoke_endpoint. Consultați următorul cod:

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

În codul precedent, ajustați parametrii de apel pentru punctul final de invocare pentru a se potrivi cu invocarea modelului dvs. specific. Noi folosim InvokeEndpoint API folosind următoarea bucată de cod din fișierul Locust; acesta este punctul nostru de rulare a testului de încărcare. Fișierul Locust pe care îl folosim este 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()

Acum că avem scriptul Locust gata, dorim să rulăm teste Locust distribuite pentru a testa instanța noastră unică pentru a afla cât trafic poate gestiona instanța noastră.

Modul distribuit Locust este puțin mai nuanțat decât un test Locust cu un singur proces. În modul distribuit, avem un lucrător principal și mai mulți lucrători. Lucrătorul principal îi instruiește pe lucrători cu privire la modul de a genera și controla utilizatorii concurenți care trimit o solicitare. În a noastră distribuit.sh script, vedem în mod implicit că 240 de utilizatori vor fi distribuiți în cei 60 de lucrători. Rețineți că --headless flag în Locust CLI elimină caracteristica UI a 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

Mai întâi rulăm testul distribuit pe o singură instanță care susține punctul final. Ideea aici este că vrem să maximizăm pe deplin o singură instanță pentru a înțelege numărul de instanțe de care avem nevoie pentru a ne atinge TPS-ul țintă, respectând în același timp cerințele noastre de latență. Rețineți că, dacă doriți să accesați interfața de utilizare, modificați Locust_UI variabila de mediu la True și luați IP-ul public al instanței dvs. EC2 și mapați portul 8089 la adresa URL.

Următoarea captură de ecran arată valorile noastre CloudWatch.

Valori CloudWatch

În cele din urmă, observăm că, deși inițial obținem un TPS de 200, începem să observăm erori 5xx în jurnalele noastre de pe partea client EC2, așa cum se arată în următoarea captură de ecran.

Putem verifica acest lucru, de asemenea, analizând valorile noastre la nivel de instanță, în special CPUUtilization.

Valori CloudWatchAici observăm CPUUtilization la aproape 4,800%. Instanța noastră ml.m5.12x.large are 48 de procesoare virtuale (48 * 100 = 4800~). Acest lucru saturează întreaga instanță, ceea ce ajută și la explicarea erorilor noastre 5xx. Vedem și o creștere a ModelLatency.

Se pare că singura noastră instanță este răsturnată și nu are capacitatea de a susține o sarcină dincolo de 200 TPS pe care îl observăm. TPS-ul nostru țintă este 1000, așa că să încercăm să creștem numărul de instanțe la 5. Ar putea fi și mai mult într-un set de producție, deoarece observam erori la 200 TPS după un anumit punct.

Setările punctului final

Vedem atât în ​​jurnalele Locust UI, cât și în CloudWatch că avem un TPS de aproape 1000 cu cinci instanțe care sprijină punctul final.

roșcov

Valori CloudWatchDacă începeți să întâmpinați erori chiar și cu această configurare hardware, asigurați-vă că monitorizați CPUUtilization pentru a înțelege imaginea completă din spatele găzduirii endpoint-ului. Este esențial să înțelegeți utilizarea hardware-ului pentru a vedea dacă trebuie să creșteți sau chiar să reduceți. Uneori, problemele la nivel de container duc la erori 5xx, dar dacă CPUUtilization este scăzută, indică faptul că nu hardware-ul dvs., ci ceva la nivel de container sau model care ar putea duce la aceste probleme (variabila de mediu adecvată pentru numărul de lucrători nesetat, de exemplu). Pe de altă parte, dacă observați că instanța dvs. devine complet saturată, este un semn că trebuie fie să măriți flota de instanțe curente, fie să încercați o instanță mai mare cu o flotă mai mică.

Deși am crescut numărul de instanțe la 5 pentru a gestiona 100 TPS, putem vedea că ModelLatency metrica este încă mare. Acest lucru se datorează faptului că instanțele sunt saturate. În general, vă sugerăm să urmăriți utilizarea resurselor instanței între 60-70%.

A curăța

După testarea încărcării, asigurați-vă că curățați orice resurse pe care nu le veți utiliza prin consola SageMaker sau prin intermediul delete_endpoint Apel API Boto3. În plus, asigurați-vă că opriți instanța EC2 sau orice configurație client pe care o aveți pentru a nu suporta alte taxe și acolo.

Rezumat

În această postare, am descris cum puteți testa să vă încărcați punctul final SageMaker în timp real. Am discutat, de asemenea, ce valori ar trebui să evaluați atunci când testați punctul final pentru a înțelege defalcarea performanței. Asigurați-vă că verificați Recomandator SageMaker Inference pentru a înțelege în continuare dimensionarea corectă a instanțelor și mai multe tehnici de optimizare a performanței.


Despre Autori

Marc Karp este arhitect ML cu echipa SageMaker Service. El se concentrează pe a ajuta clienții să proiecteze, să implementeze și să gestioneze sarcinile de lucru ML la scară. În timpul liber, îi place să călătorească și să exploreze locuri noi.

Ram Vegiraju este arhitect ML cu echipa SageMaker Service. El se concentrează pe a ajuta clienții să-și construiască și să-și optimizeze soluțiile AI/ML pe Amazon SageMaker. În timpul liber, îi place să călătorească și să scrie.

Timestamp-ul:

Mai mult de la Învățare automată AWS