Modele i platformy AI
Optymalizacja wdrożenia modeli LLM: vLLM PagedAttention i przyszłość wydajnego serwowania AI
Wdrożenie modeli językowych (LLM) w aplikacjach świata rzeczywistego stwarza unikalne wyzwania, szczególnie w zakresie zasobów obliczeniowych, opóźnień i efektywności kosztowej. W tym kompleksowym przewodniku, będziemy badać krajobraz serwowania LLM, ze szczególnym uwzględnieniem vLLM (wektorowy model językowy), rozwiązania, które zmienia sposób, w jaki wdrażamy i korzystamy z tych potężnych modeli.
Wyzwania serwowania modeli językowych
Przed przejściem do konkretnych rozwiązań, rozważmy kluczowe wyzwania, które sprawiają, że serwowanie LLM jest złożonym zadaniem:
Zasoby obliczeniowe
LLM są znane ze swoich ogromnych liczb parametrów, sięgających od miliardów do setek miliardów. Na przykład, GPT-3 ma 175 miliardów parametrów, podczas gdy nowsze modele, takie jak GPT-4 mają jeszcze więcej. Ten ogromny rozmiar przekłada się na znaczne wymagania obliczeniowe dla inferencji.
Przykład:
Rozważmy stosunkowo skromny LLM z 13 miliardami parametrów, takim jak LLaMA-13B. Nawet ten model wymaga:
– Około 26 GB pamięci, aby przechować parametry modelu (przy założeniu 16-bitowej precyzji)
– Dodatkowej pamięci dla aktywacji, mechanizmów uwagi i obliczeń pośrednich
– Znacznej mocy obliczeniowej GPU dla inferencji w czasie rzeczywistym
Opóźnienia
W wielu aplikacjach, takich jak czatboty lub generacja treści w czasie rzeczywistym, niskie opóźnienia są kluczowe dla dobrego doświadczenia użytkownika. Jednak złożoność LLM może prowadzić do znacznych czasów przetwarzania, szczególnie dla dłuższych sekwencji.
Przykład:
Wyobraźmy sobie czatbota obsługiwanego przez LLM. Jeśli każda odpowiedź zajmuje kilka sekund, rozmowa będzie wyglądać nienaturalnie i frustrująco dla użytkowników.
Koszt
Sprzęt niezbędny do uruchomienia LLM w skali może być bardzo drogi. Często wymagane są wysokiej jakości GPU lub TPU, a zużycie energii przez te systemy jest znaczne.
Przykład:
Uruchomienie klastra NVIDIA A100 GPU (często używanych do inferencji LLM) może kosztować tysiące dolarów dziennie w opłatach za chmurę obliczeniową.
Tradycyjne podejścia do serwowania LLM
Przed zbadaniem bardziej zaawansowanych rozwiązań, krótko przeglądnijmy tradycyjne podejścia do serwowania LLM:
Proste wdrożenie z Hugging Transformers
Biblioteka Hugging Face Transformers zapewnia prosty sposób wdrożenia LLM, ale nie jest zoptymalizowana do serwowania o wysokiej wydajności.
Przykład kodu:
from transformers import AutoModelForCausalLM, AutoTokenizer
import torch
<p>model_name = "meta-llama/Llama-2-13b-hf"
model = AutoModelForCausalLM.from_pretrained(model_name, device_map="auto")
tokenizer = AutoTokenizer.from_pretrained(model_name)</p>
<p>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)</p>
<p>print(generate_text("The future of AI is"))
Chociaż to podejście działa, nie jest odpowiednie dla aplikacji o wysokim ruchu ze względu na niewydajne wykorzystanie zasobów i brak optymalizacji do serwowania.
Użycie TorchServe lub podobnych frameworków
Frameworki takie jak TorchServe zapewniają bardziej solidne możliwości serwowania, w tym równoważenie obciążenia i wersjonowanie modelu. Jednak nadal nie rozwiązują specyficznych wyzwań serwowania LLM, takich jak efektywne zarządzanie pamięcią dla dużych modeli.
Zrozumienie zarządzania pamięcią w serwowaniu LLM
Efektywne zarządzanie pamięcią jest kluczowe dla serwowania dużych modeli językowych (LLM) ze względu na ogromne wymagania obliczeniowe. Poniższe obrazy ilustrują różne aspekty zarządzania pamięcią, które są integralne dla optymalizacji wydajności LLM.
Segmentowana a pamięć stronicowana
Te dwa diagramy porównują techniki zarządzania pamięcią segmentowaną i stronicowaną, powszechnie używane w systemach operacyjnych (OS).
- Pamięć segmentowana: Ta technika dzieli pamięć na różne segmenty, z których każdy odpowiada różnemu programowi lub procesowi. Na przykład, w kontekście serwowania LLM, różne segmenty mogą być przydzielone do różnych komponentów modelu, takich jak tokenizacja, osadzanie i mechanizmy uwagi. Każdy segment może rosnąć lub kurczyć się niezależnie, zapewniając elastyczność, ale potencjalnie prowadząc do fragmentacji, jeśli segmenty nie są odpowiednio zarządzane.
- Pamięć stronicowana: Tutaj pamięć jest podzielona na strony o stałym rozmiarze, które są mapowane na pamięć fizyczną. Strony mogą być wymieniane w razie potrzeby, umożliwiając efektywne wykorzystanie zasobów pamięci. W serwowaniu LLM może to być kluczowe dla zarządzania dużymi ilościami pamięci wymaganymi do przechowywania wag modelu i obliczeń pośrednich.
Zarządzanie pamięcią w systemie operacyjnym vs. vLLM
Ten obraz kontrastuje tradycyjne zarządzanie pamięcią w systemie operacyjnym z podejściem do zarządzania pamięcią używanym w vLLM.
- Zarządzanie pamięcią w systemie operacyjnym: W tradycyjnych systemach operacyjnych, procesy (np. Proces A i Proces B) są przydzielane strony pamięci (Strona 0, Strona 1 itd.) w pamięci fizycznej. To przydzielanie może prowadzić do fragmentacji z czasem, gdy procesy żądają i zwalniają pamięć.
- Zarządzanie pamięcią w vLLM: Framework vLLM wykorzystuje pamięć podręczną Key-Value (KV), aby zarządzać pamięcią w sposób bardziej efektywny. Żądania (np. Żądanie A i Żądanie B) są przydzielane bloki pamięci podręcznej KV (Blok 0, Blok 1 itd.). To podejście pomaga minimalizować fragmentację i optymalizować wykorzystanie pamięci, umożliwiając szybsze i bardziej efektywne serwowanie modelu.
Mechanizm uwagi w LLM
Mechanizm uwagi jest podstawowym komponentem modeli transformatorowych, które są powszechnie używane w LLM. Ten diagram ilustruje wzór uwagi i jego składniki:
- Zapytanie (Q): Nowy token w kroku dekodera lub ostatni token, który model widział.
- Klucz (K): Poprzedni kontekst, do którego model powinien się odnosić.
- Wartość (V): Uwzględniona suma poprzedniego kontekstu.
Wzór oblicza wyniki uwagi, biorąc iloczyn skalarny zapytania z kluczami, skalując przez pierwiastek kwadratowy wymiaru klucza, stosując funkcję softmax i biorąc iloczyn skalarny z wartościami. Ten proces pozwala modelowi koncentrować się na istotnych częściach sekwencji wejściowej podczas generowania każdego tokenu.
Porównanie przepustowości serwowania
Ten obraz przedstawia porównanie przepustowości serwowania między różnymi frameworkami (HF, TGI i vLLM) przy użyciu modeli LLaMA na różnych konfiguracjach sprzętu.
- LLaMA-13B, A100-40GB: vLLM osiąga 14-krotnie do 24-krotnie wyższą przepustowość niż Hugging Face Transformers (HF) i 2,2-krotnie do 2,5-krotnie wyższą przepustowość niż Hugging Face Text Generation Inference (TGI).
- LLaMA-7B, A10G: Obserwuje się podobne trendy, z vLLM znacznie przewyższając zarówno HF, jak i TGI.
vLLM: Nowa architektura serwowania LLM
vLLM, opracowany przez badaczy z UC Berkeley, reprezentuje znaczny krok naprzód w technologii serwowania LLM. Przeanalizujmy jego kluczowe funkcje i innowacje:
PagedAttention
W sercu vLLM leży PagedAttention, nowy algorytm uwagi zainspirowany zarządzaniem pamięcią wirtualną w systemach operacyjnych. Oto, jak to działa:
– Podział pamięci podręcznej Key-Value (KV): Zamiast przechowywać całą pamięć podręczną KV w pamięci w sposób ciągły, PagedAttention dzieli ją na bloki o stałym rozmiarze.
– Przechowywanie nieciągłe: Te bloki mogą być przechowywane w pamięci w sposób nieciągły, umożliwiając bardziej elastyczne zarządzanie pamięcią.
– Przydzielanie na żądanie: Bloki są przydzielane tylko wtedy, gdy są potrzebne, redukując marnowanie pamięci.
– Wygodne udostępnianie: Wiele sekwencji może udostępniać bloki, umożliwiając optymalizację dla technik takich jak próbkowanie równoległe i wyszukiwanie promieniowe.
Ilustracja:
“`
Tradycyjna pamięć podręczna KV:
[Token 1 KV][Token 2 KV][Token 3 KV]…[Token N KV]
(Przechowywanie ciągłe)
“`
PagedAttention pamięć podręczna KV:
[Blok 1] -> Adres fizyczny A
[Blok 2] -> Adres fizyczny C
[Blok 3] -> Adres fizyczny B
…
(Przechowywanie nieciągłe)
“`
To podejście znacznie redukuje fragmentację pamięci i pozwala na znacznie bardziej efektywne wykorzystanie pamięci GPU.
Ciągłe grupowanie
vLLM wdraża ciągłe grupowanie, które dynamicznie przetwarza żądania w momencie ich przybycia, zamiast czekania na utworzenie partii o stałym rozmiarze. To prowadzi do niższych opóźnień i wyższej przepustowości.
Przykład:
Wyobraźmy sobie strumień przychodzących żądań:
“`
Czas 0ms: Żądanie A przychodzi
Czas 10ms: Rozpoczęcie przetwarzania Żądania A
Czas 15ms: Żądanie B przychodzi
Czas 20ms: Rozpoczęcie przetwarzania Żądania B (w równolegle z A)
Czas 25ms: Żądanie C przychodzi
…
“`
Z ciągłym grupowaniem vLLM może rozpocząć przetwarzanie każdego żądania natychmiast, zamiast czekać na utworzenie partii o określonym rozmiarze.
Wygodne próbkowanie równoległe
Dla aplikacji, które wymagają wielu próbek wyjściowych na każde wejście (np. asystentów tworzenia treści), możliwości udostępniania pamięci vLLM są szczególnie przydatne. Może generować wiele wyjść, jednocześnie ponownie wykorzystując pamięć podręczną KV dla wspólnych prefiksów.
Przykład kodu przy użyciu vLLM:
from vllm import LLM, SamplingParams
<p>llm = LLM(model="meta-llama/Llama-2-13b-hf")
prompts = ["Przyszłość AI jest"]</p>
<p># Generuj 3 próbki dla każdego wejścia
sampling_params = SamplingParams(n=3, temperature=0.8, max_tokens=100)
outputs = llm.generate(prompts, sampling_params)</p>
<p>for output in outputs:
print(f"Prompt: {output.prompt}")
for i, out in enumerate(output.outputs):
print(f"Próbka {i + 1}: {out.text}")</p>
Ten kod efektywnie generuje wiele próbek dla danego wejścia, wykorzystując optymalizacje vLLM.
Testowanie wydajności vLLM
Aby naprawdę docenić wpływ vLLM, przyjrzyjmy się porównaniom wydajności:
Porównanie przepustowości
Na podstawie podanych informacji, vLLM znacznie przewyższa inne rozwiązania serwowania:
– Do 24-krotnie wyższa przepustowość w porównaniu z Hugging Face Transformers
– 2,2-krotnie do 3,5-krotnie wyższa przepustowość niż Hugging Face Text Generation Inference (TGI)
Ilustracja:
“`
Przepustowość (Tokeny/sekunda)
|
| ****
| ****
| ****
| **** ****
| **** **** ****
| **** **** ****
|————————
HF TGI vLLM
“`
Efektywność pamięci
PagedAttention vLLM prowadzi do prawie optymalnego wykorzystania pamięci:
– Tylko około 4% marnowania pamięci, w porównaniu z 60-80% w tradycyjnych systemach
– Ta efektywność pozwala na serwowanie większych modeli lub obsługę większej liczby równoczesnych żądań przy użyciu tego samego sprzętu.
Rozpoczęcie pracy z vLLM
Teraz, gdy już zbadaliśmy zalety vLLM, przejdźmy przez proces instalacji i korzystania z niego w Twoich projektach.
6.1 Instalacja
Instalacja vLLM jest prosta przy użyciu pip:
!pip install vllm
6.2 Podstawowe użycie do inferencji offline
Oto prosty przykład użycia vLLM do generacji tekstu offline:
from vllm import LLM, SamplingParams
<p># Zainicjuj model
llm = LLM(model="meta-llama/Llama-2-13b-hf")</p>
<p># Przygotuj wejścia
prompts = [
"Napisz krótki wiersz o sztucznej inteligencji:",
"Wyjaśnij kwantową komputację w prosty sposób:"
]</p>
<p># Ustaw parametry próbkowania
sampling_params = SamplingParams(temperature=0.8, max_tokens=100)</p>
<p># Wygeneruj odpowiedzi
outputs = llm.generate(prompts, sampling_params)</p>
<p># Wypisz wyniki
for output in outputs:
print(f"Prompt: {output.prompt}")
print(f"Wygenerowany tekst: {output.outputs[0].text}\n")</p>
Ten skrypt demonstruje, jak załadować model, ustawić parametry próbkowania i wygenerować tekst dla wielu wejść.
6.3 Konfigurowanie serwera vLLM
Dla serwowania online, vLLM zapewnia serwer API zgodny z OpenAI. Oto, jak go skonfigurować:
1. Uruchom serwer:
python -m vllm.entrypoints.openai.api_server --model meta-llama/Llama-2-13b-hf
2. Wyślij żądanie do serwera przy użyciu curl:
curl http://localhost:8000/v1/completions \
-H "Content-Type: application/json" \
-d '{"model": "meta-llama/Llama-2-13b-hf", "prompt": "Korzyści z sztucznej inteligencji to:", "max_tokens": 100, "temperature": 0.7}'
Ten zestaw pozwala na serwowanie Twojego LLM z interfejsem zgodnym z API OpenAI, co ułatwia integrację z istniejącymi aplikacjami.
Zaawansowane tematy na temat vLLM
Chociaż vLLM oferuje znaczne ulepszenia w serwowaniu LLM, istnieją dodatkowe rozważania i zaawansowane tematy do zbadania:
7.1 Kwantyzacja modelu
Dla jeszcze bardziej efektywnego serwowania, szczególnie na sprzęcie z ograniczoną pamięcią, można zastosować techniki kwantyzacji. Chociaż vLLM sam w sobie nie obsługuje kwantyzacji, może być używany w połączeniu z zkwantyfikowanymi modelami:
from transformers import AutoModelForCausalLM, AutoTokenizer import torch <p># Załaduj zkwantyfikowany 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)</p> <p># Użyj zkwantyfikowanego modelu z vLLM from vllm import LLM</p> <p>llm = LLM(model=model, tokenizer=tokenizer)
7.2 Rozproszone inferencje
Dla bardzo dużych modeli lub aplikacji o wysokim ruchu, rozproszone inferencje na wielu GPU lub maszynach mogą być konieczne. Chociaż vLLM nie obsługuje tego natywnie, może być integrowany z systemami rozproszonymi przy użyciu frameworków takich jak Ray:
import ray
from vllm import LLM
<p>@ray.remote(num_gpus=1)
class DistributedLLM:
def __init__(self, model_name):
self.llm = LLM(model=model_name)</p>
<p>def generate(self, prompt, params):
return self.llm.generate(prompt, params)</p>
<p># Zainicjuj rozproszone LLM
llm1 = DistributedLLM.remote("meta-llama/Llama-2-13b-hf")
llm2 = DistributedLLM.remote("meta-llama/Llama-2-13b-hf")</p>
<p># Użyj ich w równolegle
result1 = llm1.generate.remote("Prompt 1", sampling_params)
result2 = llm2.generate.remote("Prompt 2", sampling_params)</p>
<p># Pobierz wyniki
print(ray.get([result1, result2]))
7.3 Monitorowanie i obserwowalność
Podczas serwowania LLM w produkcji, monitorowanie jest kluczowe. Chociaż vLLM nie zapewnia wbudowanego monitorowania, można go zintegrować z narzędziami takimi jak Prometheus i Grafana:
from prometheus_client import start_http_server, Summary
from vllm import LLM
<p># Zdefiniuj metryki
REQUEST_TIME = Summary('request_processing_seconds', 'Czas przetwarzania żądania')</p>
<p># Zainicjuj vLLM
llm = LLM(model="meta-llama/Llama-2-13b-hf")</p>
<p># Udostępnij metryki
start_http_server(8000)</p>
<p># Użyj modelu z monitorowaniem
@REQUEST_TIME.time()
def process_request(prompt):
return llm.generate(prompt)</p>
# Twoja pętla serwowania tutaj
Ten zestaw pozwala śledzić metryki takie jak czas przetwarzania żądania, które mogą być wizualizowane w dashboardach Grafana.
Podsumowanie
Serwowanie dużych modeli językowych w sposób efektywny jest złożonym, ale kluczowym zadaniem w erze AI. vLLM, z jego innowacyjnym algorytmem PagedAttention i zoptymalizowaną implementacją, reprezentuje znaczny krok naprzód w czynieniu wdrożenia LLM bardziej dostępnym i efektywnym kosztowo.
Poprzez dramatyczne poprawienie przepustowości, redukcję marnowania pamięci i umożliwienie bardziej elastycznego serwowania, vLLM otwiera nowe możliwości integracji potężnych modeli językowych w szeroki zakres aplikacji. Niezależnie od tego, czy budujesz czatbota, system generacji treści, czy jakąkolwiek inną aplikację napędzaną NLP, zrozumienie i wykorzystanie narzędzi takich jak vLLM będzie kluczem do sukcesu.
















