Optimizing LLM Deployment: vLLM PagedAttention and the Future of Efficient AI Serving
Grote taalmodellen (LLM’s) die in toepassingen in de echte wereld worden ingezet, brengen unieke uitdagingen met zich mee, vooral op het gebied van computerbronnen, latentie en kosteneffectiviteit. In deze uitgebreide handleiding verkennen we het landschap van LLM-bediening, met een bijzondere nadruk op vLLM (vector Language Model), een oplossing die de manier verandert waarop we deze krachtige modellen inzetten en ermee omgaan.
De uitdagingen van het dienen van grote taalmodellen
Laten we, voordat we ingaan op specifieke oplossingen, eerst eens kijken naar de belangrijkste uitdagingen die ervoor zorgen dat LLM een complexe taak vervult:
Computationele bronnen
LLM’s zijn berucht vanwege hun enorme aantal parameters, variërend van miljarden tot honderden miljarden. GPT-3 beschikt bijvoorbeeld over 175 miljard parameters, terwijl recentere modellen zoals GPT-4 naar schatting zelfs nog meer hebben. Deze enorme omvang vertaalt zich in aanzienlijke rekenvereisten voor gevolgtrekking.
Voorbeeld:
Overweeg een relatief bescheiden LLM met 13 miljard parameters, zoals LLaMA-13B. Zelfs dit model vereist:
– Ongeveer 26 GB geheugen alleen al om de modelparameters op te slaan (uitgaande van een nauwkeurigheid van 16 bits)
– Extra geheugen voor activeringen, aandachtsmechanismen en tussentijdse berekeningen
– Aanzienlijke GPU-rekenkracht voor realtime gevolgtrekking
Latentie
In veel toepassingen, zoals chatbots of het realtime genereren van content, is een lage latentie cruciaal voor een goede gebruikerservaring. De complexiteit van LLM’s kan echter tot aanzienlijke verwerkingstijden leiden, vooral bij langere reeksen.
Voorbeeld:
Stel je een klantenservicechatbot voor, aangedreven door een LLM. Als het enkele seconden duurt om elk antwoord te genereren, zal het gesprek voor gebruikers onnatuurlijk en frustrerend aanvoelen.
Kosten
De hardware die nodig is om LLM’s op grote schaal uit te voeren, kan extreem duur zijn. Vaak zijn high-end GPU’s of TPU’s nodig en het energieverbruik van deze systemen is aanzienlijk.
Voorbeeld:
Het runnen van een cluster NVIDIA A100 GPU’s (vaak gebruikt voor LLM-inferentie) kan duizenden dollars per dag aan cloud computing-kosten kosten.
Traditionele benaderingen van LLM-serving
Laten we, voordat we meer geavanceerde oplossingen verkennen, kort enkele traditionele benaderingen voor het bedienen van LLM’s bekijken:
Eenvoudige implementatie met Hugging Face Transformers
De Hugging Face Transformers-bibliotheek biedt een eenvoudige manier om LLM’s te implementeren, maar is niet geoptimaliseerd voor dienstverlening met hoge doorvoer.
Voorbeeldcode:
from transformers import AutoModelForCausalLM, AutoTokenizer import torch model_name = "meta-llama/Llama-2-13b-hf" model = AutoModelForCausalLM.from_pretrained(model_name, device_map="auto") tokenizer = AutoTokenizer.from_pretrained(model_name) def generate_text(prompt, max_length=100): inputs = tokenizer(prompt, return_tensors="pt").to(model.device) outputs = model.generate(**inputs, max_length=max_length) return tokenizer.decode(outputs[0], skip_special_tokens=True) print(generate_text("The future of AI is"))
Hoewel deze aanpak werkt, is deze niet geschikt voor toepassingen met veel verkeer vanwege het inefficiënte gebruik van bronnen en het gebrek aan optimalisaties voor de weergave.
TorchServe of soortgelijke frameworks gebruiken
Frameworks zoals TorchServe bieden robuustere serveermogelijkheden, inclusief taakverdeling en modelversiebeheer. Ze gaan echter nog steeds niet in op de specifieke uitdagingen van LLM-service, zoals efficiënt geheugenbeheer voor grote modellen.
Geheugenbeheer begrijpen in LLM-serving
Efficiënt geheugenbeheer is van cruciaal belang voor het bedienen van grote taalmodellen (LLM’s) vanwege de uitgebreide benodigde computerbronnen. De volgende afbeeldingen illustreren verschillende aspecten van geheugenbeheer, die een integraal onderdeel zijn van het optimaliseren van LLM-prestaties.
Gesegmenteerd versus gewisseld geheugen
Deze twee diagrammen vergelijken gesegmenteerde geheugen- en wisselbare geheugenbeheertechnieken, die vaak worden gebruikt in besturingssystemen (OS).
- Gesegmenteerd geheugen: Deze techniek verdeelt het geheugen in verschillende segmenten, die elk overeenkomen met een ander programma of proces. In een LLM-dienende context kunnen bijvoorbeeld verschillende segmenten worden toegewezen aan verschillende componenten van het model, zoals tokenisatie, inbedding en aandachtsmechanismen. Elk segment kan onafhankelijk groeien of krimpen, waardoor flexibiliteit wordt geboden, maar mogelijk tot fragmentatie kan leiden als segmenten niet goed worden beheerd.
- Gepagineerd geheugen: Hier wordt het geheugen verdeeld in pagina’s met een vaste grootte, die worden toegewezen aan het fysieke geheugen. Pagina’s kunnen naar behoefte worden in- en uitgewisseld, waardoor een efficiënt gebruik van geheugenbronnen mogelijk is. Bij LLM-services kan dit cruciaal zijn voor het beheren van de grote hoeveelheden geheugen die nodig zijn voor het opslaan van modelgewichten en tussentijdse berekeningen.
Geheugenbeheer in besturingssysteem versus vLLM
Deze afbeelding contrasteert traditioneel OS-geheugenbeheer met de geheugenbeheerbenadering die in vLLM wordt gebruikt.
- Beheer van besturingssysteemgeheugen: In traditionele besturingssystemen worden aan processen (bijvoorbeeld proces A en proces B) geheugenpagina’s toegewezen (pagina 0, pagina 1, enz.) in het fysieke geheugen. Deze toewijzing kan in de loop van de tijd tot fragmentatie leiden, omdat processen geheugen opvragen en vrijgeven.
- vLLM-geheugenbeheer: Het vLLM-framework maakt gebruik van een Key-Value (KV)-cache om het geheugen efficiënter te beheren. Verzoeken (bijvoorbeeld Verzoek A en Verzoek B) worden toegewezen blokken van de KV-cache (KV Blok 0, KV Blok 1, etc.). Deze aanpak helpt de fragmentatie te minimaliseren en het geheugengebruik te optimaliseren, waardoor een snellere en efficiëntere modelserving mogelijk wordt.
Aandachtsmechanisme in LLM’s
Het aandachtsmechanisme is een fundamenteel onderdeel van transformatormodellen, die vaak worden gebruikt voor LLM’s. Dit diagram illustreert de aandachtsformule en zijn componenten:
- Zoekopdracht (Q): Een nieuw token in de decoderstap of het laatste token dat het model heeft gezien.
- Sleutel (K): Vorige context waar het model rekening mee moet houden.
- Waarde (V): Gewogen som ten opzichte van de vorige context.
De formule berekent de attentiescores door het puntproduct van de zoekopdracht met de sleutels te nemen, te schalen met de vierkantswortel van de sleuteldimensie, een softmax-functie toe te passen en uiteindelijk het puntproduct met de waarden te nemen. Dankzij dit proces kan het model zich concentreren op relevante delen van de invoerreeks bij het genereren van elk token.
Vergelijking van doorvoercapaciteit
Deze afbeelding toont een vergelijking van de doorvoer tussen verschillende frameworks (HF, TGI en vLLM) met behulp van LLaMA-modellen op verschillende hardware-opstellingen.
- LLaMA-13B, A100-40GB: vLLM behaalt een 14x – 24x hogere doorvoer dan HuggingFace Transformers (HF) en 2,2x – 2,5x hogere doorvoer dan HuggingFace Text Generation Inference (TGI).
- LLaMA-7B, A10G: Soortgelijke trends worden waargenomen, waarbij vLLM aanzienlijk beter presteert dan zowel HF als TGI.
vLLM: een nieuwe LLM-servicearchitectuur
vLLM, ontwikkeld door onderzoekers van UC Berkeley, vertegenwoordigt een aanzienlijke sprong voorwaarts in de LLM-bedieningstechnologie. Laten we de belangrijkste kenmerken en innovaties ervan verkennen:
PagedAttentie
De kern van vLLM wordt gevormd door PagedAttention, een nieuw aandachtsalgoritme geïnspireerd op virtueel geheugenbeheer in besturingssystemen. Dit is hoe het werkt:
– Key-Value (KV) cachepartitionering: In plaats van de volledige KV-cache aaneengesloten in het geheugen op te slaan, verdeelt PagedAttention deze in blokken van vaste grootte.
– Niet-aaneengesloten opslag: Deze blokken kunnen niet-aaneengesloten in het geheugen worden opgeslagen, waardoor een flexibeler geheugenbeheer mogelijk is.
– Toewijzing op aanvraag: Blokken worden alleen toegewezen wanneer dat nodig is, waardoor geheugenverspilling wordt verminderd.
– Efficiënt delen: Meerdere sequenties kunnen blokken delen, waardoor optimalisaties mogelijk zijn voor technieken zoals parallelle bemonstering en bundelonderzoek.
Illustratie:
“`
Traditionele KV-cache:
[Token 1 KV][Token 2 KV][Token 3 KV]…[Token N KV](Aaneengesloten geheugentoewijzing)
PagedAttention KV-cache:
[Block 1] -> Fysiek adres A
[Block 2] -> Fysiek adres C
[Block 3] -> Fysiek adres B
…
(Niet-aaneengesloten geheugentoewijzing)
“`
Deze aanpak vermindert de geheugenfragmentatie aanzienlijk en maakt een veel efficiënter gebruik van GPU-geheugen mogelijk.
Continu batchen
vLLM implementeert continue batching, waarbij aanvragen dynamisch worden verwerkt zodra ze binnenkomen, in plaats van te wachten op het vormen van batches van vaste grootte. Dit leidt tot een lagere latentie en een hogere doorvoer.
Voorbeeld:
Stel je een stroom binnenkomende verzoeken voor:
“`
Tijd 0 ms: Verzoek A arriveert
Tijd 10 ms: Start de verwerking van verzoek A
Tijd 15 ms: Verzoek B arriveert
Tijd 20 ms: Start verwerking van verzoek B (parallel met A)
Tijd 25 ms: Verzoek C arriveert
…
“`
Met continue batchverwerking kan vLLM elk verzoek onmiddellijk verwerken, in plaats van te wachten met het groeperen ervan in vooraf gedefinieerde batches.
Efficiënte parallelle bemonstering
Voor toepassingen die meerdere uitvoervoorbeelden per prompt vereisen (bijvoorbeeld creatieve schrijfassistenten), blinken de mogelijkheden van vLLM voor het delen van geheugen uit. Het kan meerdere uitvoer genereren terwijl de KV-cache wordt hergebruikt voor gedeelde voorvoegsels.
Voorbeeldcode met vLLM:
from vllm import LLM, SamplingParams llm = LLM(model="meta-llama/Llama-2-13b-hf") prompts = ["The future of AI is"] # Generate 3 samples per prompt sampling_params = SamplingParams(n=3, temperature=0.8, max_tokens=100) outputs = llm.generate(prompts, sampling_params) for output in outputs: print(f"Prompt: output.prompt") for i, out in enumerate(output.outputs): print(f"Sample i + 1: out.text")
Deze code genereert op efficiënte wijze meerdere voorbeelden voor de gegeven prompt, waarbij gebruik wordt gemaakt van de optimalisaties van vLLM.
Benchmarking van vLLM-prestaties
Laten we eens kijken naar enkele prestatievergelijkingen om de impact van vLLM echt te kunnen waarderen:
Doorvoervergelijking
Op basis van de verstrekte informatie presteert vLLM aanzienlijk beter dan andere serveeroplossingen:
– Tot 24x hogere doorvoer vergeleken met Hugging Face Transformers
– 2,2x tot 3,5x hogere doorvoer dan Hugging Face Text Generation Inference (TGI)
Illustratie:
“`
Doorvoer (tokens/seconde)
|
| ****
| ****
| ****
| **** ****
| **** **** ****
| **** **** ****
|————————
HF TGI vLLM
“`
Geheugenefficiëntie
vLLM’s PagedAttention resulteert in een vrijwel optimaal geheugengebruik:
– Slechts ongeveer 4% geheugenverspilling, vergeleken met 60-80% in traditionele systemen
– Deze efficiëntie maakt het mogelijk grotere modellen te bedienen of meer gelijktijdige verzoeken af te handelen met dezelfde hardware
Aan de slag met vLLM
Nu we de voordelen van vLLM hebben onderzocht, gaan we het proces van het instellen en gebruiken ervan in uw projecten doornemen.
6.1 Installatie
Het installeren van vLLM is eenvoudig met behulp van pip:
!pip install vllm
6.2 Basisgebruik voor offline gevolgtrekking
Hier is een eenvoudig voorbeeld van het gebruik van vLLM voor het offline genereren van tekst:
from vllm import LLM, SamplingParams # Initialize the model llm = LLM(model="meta-llama/Llama-2-13b-hf") # Prepare prompts prompts = [ "Write a short poem about artificial intelligence:", "Explain quantum computing in simple terms:" ] # Set sampling parameters sampling_params = SamplingParams(temperature=0.8, max_tokens=100) # Generate responses outputs = llm.generate(prompts, sampling_params) # Print the results for output in outputs: print(f"Prompt: output.prompt") print(f"Generated text: output.outputs[0].text\n")
Dit script laat zien hoe u een model laadt, steekproefparameters instelt en tekst genereert voor meerdere aanwijzingen.
6.3 Een vLLM-server instellen
Voor online dienstverlening biedt vLLM een OpenAI-compatibele API-server. Zo stelt u het in:
1. Start de server:
python -m vllm.entrypoints.openai.api_server --model meta-llama/Llama-2-13b-hf
2. Voer een query uit op de server met behulp van curl:
curl http://localhost:8000/v1/completions \ -H "Content-Type: application/json" \ -d ' "model": "meta-llama/Llama-2-13b-hf", "prompt": "The benefits of artificial intelligence include:", "max_tokens": 100, "temperature": 0.7 '
Met deze opstelling kunt u uw LLM bedienen met een interface die compatibel is met de API van OpenAI, waardoor deze eenvoudig in bestaande applicaties kan worden geïntegreerd.
Geavanceerde onderwerpen over vLLM
Hoewel vLLM aanzienlijke verbeteringen biedt in de LLM-service, zijn er aanvullende overwegingen en geavanceerde onderwerpen die u kunt verkennen:
7.1 Modelkwantisering
Voor een nog efficiëntere bediening, vooral op hardware met beperkt geheugen, kunnen kwantiseringstechnieken worden gebruikt. Hoewel vLLM zelf momenteel geen kwantisering ondersteunt, kan het worden gebruikt in combinatie met gekwantiseerde modellen:
from transformers import AutoModelForCausalLM, AutoTokenizer import torch # Load a quantized model model_name = "meta-llama/Llama-2-13b-hf" model = AutoModelForCausalLM.from_pretrained(model_name, device_map="auto", load_in_8bit=True) tokenizer = AutoTokenizer.from_pretrained(model_name) # Use the quantized model with vLLM from vllm import LLM llm = LLM(model=model, tokenizer=tokenizer)
7.2 Gedistribueerde gevolgtrekking
Voor extreem grote modellen of toepassingen met veel verkeer kan gedistribueerde inferentie over meerdere GPU’s of machines noodzakelijk zijn. Hoewel vLLM dit niet standaard ondersteunt, kan het worden geïntegreerd in gedistribueerde systemen met behulp van frameworks zoals Ray:
import ray from vllm import LLM @ray.remote(num_gpus=1) class DistributedLLM: def __init__(self, model_name): self.llm = LLM(model=model_name) def generate(self, prompt, params): return self.llm.generate(prompt, params) # Initialize distributed LLMs llm1 = DistributedLLM.remote("meta-llama/Llama-2-13b-hf") llm2 = DistributedLLM.remote("meta-llama/Llama-2-13b-hf") # Use them in parallel result1 = llm1.generate.remote("Prompt 1", sampling_params) result2 = llm2.generate.remote("Prompt 2", sampling_params) # Retrieve results print(ray.get([result1, result2]))
7.3 Monitoring en waarneembaarheid
Bij het bedienen van LLM’s in de productie is monitoring cruciaal. Hoewel vLLM geen ingebouwde monitoring biedt, kunt u deze integreren met tools zoals Prometheus en Grafana:
from prometheus_client import start_http_server, Summary from vllm import LLM # Define metrics REQUEST_TIME = Summary('request_processing_seconds', 'Time spent processing request') # Initialize vLLM llm = LLM(model="meta-llama/Llama-2-13b-hf") # Expose metrics start_http_server(8000) # Use the model with monitoring @REQUEST_TIME.time() def process_request(prompt): return llm.generate(prompt) # Your serving loop here
Met deze configuratie kunt u statistieken bijhouden, zoals de verwerkingstijd van verzoeken, die kunnen worden gevisualiseerd in Grafana-dashboards.
Conclusie
Het efficiënt bedienen van grote taalmodellen is een complexe maar cruciale taak in het tijdperk van AI. vLLM vertegenwoordigt met zijn innovatieve PagedAttention-algoritme en geoptimaliseerde implementatie een belangrijke stap voorwaarts in het toegankelijker en kosteneffectiever maken van LLM-implementatie.
Door de doorvoer dramatisch te verbeteren, geheugenverspilling terug te dringen en flexibelere bedieningsopties mogelijk te maken, opent vLLM nieuwe mogelijkheden voor het integreren van krachtige taalmodellen in een breed scala aan toepassingen. Of u nu een chatbot, een systeem voor het genereren van inhoud of een andere NLP-aangedreven applicatie bouwt, het begrijpen en benutten van tools zoals vLLM zal de sleutel tot succes zijn.