Modele i platformy AI

Optymalizacja wdroÅženia modeli LLM: vLLM PagedAttention i przyszłość wydajnego serwowania AI

mm
Dodaj Unite.AI do preferowanych ÅšrÃģdeł w Google

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 w LLM

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

vLLM: Łatwe, szybkie i tanie serwowanie LLM z PagedAttention

vLLM: Łatwe, szybkie i tanie serwowanie LLM z PagedAttention

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.

Przez ostatnie pięć lat zanurzałem się w fascynującym świecie Machine Learning i Deep Learning. Moja pasja i ekspertyza doprowadziły mnie do udziału w ponad 50 rÃģÅžnorodnych projektach inÅžynierii oprogramowania, ze szczegÃģlnym uwzględnieniem AI/ML. Moja nieustanna ciekawość rÃģwnieÅž skierowała mnie w stronę Natural Language Processing, dziedziny, ktÃģrą chcę dalej eksplorować.