Kæmper du med AI eller full-stack-udvikling? Vores eksperter er her for at vejlede dig: skræddersyet rådgivning, teknisk integration og meget mere. Kontakt os på [email protected].

Teknikker til optimering af LLM-inferens

Inferensoptimering er en kritisk del af generative AI-applikationer, der implementeres i produktionen. Det er en udfordring at bruge LLM'er effektivt i stor skala, og mange teknikker er blevet udviklet i de seneste år for at gøre inferens hurtigere og billigere. Lad os gennemgå disse teknikker i denne artikel.

Teknikker til optimering af LLM-inferens

Fokus på LLM's arkitektur

Store sprogmodeller (LLM'er) er alle baseret på transformerarkitekturen, der blev opfundet i 2017 af Vaswani et al. Transformerarkitekturen opnår overlegen nøjagtighed, indlæring med få skud og næsten menneskelige evner på tværs af forskellige sprogopgaver. Men disse grundmodeller, som ofte består af titusindvis til hundredvis af milliarder af parametre, er dyre at træne og ressourcekrævende under inferens. Inferensomkostningerne eskalerer med lange inputkontekster, som kræver betydelig processorkraft på grund af store inputdata. Det gør effektiv inferens til en kritisk udfordring, især når det gælder håndtering af hukommelse og computerressourcer.

Transformerens arkitektur
Transformerens arkitektur

Mere specifikt er de fleste kendte LLM'er kun dekoder-LLM'er, som GPT-3, GPT-4, LLaMA, Mistral, DeepSeek osv. Disse modeller er forudtrænet på en kausal modelleringsopgave og fungerer som forudsigere af næste ord. De behandler en sekvens af tokens som input og producerer følgende tokens autoregressivt, indtil en stopbetingelse er nået.

LLM-inferens i rene dekodermodeller involverer to nøglefaser: Prefill-fasen og afkodningsfasen. I prefill-fasen behandler modellen input-tokens for at beregne mellemliggende tilstande (nøgler og værdier) til generering af det første nye token. Denne fase, der ligner en matrix-matrix-operation, er meget paralleliseret og udnytter effektivt GPU-kapaciteter. Omvendt genererer afkodningsfasen tokens, en ad gangen, på baggrund af tidligere tokens' tilstande. Denne matrix-vektor-operation er hukommelsesbundet, da dataoverførsel til GPU'en, snarere end beregningshastighed, primært dikterer latenstid, hvilket fører til underudnyttet GPU-beregningskraft.

Optimering af afkodningsfasen er et omdrejningspunkt for at løse inferensudfordringer. Løsningerne omfatter udvikling af effektive opmærksomhedsmekanismer og bedre styring af nøgler og værdier for at reducere flaskehalse i hukommelsen. Indlægget fremhæver praktiske tilgange til at forbedre inferensydelsen, forudsat at læserne har en grundlæggende forståelse af transformerarkitekturen og opmærksomhedsmekanismerne. Disse optimeringer er afgørende for at forbedre gennemstrømningen og reducere ventetiden i LLM-implementeringer i den virkelige verden.

En yderligere komplikation opstår ved brugen af forskellige tokenizers på tværs af LLM'er, hvilket påvirker sammenligneligheden af tokener. Tokens, der stort set svarer til fire engelske tegn, varierer i repræsentation afhængigt af tokenizer, hvilket gør direkte sammenligninger af inferensgennemstrømning (f.eks. tokens pr. sekund) misvisende. Denne variation understreger behovet for standardiserede evalueringsmålinger for nøjagtigt at kunne vurdere og sammenligne LLM's ydeevne under inferens.

Batching

Batching er en vigtig strategi til at forbedre GPU-udnyttelsen og -gennemstrømningen i store sprogmodeller (LLM'er). Ved at behandle flere anmodninger samtidigt ved hjælp af den samme model fordeler batching hukommelsesomkostningerne for modelvægte på tværs af anmodninger, så større batches kan udnytte mere GPU-beregningskraft. Der er dog en grænse for batchstørrelsen, da alt for store batches kan forårsage hukommelsesoverløb på grund af LLM'ernes hukommelseskrav, især i forbindelse med key-value (KV)-caching (mere om dette senere).

Batching-teknikker
Batching-teknikker

Traditionel eller statisk batching har begrænsninger, fordi anmodninger i en batch ofte genererer forskellige antal completion tokens, hvilket fører til varierende udførelsestider. Det får alle anmodninger til at vente på, at den langsomste bliver færdig, hvilket kan være problematisk, når genereringslængderne varierer betydeligt. For at løse dette problem er der udviklet avancerede teknikker som in-flight batching for at optimere ydeevnen.

In-flight batching, også kendt som kontinuerlig batching, tackler de udfordringer, som den dynamiske karakter af LLM-arbejdsbelastninger giver, og som kan variere fra simple chatbot-svar til kompleks dokumentopsummering eller kodegenerering. Disse opgaver producerer output i vidt forskellige størrelser, hvilket gør det svært at batch'e og udføre anmodninger effektivt parallelt. I modsætning til statisk batching giver in-flight batching serveren mulighed for at fjerne afsluttede sekvenser fra batchen med det samme og begynde at behandle nye anmodninger, mens andre stadig er i gang. Denne tilgang øger GPU-udnyttelsen betydeligt ved at tilpasse sig de varierende udførelsestider for anmodninger i virkelige scenarier.

Implementering af flere GPU'er med parallelisering af modeller

Parallelisering af modeller er en vigtig strategi til at styre hukommelses- og beregningskravene til store maskinlæringsmodeller ved at fordele dem på flere GPU'er. Denne tilgang gør det muligt at håndtere større modeller eller inputbatches, der overskrider hukommelseskapaciteten på en enkelt enhed, hvilket gør det vigtigt for både træning og inferens, når hukommelsesbegrænsningerne er stramme. Der findes forskellige teknikker til opdeling af modelvægte, herunder pipeline-parallelisme, tensorparallelisme og sekvensparallelisme, som hver især adresserer forskellige aspekter af modeldistribution. I modsætning til dataparallelisme, som fokuserer på at replikere modelvægte på tværs af enheder for at behandle større inputbatches under træning, er disse metoder mere relevante for at reducere hukommelsesfodaftryk under både træning og slutning.

Flere NVIDIA GPU'er
Flere NVIDIA GPU'er

Pipeline-parallelisme opdeler modellen vertikalt i sekventielle bidder, hvor hver bid indeholder en delmængde af lag, der er tildelt en separat enhed. I en firevejs pipeline-opsætning håndterer hver enhed f.eks. en fjerdedel af modellens lag og sender output til den næste enhed i rækkefølge. Selv om dette reducerer hukommelseskravene pr. enhed betydeligt, introducerer det ineffektivitet kendt som "pipeline-bobler", hvor enheder kan gå i tomgang, mens de venter på output fra tidligere lag. Microbatching, som opdeler input-batches i mindre sub-batches til sekventiel behandling, kan reducere disse bobler, men ikke fjerne dem helt, da der stadig er tomgangstider under fremadrettede og bagudrettede passager.

Tensorparallelisme opdeler derimod individuelle lag horisontalt i mindre beregningsblokke, der kan udføres uafhængigt på tværs af enheder. Det er især effektivt for transformerkomponenter som opmærksomhedsblokke og flerlagsperceptroner (MLP'er), hvor f.eks. forskellige opmærksomhedshoveder kan tildeles separate enheder til parallelberegning. Tensorparallelisme er dog mindre effektiv til operationer som LayerNorm og Dropout, som ikke let kan opdeles og skal replikeres på tværs af enheder, hvilket fører til overflødig brug af hukommelse til lagring af aktiveringer. Denne begrænsning understreger behovet for supplerende tilgange til at optimere hukommelseseffektiviteten.

Sekvensparallelisme håndterer den ineffektive hukommelse i operationer som LayerNorm og Dropout ved at opdele dem langs inputsekvensdimensionen og udnytte deres uafhængighed på tværs af sekvenselementer. Denne metode reducerer hukommelsesaftrykket fra overflødige aktiveringer, hvilket gør den til et værdifuldt supplement til tensorparallelisme. Disse paralleliseringsteknikker udelukker ikke hinanden og kan kombineres for at optimere store sprogmodeller (LLM'er) yderligere. Derudover kan specifikke optimeringsstrategier for opmærksomhedsmodulet forbedre skalerbarheden og reducere hukommelseskravene pr. GPU, hvilket muliggør mere effektiv træning og inferens for store modeller.

Opmærksomhedsoptimering

Artiklen *Attention Is All You Need* fra 2017 af Vaswani et al. introducerede Transformer-modellen med selvopmærksomhed som hjørnesten. Selvopmærksomhed gør det muligt for modellen at vurdere relevansen af forskellige ord i en sætning i forhold til hinanden, hvilket forbedrer den kontekstuelle forståelse til opgaver som naturlig sprogbehandling. Artiklen formaliserede selvopmærksomhed, især gennem SDPA-mekanismen (scaled dot-product attention), som kortlægger forespørgsels- og nøgleværdipar til et output, hvilket gør det til en central komponent i moderne neurale netværk. Her er nogle af de vigtigste teknikker til at optimere opmærksomhedsberegninger:

Opmærksomhedspapiret
Opmærksomhedspapiret

Multi-head attention (MHA) bygger på SDPA ved at køre flere opmærksomhedsoperationer parallelt, hver med forskellige projektioner af forespørgsels-, nøgle- og værdimatricer. Disse parallelle operationer, eller "hoveder", fokuserer på forskellige repræsentative underrum, hvilket beriger modellens forståelse af input. Output fra disse hoveder sammenkædes og projiceres lineært, hvilket opretholder en beregningseffektivitet, der kan sammenlignes med opmærksomhed i et enkelt hoved, ved at reducere dimensionaliteten af hvert hoved (f.eks. ved at dividere modeldimensionen med antallet af hoveder, f.eks. 8).

Multi-query attention (MQA) optimerer MHA til inferens ved at dele nøgle- og værdiprojektioner på tværs af flere opmærksomhedshoveder, mens flere forespørgselsprojektioner bevares. Dette reducerer kravene til hukommelsesbåndbredde og størrelsen på key-value (KV)-cachen, hvilket muliggør større batchstørrelser og bedre udnyttelse af computeren. MQA kan dog reducere nøjagtigheden en smule, og modeller, der udnytter det, kræver træning eller finjustering med MQA aktiveret for at opretholde ydeevnen.

Grouped-query attention (GQA) afbalancerer MHA og MQA ved at gruppere forespørgselshoveder og dele nøgleværdiprojektioner inden for hver gruppe, hvilket giver næsten MHA-kvalitet med en beregningseffektivitet, der er tættere på MQA. Modeller som Llama 2 70B bruger GQA, og dem, der er trænet med MHA, kan tilpasses til GQA med minimal ekstra træning. Både MQA og GQA reducerer kravene til KV-cache-hukommelse, selvom yderligere optimeringer i cache-styring stadig er nødvendige.

FlashAttention forbedrer opmærksomhedsmekanismer ved at omorganisere beregninger for at udnytte GPU-hukommelseshierarkier mere effektivt. I modsætning til traditionel lag-for-lag-behandling smelter FlashAttention operationer sammen og bruger "tiling" til at beregne små dele af outputmatrixen på én gang, hvilket minimerer læse-/skriveoperationer i hukommelsen. Denne I/O-bevidste, nøjagtige opmærksomhedsalgoritme integreres problemfrit i eksisterende modeller uden ændringer og giver betydelige hastighedsforøgelser ved at optimere databevægelsen.

Caching af nøgleværdier

KV-caching er en kritisk optimeringsteknik, der bruges i afkodningsfasen af store sprogmodeller (LLM'er) for at forbedre effektiviteten af selvopmærksomhedsberegninger. I denne fase afhænger hvert genereret token af nøgle- (K) og værdi- (V) tensorer for alle tidligere tokens, inklusive dem, der er beregnet under prefill-fasen og de efterfølgende afkodningstrin. I stedet for at genberegne disse tensorer for hvert token ved hvert tidstrin, gemmer KV-cachen dem i GPU-hukommelsen og tilføjer nye tensorer til cachen, når de beregnes. Typisk opretholdes en separat KV-cache for hvert lag i modellen, hvilket reducerer overflødige beregninger betydeligt og fremskynder afkodningsprocessen.

Caching af nøgleværdier
Caching af nøgleværdier

Hukommelseskravene til LLM'er på GPU'er er primært drevet af to komponenter: modelvægte og KV-cachen. Modelvægte, som består af modellens parametre, optager betydelig hukommelse; for eksempel kræver en model med 7 milliarder parametre som Llama 2 7B i 16-bit præcision ca. 14 GB. KV-cachen gemmer derimod selvopmærksomhedstensorer for at undgå genberegning, og dens størrelse bestemmes af faktorer som antallet af lag, opmærksomhedshoveder, hoveddimensioner og præcision. For hvert token beregnes cachestørrelsen som 2 * num_layers * (num_heads * dim_head) * precision_in_bytes, hvor faktoren 2 tager højde for både K- og V-matricer. For en batch af input skalerer den samlede KV-cachestørrelse med batchstørrelse og sekvenslængde og kan potentielt nå betydelige størrelser, f.eks. ~2 GB for en Llama 2 7B-model med en sekvenslængde på 4.096 og batchstørrelse på 1.

Det er en udfordring at administrere KV-cachen effektivt, fordi den vokser lineært med batchstørrelsen og sekvenslængden, hvilket kan begrænse gennemstrømningen og komplicere håndteringen af input med lange kontekster. En almindelig ineffektivitet skyldes statisk overkapacitet, hvor hukommelsen er reserveret til den maksimalt understøttede sekvenslængde (f.eks. 2.048 tokens), uanset den faktiske inputstørrelse. Dette fører til betydeligt hukommelsesspild eller fragmentering, da en stor del af den reserverede plads ofte forbliver ubrugt i hele anmodningens levetid og binder værdifulde GPU-hukommelsesressourcer.

For at afhjælpe denne ineffektivitet introducerer PagedAttention-algoritmen en ny tilgang, der er inspireret af operativsystemets personsøgning. Den opdeler KV-cachen i blokke af fast størrelse, som hver repræsenterer et bestemt antal tokens, der kan lagres i hukommelsen uden at være sammenhængende. En bloktabel sporer disse blokke og henter dem efter behov under opmærksomhedsberegninger. Når der genereres nye tokens, allokeres yderligere blokke dynamisk. Denne metode minimerer hukommelsesspild ved at eliminere behovet for sammenhængende allokering og overprovisionering, hvilket muliggør større batchstørrelser og forbedrer gennemstrømningen, hvilket gør det til et betydeligt fremskridt i håndteringen af KV-cachehukommelse til LLM'er.

Optimering af modeller

I dette afsnit diskuterer vi forskellige teknikker til optimering af store sprogmodeller (LLM'er) for at reducere deres hukommelsesforbrug og forbedre ydeevnen på GPU'er. De vigtigste metoder omfatter kvantisering, sparsomhed og destillation, som hver især er rettet mod forskellige aspekter af modeleffektivitet. Disse teknikker ændrer modelvægte, udnytter GPU-hardwareacceleration og overfører viden til mindre modeller, så større modeller kan køre på begrænset hardware, samtidig med at ydeevnen opretholdes. Disse metoder kan forringe modellens nøjagtighed, så de skal bruges med forsigtighed.

Kvantisering reducerer præcisionen af en models vægte og aktiveringer, typisk fra 32 eller 16 bits til 8 eller færre bits, så modeller kan optage mindre hukommelse og overføre data mere effektivt. Mens kvantificering af vægte er ligetil på grund af deres faste karakter efter træning, er kvantificering af aktiveringer mere kompleks på grund af outliers, der udvider deres dynamiske område. Teknikker som LLM.int8() løser dette ved selektivt at anvende højere præcision på visse aktiveringer eller ved at genbruge det dynamiske område af kvantiserede vægte til aktiveringer, selvom GPU'er kan kræve konvertering af vægte tilbage til højere præcision for operationer.

Sparsomhed involverer beskæring af modelværdier tæt på nul, hvilket skaber sparsomme matricer, der kræver mindre hukommelse. GPU'er understøtter struktureret sparsomhed, som f.eks. at repræsentere to ud af fire værdier som nuller, hvilket fremskynder beregningerne. Ved at kombinere sparsomhed med kvantisering kan man øge udførelseshastigheden yderligere. Forskningen fortsætter med at udforske optimale sparsomme repræsentationer for LLM'er, hvilket indikerer en lovende vej til at forbedre inferenshastighederne.

Destillation overfører viden fra en større "lærer"-model til en mindre "elev"-model og komprimerer størrelsen, mens ydeevnen bevares. DistilBERT opnår f.eks. en størrelsesreduktion på 40 % og en hastighedsforøgelse på 60 % sammenlignet med BERT og bevarer 97 % af sin kapacitet. Destillation kan involvere efterligning af lærerens output eller brug af lærergenererede data til træning, med metoder som "Distilling Step by Step!", der indeholder rationaler for effektiv læring. Restriktive licenser på mange avancerede LLM'er begrænser dog tilgængeligheden af egnede lærermodeller til destillation.

Spekulativ slutning

Spekulativ inferens, også kendt som spekulativ sampling eller assisteret generering, er en metode til at parallelisere udførelsen af autoregressive store sprogmodeller (LLM'er) som modeller i GPT-stil, der typisk genererer tekst token for token. Ved standardafvikling afhænger hvert token af alle tidligere tokens for kontekst, hvilket gør parallel generering umulig, da det n'te token skal genereres før det (n+1)te. Spekulativ inferens løser dette ved at bruge en "billigere" udkastmodel til at forudsige flere fremtidige tokens samtidigt, som derefter verificeres eller afvises parallelt af hovedmodellen, hvilket giver mulighed for hurtigere tekstgenerering.

Processen involverer generering af et udkast til fortsættelse af flere tokens ved hjælp af en mindre ressourcekrævende metode, efterfulgt af parallel verifikation af hovedmodellen ved hjælp af udkastet som spekulativ kontekst. Hvis verifikationsmodellen matcher udkastet til tokens, accepteres de; ellers kasseres tokens, der ikke matcher, og efterfølgende tokens, og processen gentages med et nyt udkast. Udkast til tokens kan genereres ved hjælp af forskellige tilgange, såsom træning af flere modeller, finjustering af flere hoveder på en prætrænet model for at forudsige fremtidige tokens eller anvendelse af en mindre udkastmodel sammen med en større, mere kapabel verifikationsmodel, hver med sine egne afvejninger.

Disaggregeret slutning

Disaggregeret inferens er en teknik, hvor beregningsopgaverne opdeles på forskellig hardware for at optimere ydeevne, omkostninger og ressourceforbrug. Specifikt adskiller den præfyldnings- og afkodningsfaserne. Ved at opdele disse faser kan de hver især tildeles den hardware, der er bedst egnet til deres beregningsbehov, hvilket forbedrer effektiviteten og skalerbarheden.

Disaggregeret slutning
Disaggregeret slutning

Prefilling er beregningsintensivt og kræver betydelige matrixmultiplikationer for at behandle hele inputprompten og producere KV-cacher. Denne fase drager fordel af højtydende hardware som GPU'er eller TPU'er, som udmærker sig ved parallelle beregninger. Da prefilling er en engangsopgave pr. inferensanmodning, kan den aflastes til en centraliseret, kraftfuld beregningsnode, der er optimeret til sådanne arbejdsbelastninger. Denne opsætning giver mulighed for hurtigere behandling af store forespørgsler og reducerer byrden på mindre kapable enheder, hvilket gør den ideel til skybaserede eller datacentermiljøer, hvor hardware med høj kapacitet er tilgængelig.

Afkodning er derimod hukommelsesbundet og involverer iterativ tokengenerering, der er stærkt afhængig af adgang til KV-cacherne. Det kræver mindre regnekraft, men har brug for hurtig hukommelsesadgang, hvilket gør det velegnet til mindre kraftfuld, hukommelsesoptimeret hardware som CPU'er eller edge-enheder. Ved at flytte afkodningen til separat hardware - potentielt tættere på slutbrugeren, f.eks. lokale servere eller edge-enheder - reducerer disaggregeret inferens latenstid og krav til netværksbåndbredde. Denne adskillelse muliggør fleksibel implementering, hvor prefilling kører på avancerede cloud-servere, og afkodning sker på lokale enheder eller edge-enheder, hvilket optimerer ressourceallokeringen og muliggør effektiv skalering til applikationer som chatbots i realtid eller interaktive AI-systemer.

Konklusion

Der er for nylig blevet opfundet mange teknikker til optimering af inferens for at forbedre LLM'ernes ydeevne.

Implementering af disse teknikker kræver en dyb forståelse af LLM-arkitekturen og den hardware, du bruger, så det er generelt nemmere at bruge en eksisterende inferensmotor, der allerede har implementeret disse teknikker som vLLM, TensorRT-LLM, LMDeploy osv. Vi har faktisk implementeret disse teknikker i vores egen inferensmotor hos NLP Cloud, og vi har skrevet et blogindlæg om inferensmotorer, hvis du ønsker at implementere dine egne modeller: Du kan læse det her.

Hvis du ikke selv kan eller vil implementere dine egne LLM'er, kan du bruge NLP Cloud og udnytte hurtige generative AI-modeller i stor skala i produktionen. Prøv hurtig inferens på NLP Cloud nu!

Hvis du har spørgsmål om inferensmotorer generelt, så tøv ikke med at spørge os, det er altid en fornøjelse at rådgive!

Julien
CTO hos NLP Cloud