Bästa metoder för belastningstestning av Amazon SageMaker slutpunkter i realtid

Bästa metoder för belastningstestning av Amazon SageMaker slutpunkter i realtid

Källnod: 1889926

Amazon SageMaker är en fullständigt hanterad maskininlärningstjänst (ML). Med SageMaker kan datavetare och utvecklare snabbt och enkelt bygga och träna ML-modeller och sedan direkt distribuera dem i en produktionsklar värdmiljö. Den tillhandahåller en integrerad Jupyter-författaranteckningsbok-instans för enkel åtkomst till dina datakällor för utforskning och analys, så att du inte behöver hantera servrar. Det ger också gemensamma ML-algoritmer som är optimerade för att köras effektivt mot extremt stora data i en distribuerad miljö.

SageMaker realtidsinferens är idealisk för arbetsbelastningar som har interaktiva realtidskrav med låg latens. Med SageMaker realtidsinferens kan du distribuera REST-slutpunkter som backas upp av en specifik instanstyp med en viss mängd beräkning och minne. Att implementera en SageMaker-slutpunkt i realtid är bara det första steget på vägen till produktion för många kunder. Vi vill kunna maximera prestanda för slutpunkten för att uppnå ett mål för transaktioner per sekund (TPS) samtidigt som vi följer latenskraven. En stor del av prestandaoptimering för slutledning är att se till att du väljer rätt instanstyp och räknar för att backa en slutpunkt.

Det här inlägget beskriver de bästa metoderna för att ladda en SageMaker-slutpunkt för att hitta rätt konfiguration för antalet instanser och storlek. Detta kan hjälpa oss att förstå minimikraven för tillhandahållna instanser för att uppfylla våra latens- och TPS-krav. Därifrån dyker vi in ​​i hur du kan spåra och förstå mätvärden och prestanda för SageMaker-slutpunkten med hjälp av amazoncloudwatch metrik.

Vi jämför först prestandan för vår modell på en enda instans för att identifiera den TPS den kan hantera enligt våra acceptabla latenskrav. Sedan extrapolerar vi resultaten för att bestämma hur många instanser vi behöver för att hantera vår produktionstrafik. Slutligen simulerar vi trafik på produktionsnivå och ställer in belastningstester för en SageMaker-slutpunkt i realtid för att bekräfta att vår slutpunkt kan hantera belastningen på produktionsnivå. Hela koduppsättningen för exemplet finns tillgänglig i följande GitHub repository.

Översikt över lösningen

För det här inlägget distribuerar vi en förutbildad Kramar Face DistilBERT modell från Kramar Face Hub. Denna modell kan utföra ett antal uppgifter, men vi skickar en nyttolast specifikt för sentimentanalys och textklassificering. Med denna exempelnyttolast strävar vi efter att uppnå 1000 TPS.

Distribuera en slutpunkt i realtid

Det här inlägget förutsätter att du är bekant med hur man distribuerar en modell. Hänvisa till Skapa din slutpunkt och distribuera din modell för att förstå det interna bakom att vara värd för en slutpunkt. Tills vidare kan vi snabbt peka på den här modellen i Hugging Face Hub och distribuera en slutpunkt i realtid med följande kodavsnitt:

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

Låt oss testa vår slutpunkt snabbt med exempelnyttolasten som vi vill använda för belastningstestning:


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

Observera att vi backar slutpunkten med en singel Amazon Elastic Compute Cloud (Amazon EC2)-instans av typen ml.m5.12xlarge, som innehåller 48 vCPU och 192 GiB minne. Antalet vCPU:er är en bra indikation på vilken samtidighet instansen kan hantera. I allmänhet rekommenderas det att testa olika instanstyper för att säkerställa att vi har en instans som har resurser som används på rätt sätt. För att se en fullständig lista över SageMaker-instanser och deras motsvarande beräkningskraft för inferens i realtid, se Amazon SageMaker Prissättning.

Mätvärden att spåra

Innan vi kan gå in på belastningstestning är det viktigt att förstå vilka mätvärden som ska spåras för att förstå prestandauppdelningen för din SageMaker-slutpunkt. CloudWatch är det primära loggningsverktyget som SageMaker använder för att hjälpa dig förstå de olika mätvärdena som beskriver din slutpunkts prestanda. Du kan använda CloudWatch-loggar för att felsöka dina slutpunktsanrop; alla loggnings- och utskriftssatser du har i din slutledningskod fångas här. För mer information, se Så fungerar Amazon CloudWatch.

Det finns två olika typer av mätvärden CloudWatch täcker för SageMaker: instansnivå och anropsmått.

Mätvärden på instansnivå

Den första uppsättningen parametrar att överväga är mätvärdena på instansnivå: CPUUtilization och MemoryUtilization (för GPU-baserade instanser, GPUUtilization). För CPUUtilization, kan du se procentsatser över 100 % först i CloudWatch. Det är viktigt att inse för CPUUtilization, visas summan av alla CPU-kärnor. Till exempel, om instansen bakom din slutpunkt innehåller 4 vCPU:er betyder det att användningsområdet är upp till 400 %. MemoryUtilization, å andra sidan, ligger i intervallet 0–100 %.

Specifikt kan du använda CPUUtilization för att få en djupare förståelse för om du har tillräckligt med eller till och med överflöd av hårdvara. Om du har en underutnyttjad instans (mindre än 30 %) kan du eventuellt skala ner din instanstyp. Omvänt, om du använder cirka 80–90 %, skulle det vara fördelaktigt att välja en instans med större beräkning/minne. Från våra tester föreslår vi att din hårdvara används på cirka 60–70 %.

Anropsstatistik

Som antyds av namnet, är anropsstatistik där vi kan spåra fördröjningen från ända till ända för eventuella anrop till din slutpunkt. Du kan använda anropsstatistiken för att fånga antalet fel och vilken typ av fel (5xx, 4xx och så vidare) som din slutpunkt kan uppleva. Ännu viktigare är att du kan förstå fördröjningen av dina slutpunktssamtal. Mycket av detta går att fånga med ModelLatency och OverheadLatency mätvärden, som illustreras i följande diagram.

latenser

Smakämnen ModelLatency metrisk fångar den tid som slutsatsen tar inom modellbehållaren bakom en SageMaker-slutpunkt. Observera att modellbehållaren även innehåller alla anpassade slutledningskoder eller skript som du har skickat för slutledning. Den här enheten fångas på mikrosekunder som ett anropsmått, och i allmänhet kan du rita en percentil över CloudWatch (p99, p90, och så vidare) för att se om du når din målfördröjning. Observera att flera faktorer kan påverka modell- och behållarfördröjning, till exempel följande:

  • Anpassat slutledningsskript – Oavsett om du har implementerat din egen behållare eller använt en SageMaker-baserad behållare med anpassade slutledningshanterare, är det bästa praxis att profilera ditt skript för att fånga alla operationer som specifikt lägger mycket tid till din latens.
  • Kommunikationsprotokoll – Överväg REST vs. gRPC-anslutningar till modellservern i modellbehållaren.
  • Modellramverksoptimeringar – Det här är ramspecifikt, till exempel med TensorFlow, det finns ett antal miljövariabler du kan ställa in som är specifika för TF-serving. Se till att kontrollera vilken behållare du använder och om det finns några ramspecifika optimeringar som du kan lägga till i skriptet eller som miljövariabler att injicera i behållaren.

OverheadLatency mäts från det att SageMaker tar emot förfrågan tills den returnerar ett svar till klienten, minus modellens latens. Denna del ligger till stor del utanför din kontroll och faller under den tid det tar för SageMaker omkostnader.

End-to-end latens som helhet beror på en mängd olika faktorer och är inte nödvändigtvis summan av ModelLatency plus OverheadLatency. Till exempel, om din klient gör InvokeEndpoint API-anrop över internet, från klientens perspektiv, skulle fördröjningen från slut till ände vara internet + ModelLatency + OverheadLatency. Som sådan, när du belastningstester din endpoint för att korrekt benchmarka själva endpointen, rekommenderas det att fokusera på endpoint-statistiken (ModelLatency, OverheadLatencyoch InvocationsPerInstance) för att korrekt benchmarka SageMaker-slutpunkten. Eventuella problem relaterade till end-to-end latens kan sedan isoleras separat.

Några frågor att tänka på för fördröjning från slut till ände:

  • Var är klienten som anropar din slutpunkt?
  • Finns det några mellanliggande lager mellan din klient och SageMaker runtime?

Automatisk skalning

Vi täcker inte automatisk skalning specifikt i det här inlägget, men det är ett viktigt övervägande för att tillhandahålla rätt antal instanser baserat på arbetsbelastningen. Beroende på dina trafikmönster kan du bifoga en automatisk skalningspolicy till din SageMaker-slutpunkt. Det finns olika skalningsalternativ, som t.ex TargetTrackingScaling, SimpleScalingoch StepScaling. Detta gör att din slutpunkt kan skalas in och ut automatiskt baserat på ditt trafikmönster.

Ett vanligt alternativ är målspårning, där du kan ange ett CloudWatch-mått eller anpassat mått som du har definierat och skala ut baserat på det. Ett frekvent utnyttjande av automatisk skalning är att spåra InvocationsPerInstance metrisk. Efter att du har identifierat en flaskhals vid en viss TPS kan du ofta använda det som ett mått för att skala ut till ett större antal instanser för att kunna hantera toppbelastningar av trafik. För att få en djupare uppdelning av automatisk skalning av SageMaker-slutpunkter, se Konfigurera slutpunkter för automatisk skalning av slutpunkter i Amazon SageMaker.

Lasttestning

Även om vi använder Locust för att visa hur vi kan ladda test i skala, om du försöker att rätt storlek på instansen bakom din slutpunkt, SageMaker Inference Recommender är ett mer effektivt alternativ. Med belastningstestverktyg från tredje part måste du manuellt distribuera slutpunkter över olika instanser. Med Inference Recommender kan du helt enkelt klara en uppsättning av instanstyperna du vill ladda testet mot, så kommer SageMaker att snurra upp jobb för vart och ett av dessa fall.

Gräshoppa

För det här exemplet använder vi Gräshoppa, ett belastningstestverktyg med öppen källkod som du kan implementera med Python. Locust liknar många andra belastningstestverktyg med öppen källkod, men har några specifika fördelar:

  • Lätt att installera – Som vi visar i det här inlägget skickar vi ett enkelt Python-skript som enkelt kan omfaktoreras för din specifika slutpunkt och nyttolast.
  • Distribuerad och skalbar – Locust är evenemangsbaserat och använder gevent under huven. Detta är mycket användbart för att testa mycket samtidiga arbetsbelastningar och simulera tusentals samtidiga användare. Du kan uppnå hög TPS med en enda process som kör Locust, men den har också en distribuerad lastgenerering funktion som gör att du kan skala ut till flera processer och klientmaskiner, som vi kommer att utforska i det här inlägget.
  • Locust-mått och UI – Locust fångar också upp fördröjning från slut till ände som ett mått. Detta kan hjälpa dig att komplettera dina CloudWatch-mått för att måla en fullständig bild av dina tester. Allt detta fångas i Locust UI, där du kan spåra samtidiga användare, arbetare och mer.

För att förstå Locust ytterligare, kolla in deras dokumentation.

Amazon EC2-inställning

Du kan ställa in Locust i vilken miljö som helst som är kompatibel för dig. För det här inlägget ställer vi upp en EC2-instans och installerar Locust där för att utföra våra tester. Vi använder en c5.18xlarge EC2-instans. Beräkningskraften på klientsidan är också något att ta hänsyn till. Vid tillfällen när du får slut på beräkningskraft på klientsidan, fångas detta ofta inte upp, och det misstas som ett SageMaker-slutpunktsfel. Det är viktigt att placera din klient på en plats med tillräcklig beräkningskraft som kan hantera belastningen som du testar vid. För vår EC2-instans använder vi en Ubuntu Deep Learning AMI, men du kan använda vilken AMI som helst så länge du kan ställa in Locust på maskinen korrekt. För att förstå hur du startar och ansluter till din EC2-instans, se handledningen Kom igång med Amazon EC2 Linux-instanser.

Locust UI är tillgängligt via port 8089. Vi kan öppna detta genom att justera våra regler för inkommande säkerhetsgrupp för EC2-instansen. Vi öppnar också port 22 så att vi kan SSH in i EC2-instansen. Överväg att avgränsa källan till den specifika IP-adress som du kommer åt EC2-instansen från.

Säkerhetsgrupper

När du är ansluten till din EC2-instans ställer vi upp en virtuell Python-miljö och installerar Locust API med öppen källkod 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 är nu redo att arbeta med Locust för lasttestning av vår slutpunkt.

Locust testning

Alla Locust-belastningstester utförs baserat på en Locust fil som du tillhandahåller. Denna Locust-fil definierar en uppgift för belastningstestet; det är här vi definierar vår Boto3 invoke_endpoint API-anrop. Se följande kod:

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 föregående koden, justera dina anropsändpunktsanropsparametrar så att de passar din specifika modellanrop. Vi använder InvokeEndpoint API som använder följande kodbit i Locust-filen; detta är vår belastningstestkörningspunkt. Locust-filen vi använder är 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()

Nu när vi har vårt Locust-skript redo vill vi köra distribuerade Locust-tester för att stresstesta vår enstaka instans för att ta reda på hur mycket trafik vår instans kan hantera.

Locust distribuerat läge är lite mer nyanserat än ett Locust-test med en process. I distribuerat läge har vi en primär och flera arbetare. Den primära arbetaren instruerar arbetarna om hur de ska skapa och kontrollera de samtidiga användare som skickar en förfrågan. I vår distributed.sh skript ser vi som standard att 240 användare kommer att fördelas över de 60 arbetarna. Observera att --headless flaggan i Locust CLI tar bort UI-funktionen i 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 kör först det distribuerade testet på en enda instans som backar upp slutpunkten. Tanken här är att vi vill maximera en enda instans för att förstå antalet instanser som vi behöver för att uppnå vårt mål-TPS samtidigt som vi håller oss inom våra latenskrav. Observera att om du vill komma åt användargränssnittet, ändra Locust_UI miljövariabeln till True och ta den publika IP-adressen för din EC2-instans och mappa port 8089 till URL:en.

Följande skärmdump visar våra CloudWatch-statistik.

CloudWatch-mätvärden

Så småningom märker vi att även om vi initialt uppnår en TPS på 200, börjar vi märka 5xx-fel i våra EC2-loggar på klientsidan, som visas i följande skärmdump.

Vi kan också verifiera detta genom att titta närmare på våra mätvärden på instansnivå CPUUtilization.

CloudWatch-mätvärdenHär märker vi CPUUtilization på nästan 4,800 5.12 %. Vår ml.m48x.large-instans har 48 vCPU:er (100 * 4800 = 5~). Detta mättar hela instansen, vilket också hjälper till att förklara våra XNUMXxx-fel. Vi ser också en ökning av ModelLatency.

Det verkar som om vår enstaka instans blir störtad och inte har datorn för att klara en belastning förbi de 200 TPS som vi observerar. Vårt mål för TPS är 1000, så låt oss försöka öka vårt antal instanser till 5. Detta kan behöva vara ännu mer i en produktionsinställning, eftersom vi observerade fel vid 200 TPS efter en viss punkt.

Slutpunktsinställningar

Vi ser i både Locust UI- och CloudWatch-loggarna att vi har en TPS på nästan 1000 med fem instanser som backar slutpunkten.

Gräshoppa

CloudWatch-mätvärdenOm du börjar uppleva fel även med denna hårdvaruinställning, se till att övervaka CPUUtilization för att förstå hela bilden bakom din slutpunktshosting. Det är viktigt att förstå hur du använder hårdvaran för att se om du behöver skala upp eller till och med ned. Ibland leder problem på containernivå till 5xx-fel, men om CPUUtilization är låg, indikerar det att det inte är din hårdvara utan något på container- eller modellnivå som kan leda till dessa problem (till exempel korrekt miljövariabel för antal arbetare som inte har ställts in). Å andra sidan, om du märker att din instans håller på att bli helt mättad, är det ett tecken på att du antingen måste öka den nuvarande instansflottan eller prova en större instans med en mindre flotta.

Även om vi ökade antalet instanser till 5 för att hantera 100 TPS, kan vi se att ModelLatency måtten är fortfarande hög. Detta beror på att instanserna är mättade. Generellt föreslår vi att man strävar efter att utnyttja instansens resurser mellan 60–70 %.

Städa upp

Efter belastningstesten, se till att rensa upp alla resurser som du inte kommer att använda via SageMaker-konsolen eller via delete_endpoint Boto3 API-anrop. Se dessutom till att stoppa din EC2-instans eller vilken klientinstallation du har för att inte ådra dig några ytterligare avgifter där också.

Sammanfattning

I det här inlägget beskrev vi hur du kan ladda testa din SageMaker-slutpunkt i realtid. Vi diskuterade också vilka mätvärden du bör utvärdera när du belastningstester din slutpunkt för att förstå din prestandafördelning. Se till att checka ut SageMaker Inference Recommender för att ytterligare förstå instansernas rätt storlek och fler tekniker för prestandaoptimering.


Om författarna

Marc Karp är en ML-arkitekt med SageMaker Service-teamet. Han fokuserar på att hjälpa kunder att designa, distribuera och hantera ML-arbetsbelastningar i stor skala. På fritiden tycker han om att resa och utforska nya platser.

Ram Vegiraju är en ML-arkitekt med SageMaker Service-teamet. Han fokuserar på att hjälpa kunder att bygga och optimera sina AI/ML-lösningar på Amazon SageMaker. På fritiden älskar han att resa och skriva.

Tidsstämpel:

Mer från AWS maskininlärning