Maximera stabil diffusionsprestanda och lägre slutledningskostnader med AWS Inferentia2 | Amazon webbtjänster

Maximera stabil diffusionsprestanda och lägre slutledningskostnader med AWS Inferentia2 | Amazon webbtjänster

Generativa AI-modeller har upplevt snabb tillväxt de senaste månaderna på grund av dess imponerande förmåga att skapa realistisk text, bilder, kod och ljud. Bland dessa modeller utmärker sig Stable Diffusion-modeller för sin unika styrka när det gäller att skapa bilder av hög kvalitet baserade på textuppmaningar. Stabil diffusion kan generera en mängd olika högkvalitativa bilder, inklusive realistiska porträtt, landskap och till och med abstrakt konst. Och, liksom andra generativa AI-modeller, kräver stabila diffusionsmodeller kraftfull beräkning för att ge slutledning med låg latens.

I det här inlägget visar vi hur du kan köra stabila diffusionsmodeller och uppnå hög prestanda till lägsta kostnad inom Amazon Elastic Compute Cloud (Amazon EC2) med hjälp av Amazon EC2 Inf2-instanser drivs av AWS Inferentia2. Vi tittar på arkitekturen för en stabil diffusionsmodell och går igenom stegen för att kompilera en stabil diffusionsmodell med hjälp av AWS Neuron och distribuera den till en Inf2-instans. Vi diskuterar också de optimeringar som Neuron SDK automatiskt gör för att förbättra prestandan. Du kan köra både Stable Diffusion 2.1 och 1.5 versioner på AWS Inferentia2 kostnadseffektivt. Till sist visar vi hur du kan distribuera en stabil diffusionsmodell till en Inf2-instans med Amazon SageMaker.

Stable Diffusion 2.1-modellstorleken i flyttal 32 (FP32) är 5 GB och 2.5 GB i bfoat16 (BF16). En enda inf2.xlarge-instans har en AWS Inferentia2-accelerator med 32 GB HBM-minne. Stable Diffusion 2.1-modellen kan passa på en enda inf2.xlarge-instans. Stable Diffusion är en text-till-bild-modell som du kan använda för att skapa bilder av olika stilar och innehåll helt enkelt genom att tillhandahålla en textprompt som indata. För att lära dig mer om den stabila diffusionsmodellens arkitektur, se Skapa bilder av hög kvalitet med Stable Diffusion-modeller och distribuera dem kostnadseffektivt med Amazon SageMaker.

Hur Neuron SDK optimerar stabil diffusionsprestanda

Innan vi kan distribuera Stable Diffusion 2.1-modellen på AWS Inferentia2-instanser måste vi kompilera modellkomponenterna med hjälp av Neuron SDK. Neuron SDK, som inkluderar en kompilator för djupinlärning, körtid och verktyg, kompilerar och optimerar automatiskt modeller för djupinlärning så att de kan köras effektivt på Inf2-instanser och extrahera full prestanda från AWS Inferentia2-acceleratorn. Vi har exempel tillgängliga för Stable Diffusion 2.1-modellen på GitHub repo. Den här anteckningsboken presenterar ett heltäckande exempel på hur man kompilerar en stabil diffusionsmodell, sparar de kompilerade Neuron-modellerna och laddar den i körtiden för slutledning.

Vi använder StableDiffusionPipeline från The Hugging Face diffusers bibliotek för att ladda och kompilera modellen. Vi sammanställer sedan alla komponenter i modellen för Neuron med hjälp av torch_neuronx.trace() och spara den optimerade modellen som TorchScript. Kompileringsprocesser kan vara ganska minneskrävande och kräver en betydande mängd RAM. För att kringgå detta, innan vi spårar varje modell, skapar vi en deepcopy av den del av rörledningen som spåras. Efter detta tar vi bort pipeline-objektet från minnet med hjälp av del pipe. Denna teknik är särskilt användbar vid kompilering på instanser med lågt RAM-minne.

Dessutom utför vi även optimeringar av stabila diffusionsmodeller. UNet har den mest beräkningsintensiva aspekten av slutsatsen. UNet-komponenten arbetar på ingångstensorer som har en batchstorlek på två, och genererar en motsvarande utgående tensor också med en batchstorlek på två, för att producera en enda bild. Elementen inom dessa partier är helt oberoende av varandra. Vi kan dra fördel av detta beteende för att få optimal latens genom att köra en batch på varje Neuron-kärna. Vi kompilerar UNet för en batch (genom att använda ingångstensorer med en batch), använder sedan torch_neuronx.DataParallel API för att ladda denna enda batchmodell på varje kärna. Utdata från detta API är en sömlös två-batch-modul: vi kan skicka ingångarna från två batcher till UNet, och en två-batch-utgång returneras, men internt körs de två enkelbatchmodellerna på de två Neuron-kärnorna . Denna strategi optimerar resursutnyttjandet och minskar latensen.

Kompilera och distribuera en stabil diffusionsmodell på en Inf2 EC2-instans

För att kompilera och distribuera den stabila diffusionsmodellen på en Inf2 EC2-instans, logga till AWS Management Console och skapa en inf2.8xlarge-instans. Observera att en inf2.8xlarge-instans endast krävs för kompileringen av modellen eftersom kompilering kräver ett högre värdminne. Stable Diffusion-modellen kan vara värd för en inf2.xlarge-instans. Du kan hitta de senaste AMI med Neuron-bibliotek med hjälp av följande AWS-kommandoradsgränssnitt (AWS CLI) kommando:

aws ec2 describe-images --region us-east-1 --owners amazon --filters 'Name=name,Values=Deep Learning AMI Neuron PyTorch 1.13.? (Amazon Linux 2) ????????' 'Name=state,Values=available' --query 'reverse(sort_by(Images, &CreationDate))[:1].ImageId' --output text

För det här exemplet skapade vi en EC2-instans med Deep Learning AMI Neuron PyTorch 1.13 (Ubuntu 20.04). Du kan sedan skapa en JupyterLab labbmiljö genom att ansluta till instansen och köra följande steg:

run source /opt/aws_neuron_venv_pytorch/bin/activate
pip install jupyterlab
jupyter-lab

En anteckningsbok med alla steg för att kompilera och vara värd för modellen finns på GitHub.

Låt oss titta på kompileringsstegen för ett av textkodarblocken. Andra block som ingår i pipeline för stabil diffusion kan sammanställas på liknande sätt.

Första steget är att ladda den förtränade modellen från Hugging Face. De StableDiffusionPipeline.from_pretrained metoden laddar den förtränade modellen i vårt pipelineobjekt, pipe. Vi skapar sedan en deepcopy av textkodaren från vår pipeline, och klona den effektivt. De del pipe kommandot används sedan för att ta bort det ursprungliga pipeline-objektet, vilket frigör minnet som förbrukades av det. Här kvantiserar vi modellen till BF16-vikter:

model_id = "stabilityai/stable-diffusion-2-1-base"
pipe = StableDiffusionPipeline.from_pretrained(model_id, torch_dtype=torch.bfloat16)
text_encoder = copy.deepcopy(pipe.text_encoder)
del pipe

Det här steget innebär att vi lindar in vår textkodare med NeuronTextEncoder omslag. Utdata från en kompilerad textkodningsmodul kommer att vara av dict. Vi konverterar det till en list skriv med detta omslag:

text_encoder = NeuronTextEncoder(text_encoder)

Vi initierar PyTorch-tensor emb med vissa värderingar. De emb tensor används som exempel indata för torch_neuronx.trace fungera. Denna funktion spårar vår textkodare och kompilerar den till ett format optimerat för Neuron. Katalogsökvägen för den kompilerade modellen konstrueras genom sammanfogning COMPILER_WORKDIR_ROOT med underkatalogen text_encoder:

emb = torch.tensor([...])
text_encoder_neuron = torch_neuronx.trace(
        text_encoder.neuron_text_encoder,
        emb,
        compiler_workdir=os.path.join(COMPILER_WORKDIR_ROOT, 'text_encoder'),
        )

Den kompilerade textkodaren sparas med torch.jit.save. Den lagras under filnamnet model.pt i text_encoder katalog för vår kompilators arbetsyta:

text_encoder_filename = os.path.join(COMPILER_WORKDIR_ROOT, 'text_encoder/model.pt')
torch.jit.save(text_encoder_neuron, text_encoder_filename)

Smakämnen anteckningsbok innehåller liknande steg för att kompilera andra komponenter i modellen: UNet, VAE-avkodare och VAE post_quant_conv. När du har sammanställt alla modeller kan du ladda och köra modellen genom att följa dessa steg:

  1. Definiera sökvägarna för de kompilerade modellerna.
  2. Ladda en förtränad StableDiffusionPipeline modell, med dess konfiguration specificerad för att använda datatypen bfloat16.
  3. Ladda UNet-modellen på två Neuron-kärnor med hjälp av torch_neuronx.DataParallel API. Detta gör att dataparallell slutledning kan utföras, vilket avsevärt kan påskynda modellens prestanda.
  4. Ladda de återstående delarna av modellen (text_encoder, decoderoch post_quant_conv) på en enda neuronkärna.

Du kan sedan köra pipelinen genom att tillhandahålla inmatningstext som uppmaningar. Följande är några bilder som genereras av modellen för uppmaningarna:

  • Porträtt av renaud sechan, penna och bläck, intrikata linjeteckningar, av craig mullins, ruan jia, kentaro miura, greg rutkowski, loundraw

Maximera stabil diffusionsprestanda och lägre slutledningskostnader med AWS Inferentia2 | Amazon Web Services PlatoBlockchain Data Intelligence. Vertikal sökning. Ai.

  • Porträtt av gammal kolgruvarbetare på 19-talet, vacker målning, med mycket detaljerad ansiktsmålning av greg rutkowski

Maximera stabil diffusionsprestanda och lägre slutledningskostnader med AWS Inferentia2 | Amazon Web Services PlatoBlockchain Data Intelligence. Vertikal sökning. Ai.

  • Ett slott mitt i en skog

Maximera stabil diffusionsprestanda och lägre slutledningskostnader med AWS Inferentia2 | Amazon Web Services PlatoBlockchain Data Intelligence. Vertikal sökning. Ai.

Host Stable Diffusion 2.1 på AWS Inferentia2 och SageMaker

Att vara värd för stabila diffusionsmodeller med SageMaker kräver också kompilering med Neuron SDK. Du kan slutföra kompileringen i förväg eller under körning med Large Model Inference (LMI)-behållare. Kompilering i förväg möjliggör snabbare modellladdningstider och är det föredragna alternativet.

SageMaker LMI-behållare ger två sätt att distribuera modellen:

  • Ett kodfritt alternativ där vi bara tillhandahåller en serving.properties fil med nödvändiga konfigurationer
  • Ta med ditt eget slutledningsskript

Vi tittar på båda lösningarna och går igenom konfigurationerna och slutledningsskriptet (model.py). I det här inlägget demonstrerar vi distributionen med hjälp av en förkompilerad modell lagrad i en Amazon enkel lagringstjänst (Amazon S3) hink. Du kan använda den här förkompilerade modellen för dina distributioner.

Konfigurera modellen med ett medföljande skript

I det här avsnittet visar vi hur du konfigurerar LMI-behållaren för att vara värd för stabila diffusionsmodeller. SD2.1-anteckningsboken tillgänglig på GitHub. Det första steget är att skapa modellkonfigurationspaketet enligt följande katalogstruktur. Vårt mål är att använda de minimala modellkonfigurationer som behövs för att vara värd för modellen. Katalogstrukturen som behövs är följande:

<config-root-directory> / 
    ├── serving.properties
    │   
    └── model.py [OPTIONAL]

Därefter skapar vi serveringsegenskaper fil med följande parametrar:

%%writefile code_sd/serving.properties
engine=Python
option.entryPoint=djl_python.transformers-neuronx
option.use_stable_diffusion=True
option.model_id=s3url
option.tensor_parallel_degree=2
option.dtype=bf16

Parametrarna anger följande:

  • option.model_id – LMI-behållarna använder s5cmd för att ladda modellen från S3-platsen och därför måste vi ange var våra sammanställda vikter är.
  • option.entryPoint – För att använda de inbyggda hanterarna anger vi klassen transformers-neuronx. Om du har ett anpassat slutledningsskript måste du tillhandahålla det istället.
  • option.dtype – Detta anger att vikterna ska laddas i en viss storlek. För det här inlägget använder vi BF16, vilket ytterligare minskar våra minneskrav jämfört med FP32 och sänker vår latens på grund av det.
  • option.tensor_parallel_degree – Den här parametern anger antalet acceleratorer vi använder för den här modellen. AWS Inferentia2-chipacceleratorn har två Neuron-kärnor och att specificera ett värde på 2 betyder att vi använder en accelerator (två kärnor). Detta innebär att vi nu kan skapa flera arbetare för att öka genomströmningen av slutpunkten.
  • option.motor – Detta är inställt på Python för att indikera att vi inte kommer att använda andra kompilatorer som DeepSpeed ​​eller Faster Transformer för denna värd.

Ta med eget manus

Om du vill ta med ditt eget anpassade slutledningsskript måste du ta bort option.entryPoint från serving.properties. LMI-behållaren kommer i så fall att leta efter en model.py fil på samma plats som serving.properties och använd det för att köra slutledning.

Skapa ditt eget slutledningsskript (model.py)

Att skapa ditt eget slutledningsskript är relativt enkelt med LMI-behållaren. Behållaren kräver din model.py fil för att ha en implementering av följande metod:

def handle(inputs: Input) which returns an object of type Outputs

Låt oss undersöka några av de kritiska områdena bifogad anteckningsbok, som demonstrerar funktionen ta med ditt eget skript.

Ersätt cross_attention modul med den optimerade versionen:

# Replace original cross-attention module with custom cross-attention module for better performance
    CrossAttention.get_attention_scores = get_attention_scores
Load the compiled weights for the following
text_encoder_filename = os.path.join(COMPILER_WORKDIR_ROOT, 'text_encoder.pt')
decoder_filename = os.path.join(COMPILER_WORKDIR_ROOT, 'vae_decoder.pt')
unet_filename = os.path.join(COMPILER_WORKDIR_ROOT, 'unet.pt')
post_quant_conv_filename =. os.path.join(COMPILER_WORKDIR_ROOT, 'vae_post_quant_conv.pt')

Det här är namnen på den kompilerade viktfilen som vi använde när vi skapade kompileringarna. Ändra gärna filnamnen, men se till att dina vikter filnamn matchar det du anger här.

Sedan måste vi ladda dem med Neuron SDK och ställa in dessa i de faktiska modellvikterna. När du laddar de UNet-optimerade vikterna, observera att vi också anger antalet neuronkärnor vi behöver ladda dessa på. Här laddar vi till en enda accelerator med två kärnor:

# Load the compiled UNet onto two neuron cores.
    pipe.unet = NeuronUNet(UNetWrap(pipe.unet))
    logging.info(f"Loading model: unet:created")
    device_ids = [idx for idx in range(tensor_parallel_degree)]
   
    pipe.unet.unetwrap = torch_neuronx.DataParallel(torch.jit.load(unet_filename), device_ids, set_dynamic_batching=False)
   
 
    # Load other compiled models onto a single neuron core.
 
    # - load encoders
    pipe.text_encoder = NeuronTextEncoder(pipe.text_encoder)
    clip_compiled = torch.jit.load(text_encoder_filename)
    pipe.text_encoder.neuron_text_encoder = clip_compiled
    #- load decoders
    pipe.vae.decoder = torch.jit.load(decoder_filename)
    pipe.vae.post_quant_conv = torch.jit.load(post_quant_conv_filename)

Att köra inferensen med en prompt anropar rörobjektet för att generera en bild.

Skapa SageMaker-slutpunkten

Vi använder Boto3 API:er för att skapa en SageMaker-slutpunkt. Slutför följande steg:

  1. Skapa tarballen med bara serveringen och det valfria model.py filer och ladda upp den till Amazon S3.
  2. Skapa modellen med hjälp av bildbehållaren och modellen tarball som laddades upp tidigare.
  3. Skapa slutpunktskonfigurationen med hjälp av följande nyckelparametrar:
    1. Använd en ml.inf2.xlarge exempel.
    2. uppsättning ContainerStartupHealthCheckTimeoutInSeconds till 240 för att säkerställa att hälsokontrollen startar efter att modellen har distribuerats.
    3. uppsättning VolumeInGB till ett högre värde så att den kan användas för att ladda modellvikter som är 32 GB stora.

Skapa en SageMaker-modell

När du har skapat filen model.tar.gz och laddat upp den till Amazon S3 måste vi skapa en SageMaker-modell. Vi använder LMI-behållaren och modellartefakten från föregående steg för att skapa SageMaker-modellen. SageMaker låter oss anpassa och injicera olika miljövariabler. För detta arbetsflöde kan vi lämna allt som standard. Se följande kod:

inference_image_uri = (
    f"763104351884.dkr.ecr.{region}.amazonaws.com/djl-inference:0 djl-serving-inf2"
)

Skapa modellobjektet, som i huvudsak skapar en lockdown-behållare som laddas på instansen och används för slutledning:

model_name = name_from_base(f"inf2-sd")
create_model_response = boto3_sm_client.create_model(
    ModelName=model_name,
    ExecutionRoleArn=role,
    PrimaryContainer={"Image": inference_image_uri, "ModelDataUrl": s3_code_artifact},
)

Skapa en SageMaker-slutpunkt

I den här demon använder vi en ml.inf2.xlarge-instans. Vi måste ställa in VolumeSizeInGB parametrar för att ge det nödvändiga diskutrymmet för att ladda modellen och vikterna. Den här parametern är tillämplig på instanser som stöder Amazon Elastic Block Store (Amazon EBS) volymfäste. Vi kan lämna tidsgränsen för modellnedladdningen och hälsokontrollen av containerstart till ett högre värde, vilket ger tillräckligt med tid för containern att dra vikterna från Amazon S3 och ladda in i AWS Inferentia2-acceleratorerna. För mer information, se CreateEndpointConfig.

endpoint_config_response = boto3_sm_client.create_endpoint_config( EndpointConfigName=endpoint_config_name,
    ProductionVariants=[
        {
            "VariantName": "variant1",
            "ModelName": model_name,
            "InstanceType": "ml.inf2.xlarge", # - 
            "InitialInstanceCount": 1,
            "ContainerStartupHealthCheckTimeoutInSeconds": 360, 
            "VolumeSizeInGB": 400
        },
    ],
)

Slutligen skapar vi en SageMaker-slutpunkt:

create_endpoint_response = boto3_sm_client.create_endpoint(
    EndpointName=f"{endpoint_name}", EndpointConfigName=endpoint_config_name
)

Anropa modellens slutpunkt

Detta är en generativ modell, så vi skickar in prompten som modellen använder för att generera bilden. Nyttolasten är av typen JSON:

response_model = boto3_sm_run_client.invoke_endpoint( EndpointName=endpoint_name,
    Body=json.dumps(
        {
            "prompt": "Mountain Landscape", 
            "parameters": {} # 
        }
    ), 
    ContentType="application/json",
)

Benchmarking av stabil diffusionsmodell på Inf2

Vi körde några tester för att benchmarka den stabila diffusionsmodellen med BF 16-datatypen på Inf2, och vi kan härleda latenstal som konkurrerar med eller överträffar några av de andra acceleratorerna för stabil diffusion. Detta, tillsammans med den lägre kostnaden för AWS Inferentia2-chips, gör detta till ett extremt värdefullt förslag.

Följande siffror är från den stabila diffusionsmodellen som används på en inf2.xl-instans. För mer information om kostnader, se Amazon EC2 Inf2-instanser.

Modell Upplösning Data typ Iterationer P95 latens (ms) Inf2.xl On-Demand kostnad per timme Inf2.xl (kostnad per bild)
Stabil diffusion 1.5 512 × 512 bf16 50 2,427.4 $0.76 $0.0005125
Stabil diffusion 1.5 768 × 768 bf16 50 8,235.9 $0.76 $0.0017387
Stabil diffusion 1.5 512 × 512 bf16 30 1,456.5 $0.76 $0.0003075
Stabil diffusion 1.5 768 × 768 bf16 30 4,941.6 $0.76 $0.0010432
Stabil diffusion 2.1 512 × 512 bf16 50 1,976.9 $0.76 $0.0004174
Stabil diffusion 2.1 768 × 768 bf16 50 6,836.3 $0.76 $0.0014432
Stabil diffusion 2.1 512 × 512 bf16 30 1,186.2 $0.76 $0.0002504
Stabil diffusion 2.1 768 × 768 bf16 30 4,101.8 $0.76 $0.0008659

Slutsats

I det här inlägget dyker vi djupt in i kompileringen, optimeringen och distributionen av Stable Diffusion 2.1-modellen med hjälp av Inf2-instanser. Vi demonstrerade också distribution av stabila diffusionsmodeller med SageMaker. Inf2-instanser levererar också bra prisprestanda för Stable Diffusion 1.5. För att lära dig mer om varför Inf2-instanser är bra för generativ AI och stora språkmodeller, se Amazon EC2 Inf2-instanser för låg kostnad, högpresterande generativ AI-inferens är nu allmänt tillgängliga. För prestandadetaljer, se Inf2 prestanda. Kolla in ytterligare exempel på GitHub repo.

Speciellt tack till Matthew Mcclain, Beni Hegedus, Kamran Khan, Shruti Koparkar och Qing Lan för att ha granskat och tillhandahållit värdefulla input.


Om författarna

Maximera stabil diffusionsprestanda och lägre slutledningskostnader med AWS Inferentia2 | Amazon Web Services PlatoBlockchain Data Intelligence. Vertikal sökning. Ai.Vivek Gangasani är Senior Machine Learning Solutions Architect på Amazon Web Services. Han arbetar med startups för maskininlärning för att bygga och distribuera AI/ML-applikationer på AWS. Han är för närvarande fokuserad på att leverera lösningar för MLOps, ML-inferens och lågkods-ML. Han har arbetat med projekt inom olika domäner, inklusive naturlig språkbehandling och datorseende.

Maximera stabil diffusionsprestanda och lägre slutledningskostnader med AWS Inferentia2 | Amazon Web Services PlatoBlockchain Data Intelligence. Vertikal sökning. Ai.KC Tung är senior lösningsarkitekt i AWS Annapurna Labs. Han är specialiserad på utbildning och implementering av stora modeller för djupinlärning i moln. Han har en Ph.D. i molekylär biofysik från University of Texas Southwestern Medical Center i Dallas. Han har talat på AWS Summits och AWS Reinvent. Idag hjälper han kunder att träna och distribuera stora PyTorch- och TensorFlow-modeller i AWS-moln. Han är författare till två böcker: Lär dig TensorFlow Enterprise och TensorFlow 2 Pocket Referens.

Maximera stabil diffusionsprestanda och lägre slutledningskostnader med AWS Inferentia2 | Amazon Web Services PlatoBlockchain Data Intelligence. Vertikal sökning. Ai.Rupinder Grewal är en Sr Ai/ML Specialist Solutions Architect med AWS. Han fokuserar för närvarande på servering av modeller och MLOps på SageMaker. Innan denna roll har han arbetat som Machine Learning Engineer med att bygga och hosta modeller. Utanför jobbet tycker han om att spela tennis och cykla på bergsstigar.

Tidsstämpel:

Mer från AWS maskininlärning