Prompt engineering

Przyspieszanie inferencji dużych modeli językowych: techniki dla wydajnego wdrożenia

mm
Dodaj Unite.AI do preferowanych źródeł w Google
LLM Inference Speed up

Duże modele językowe (LLM) takie jak GPT-4, LLaMA i PaLM są na granicy tego, co jest możliwe w przetwarzaniu języka naturalnego. Jednak wdrożenie tych ogromnych modeli w środowiskach produkcyjnych stanowi znaczne wyzwania pod względem wymagań obliczeniowych, zużycia pamięci, opóźnień i kosztów. W miarę jak LLM-y stają się coraz większe i bardziej zaawansowane, optymalizacja ich wydajności inferencji jest kluczowa dla aplikacji w świecie rzeczywistym.

W tym technicznym artykule zagłębimy się w najnowsze techniki przyspieszania inferencji LLM, umożliwiające szybsze czasy odpowiedzi, wyższy przepływ i bardziej efektywne wykorzystanie zasobów sprzętowych. Zajmiemy się metodami od technik precyzji numerycznej i nowych mechanizmów uwagi do innowacji architektonicznych opracowanych specjalnie dla wydajnej generacji tekstu.

Zacznijmy od zrozumienia, dlaczego inferencja LLM jest tak wyzwaniem w porównaniu z tradycyjnymi modelami NLP.

Wyzwanie inferencji z dużymi modelami językowymi

Przed pojawieniem się LLM-ów, przetwarzanie języka naturalnego opierało się na mniejszych modelach skupionych na konkretnych zadaniach, takich jak klasyfikacja tekstu, rozpoznawanie nazwanych encji i analiza sentymentu. Chociaż nadal wymagające obliczeniowo, te modele mogły być wdrożone na skromnym sprzęcie i podążały dość prostymi procesami inferencji.

LLM-y, z drugiej strony, reprezentują zmianę paradygmatu. Te modele są szkolone na ogromnych zbiorach danych przy użyciu miliardów parametrów, umożliwiając im wykonywanie szerokiego zakresu zadań językowych z godnymi uwagi umiejętnościami. Jednak ta moc przychodzi z kosztem – dramatycznie zwiększonymi wymaganiami obliczeniowymi podczas szkolenia i inferencji.

Jednym z kluczowych wyzwań jest autoregresyjny charakter generacji tekstu z LLM-ami. Aby wytworzyć tekst podobny do ludzkiego, te modele przewidują jeden token (słowo lub podział słowa) na raz, z każdym nowym tokenem zależnym od wcześniej wygenerowanego wyjścia. Ta sekwencyjna zależność uniemożliwia efektywną paralelizację i skutkuje wymaganiami obliczeniowymi, które rosną wielomianowo ze względną długością sekwencji.

Ponadto LLM-y często wymagają długich sekwencji wejściowych (wypowiedzi), aby ustanowić niezbędny kontekst dla wysokiej jakości generacji tekstu. Dłuższe długości wejściowe wymagają więcej pamięci do przechowywania stanów pośrednich i macierzy uwagi, co dodatkowo obciąża zasoby sprzętowe.

Z tymi unikalnymi wyzwaniami tradycyjne techniki optymalizacji, takie jak kwantyzacja i statyczne grafy obliczeniowe, mogą okazać się niewystarczające, walcząc o utrzymanie wydajności LLM przy jednoczesnym dostarczaniu znaczących przyspieszeń. Zagłębmy się w niektóre z kluczowych strategii opracowanych specjalnie dla przyspieszania inferencji LLM.

Techniki precyzji numerycznej

From 32-Bit to 16-Bit Precision

From 32-Bit to 16-Bit Precision

Jedną z możliwości przyspieszania inferencji LLM jest wykorzystanie zmniejszonej precyzji numerycznej dla wag modelu i aktywacji. Współczesne ramy głębokiego uczenia się, takie jak PyTorch i TensorFlow, zwykle wykorzystują precyzję 32-bitową (FP32) jako domyślną. Jednak badania wykazały, że LLM-y mogą często utrzymywać wysoką dokładność nawet przy pracy w niższych precyzjach, takich jak 16-bitowa (FP16), 8-bitowa liczba całkowita (INT8) lub nawet 4-bitowa liczba całkowita (INT4).

Zmniejszanie precyzji numerycznej oferuje kilka korzyści:

  • Zmniejszony ślad pamięciowy: Niższe precyzje reprezentacji wymagają mniej pamięci, pozwalając na większe modele lub większe rozmiary partii w ramach tych samych ograniczeń sprzętowych.
  • Szybsze obliczenia: Wiele nowoczesnych CPU i GPU zapewnia specjalne instrukcje i przyspieszenie sprzętowe dla arytmetyki o niższej precyzji, umożliwiając znaczne przyspieszenia.
  • Poprawiona efektywność energetyczna: Z mniejszymi wymaganiami pamięciowymi i szybszymi obliczeniami, inferencja o niższej precyzji może przekładać się na zmniejszone zużycie energii – kluczową zaletą wdrożeń krawędziowych i mobilnych.

Chociaż potężne, techniki precyzji numerycznej wprowadzają pewną utratę dokładności w porównaniu z operacją FP32. Kluczem jest staranne ocenianie tego kompromisu między zyskami obliczeniowymi a potencjalnym pogorszeniem wydajności dla konkretnego przypadku użycia.

Istnieją dwie główne podejścia do kwantyzacji z LLM-ami:

Kwantyzacja po szkoleniu (PTQ): W tej metodzie LLM jest najpierw szkolony przy użyciu standardowej precyzji FP32. Po szkoleniu wagi modelu są kwantyzowane (przekonwertowane) na niższą precyzję, taką jak INT8 lub INT4. PTQ jest proste w implementacji, ale może prowadzić do większych spadków dokładności.

Szkolenie z kwantyzacją (QAT): Z QAT proces kwantyzacji jest symulowany podczas samej fazy szkolenia. Pozwala to modelowi nauczyć się kompensować błędy kwantyzacji, minimalizując degradację dokładności, gdy wdrożony zostanie ostateczny kwantyzowany model. QAT jest bardziej zaangażowany, ale często daje lepsze wyniki w porównaniu z PTQ.

Dla praktycznego zastosowania można wykorzystać pre-kwantyzowane modele dostępne na platformach takich jak Hugging Face, które hostują różne modele zoptymalizowane przy użyciu różnych metod kwantyzacji. Na przykład, jeśli model kwantyzowany przy użyciu Auto-GPTQ jest pożądany, użytkownicy mogą łatwo go załadować przy użyciu biblioteki transformers Hugging Face. Dodatkowo, aby skwantyzować model, można wykorzystać narzędzia takie jak AutoGPTQ, które integrują się płynnie z istniejącymi bibliotekami w celu skompresowania modelu w sposób wydajny.

Oto przykład załadowania pre-kwantyzowanego modelu Llama-2-7b przy użyciu biblioteki transformers Hugging Face:

from transformers import AutoModelForCausalLM, AutoTokenizer

<p>model_id = "TheBloke/Llama-2-7b-Chat-GPTQ"
tokenizer = AutoTokenizer.from_pretrained(model_id)
model = AutoModelForCausalLM.from_pretrained(model_id)
I dla niestandardowej kwantyzacji można postępować zgodnie z poniższymi krokami przy użyciu narzędzia AutoGPTQ:</p>

<p>from transformers import AutoModelForCausalLM, AutoTokenizer, GPTQConfig</p>

<p>model_id = "llama-2-7b-original"
tokenizer = AutoTokenizer.from_pretrained(model_id)
quantization_config = GPTQConfig(bits=4, dataset="your-dataset", tokenizer=tokenizer)
model = AutoModelForCausalLM.from_pretrained(model_id, quantization_config=quantization_config)</p>

Pamiętaj, że kwantyzacja może wymagać dodatkowego szkolenia lub inżynierii wypowiedzi, aby utrzymać jakość modelu. Dla nowej kwantyzacji możesz przyczynić się do społeczności, przekazując swoje skwantyzowane modele na platformy takie jak Hugging Face.

Zawsze upewnij się, że równoważysz rozmiar modelu, wymagania obliczeniowe i wydajność przy wyborze strategii kwantyzacji dla konkretnego przypadku użycia.

 

Algorytm Flash Attention

Mechanizm uwagi z wieloma głowicami jest podstawowym składnikiem modeli LLM opartych na transformatorach, umożliwiając modelowi przechwytywanie dalekosiężnych zależności i kontekstualizowanych reprezentacji. Jednak ta operacja uwagi jest nieefektywna obliczeniowo dla autoregresyjnej generacji tekstu, ponieważ wymaga ponownego obliczania wielu tych samych wartości dla każdego nowego tokenu.

Algorytm Flash Attention, wprowadzony w pracy FlashAttention, zapewnia bardziej efektywny i przyjazny dla paralelizacji sposób operacji uwagi. Zamiast ponownego obliczania wartości uwagi dla każdego tokenu, Flash Attention buforuje i ponownie wykorzystuje pośrednie macierze kluczy/wartości, unikając zbędnych obliczeń.

To optymalizacja nie tylko zmniejsza obciążenie obliczeniowe, ale także poprawia wzorce dostępu do pamięci, prowadząc do lepszego wykorzystania przepustowości pamięci GPU i paralelizmu.

Chociaż szczegóły Flash Attention są dość skomplikowane, podstawowa idea polega na rozłożeniu operacji uwagi na dwie fazy:

  1. Wstawienie sumy prefiksu: Ta faza oblicza i buforuje wstawienia kluczy/wartości dla wszystkich tokenów wejściowych, umożliwiając efektywne ponowne wykorzystanie podczas generacji.
  2. Uwaga przyczynowa: Samo operacja uwagi, teraz zoptymalizowana do wykorzystania buforowanych wstawień kluczy/wartości z pierwszej fazy.

Dzięki rozdzieleniu tych faz Flash Attention może korzystać z wysoko paralelizowalnych operacji GPU, znacznie przyspieszając wąskie gardło uwagi w inferencji LLM.

Oto krótkie, koncepcyjne ilustracja implementacji Flash Attention z LLM:

from transformers import AutoModelForCausalLM
import torch
from flash_attention import flash_attention

<p># Załaduj LLM, takiego jak OctoCoder
model = AutoModelForCausalLM.from_pretrained("bigcode/octocoder")</p>

<p># Przykładowa wypowiedź systemowa, która prowadzi model do bycia lepszym asystentem kodowania
system_prompt = "..."</p>

<p># Przygotowanie dłuższej wypowiedzi z wypowiedzią systemową
long_prompt = system_prompt + "Pytanie: Napisz funkcję w Pythonie, która przekształca bajty na gigabajty."</p>

<p># Przekształcenie modelu dla optymalizacji Flash Attention
model.to_bettertransformer()</p>

<p># Uruchomienie modelu z Flash Attention
start_time = time.time()
with torch.backends.cuda.sdp_kernel(enable_flash=True):
result = model.generate(long_prompt, max_new_tokens=60)
print(f"Wygenerowano w {time.time() - start_time} sekund.")

Chociaż Flash Attention oferuje imponujące przyrosty wydajności, działa w ramach istniejącej architektury transformatora. Aby w pełni wykorzystać potencjał przyspieszonej inferencji LLM, musimy zbadać innowacje architektoniczne opracowane specjalnie dla tego zadania.

Pruning LLM-ów

Pruning LLM-ów to technika redukowania rozmiaru modelu przy zachowaniu funkcjonalności. Wykorzystuje estymator ważności wag oparty na przybliżeniach macierzy Hessian. W pruning, mniej ważne grupy wag są usuwane, a następnie model jest dostrojony, aby odzyskać dokładność. Pakiet LLM-Pruner oferuje skrypty do pruning z różnymi strategiami. Pruning obejmuje odkrywanie zależności, szacowanie wkładu grup i etap odzyskiwania obejmujący krótkie poszkolenie.

Oto uproszczony przykład kodu w języku Python, demonstrujący użycie LLM-Pruner dla modelu LLaMa:

from transformers import AutoModelForSequenceClassification
from pruning import LLMPruner

<p># Załaduj pre-trenowany model LLaMa
model = AutoModelForSequenceClassification.from_pretrained("llama-base")</p>

<p># Zainicjuj pruner z pożądaną konfiguracją
pruner = LLMPruner(
model,
pruning_ratio=0.25,
block_mlp_layers=(4, 30),
block_attention_layers=(4, 30),
pruner_type='taylor'
)</p>

<p># Wykonaj pruning
pruned_model = pruner.prune()</p>

<p># Dostroj pruned model
pruned_model.fine_tune(training_data)

To kod jest zarysem, reprezentującym załadowanie pre-trenowanego modelu LLaMa, ustawienie prunera z określoną konfiguracją, wykonanie procesu pruning i dostrojenie pruned modelu.

Innowacje architektoniczne dla efektywnej generacji tekstu

Architektura transformatora, chociaż bardzo skuteczna w zadaniach modelowania języka, została zaprojektowana jako model sekwencja-do-sekwencji o ogólnym przeznaczeniu. Podczas wdrożenia LLM-ów do zadań generacji tekstu z długimi kontekstami wejściowymi, badacze odkryli, że bardziej wyspecjalizowane architektury mogą znacznie poprawić efektywność inferencji bez poświęcania jakości.

Oto niektóre z kluczowych innowacji architektonicznych umożliwiających szybszą inferencję LLM:

Alibi: Architektura Alibi, wprowadzona w pracy PAL-Instruction, oddziela modelowanie długiego kontekstu wejściowego od samego procesu generacji tekstu. Wykorzystuje skompresowaną reprezentację kontekstu wejściowego (tzw. “alibi”), aby zainicjować generację, unikając potrzeby ponownego przetwarzania pełnej sekwencji wejściowej podczas autoregresyjnej generacji.

Rotary Embeddings: Zamiast standardowych osadzeń pozycyjnych, technika rotary embedding wykorzystuje macierze obrotu do zakodowania informacji pozycyjnej w sposób bardziej efektywny. Podejście to poprawiło wyniki i umożliwiło przetwarzanie dłuższych sekwencji wejściowych.

Uwaga wielokrotna (MQA): W tradycyjnej uwadze, każdy token wyjściowy zwraca uwagę na całą sekwencję wejściową, prowadząc do zbędnych obliczeń. MQA reformuluje operację uwagi, aby dzielić obliczenia między wiele tokenów wyjściowych, zmniejszając ogólny koszt obliczeniowy.

Multiquery attention

Multiquery attention

Uwaga grupowa (GQA): Rozwijając MQA, GQA grupuje tokeny wyjściowe w klastry i oblicza uwagę wspólnie dla każdego klastra. Podejście to dalej zmniejsza wymagania obliczeniowe, utrzymując wysoką jakość generacji tekstu.

Chociaż wciąż w fazie aktywnych badań i rozwoju, te innowacje architektoniczne wykazały imponujące przyspieszenia dla zadań inferencji LLM, szczególnie gdy łączone są z technikami takimi jak Flash Attention i optymalizacja precyzji numerycznej.

Rozważania dotyczące wdrożenia w świecie rzeczywistym

Poza algorytmami i architekturami, istnieją praktyczne rozważania i kompromisy, które należy uwzględnić podczas wdrażania LLM-ów w środowiskach produkcyjnych:

Przyspieszenie sprzętowe: Chociaż procesory mogą obsłużyć inferencję LLM, GPU i inne przyspieszenia, takie jak TPUs firmy Google (GOOGL ), są niezbędne do osiągnięcia wysokiej wydajności i niskiej latencji. Wybór odpowiedniego sprzętu i optymalizacja użycia pamięci są kluczowe.

Partie i paralelizm: Aby w pełni wykorzystać paralelizm sprzętowy, strategie takie jak inferencja partiami (przetwarzanie wielu wejść jednocześnie) i paralelizm modelu (dystrybucja LLM na wiele urządzeń) mogą znacznie zwiększyć przepływ.

Kompromis między kwantyzacją a jakością: Stopień kwantyzacji (8-bit, 4-bit itd.) będzie bezpośrednio wpływał na szybkość inferencji i użycie pamięci, ale również wpłynie na jakość wyjściową. Ten kompromis musi być starannie oceniony dla każdego przypadku użycia.

Destylacja modelu: Alternatywą dla kwantyzacji są techniki destylacji modelu, które mogą skompresować duże LLM-y do mniejszych, bardziej efektywnych modeli uczniowskich, zachowując wysoką dokładność.

Buforowanie i zoptymalizowane środowiska wykonawcze: Zoptymalizowane środowiska wykonawcze głębokiego uczenia się, takie jak TensorRT od NVIDII, i ramy zaprojektowane specjalnie do obsługi LLM (np. Composable Inference Suite od MosaicML), mogą zapewnić znaczne przyrosty wydajności dzięki technikom takim jak fuzja operatorów, optymalizacja jądra i inteligentne strategie buforowania.

Ścieżka do optymalnego wdrożenia LLM często wymaga łączenia kilku technik, przy czym należy starannie rozważyć konkretnych wymagań aplikacji, ograniczeń infrastruktury i celów wydajności.

Podsumowanie

W miarę jak duże modele językowe kontynuują swoją gwałtowną ewolucję, przyspieszanie ich wydajności inferencji staje się coraz bardziej kluczowe dla umożliwienia aplikacji w świecie rzeczywistym i demokratyzacji dostępu do tych potężnych możliwości AI.

W tym przewodniku technicznym, zagłębiliśmy się w najnowsze techniki, od optymalizacji precyzji numerycznej i nowych mechanizmów uwagi, takich jak Flash Attention, po innowacje architektoniczne opracowane specjalnie dla efektywnej generacji tekstu. Chociaż każde podejście oferuje swoje własne zalety, prawdziwa moc często leży w łączeniu kilku strategii, przy uwzględnieniu złożonych kompromisów między szybkością, użyciem pamięci i jakością wyjściową.

Spójrzmy w przyszłość, możemy oczekiwać dalszych badań i rozwoju w tej dziedzinie, napędzanych przez nieustanną potrzebę bardziej zdolnych i dostępnych LLM-ów. Od przyspieszenia sprzętowego i kompresji modelu po całkowicie nowe architektury, poszukiwanie efektywnej inferencji LLM pozostaje ekscytującą granicą w świecie przetwarzania języka naturalnego i sztucznej inteligencji.

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ć.