Искусственный интеллект

Оптимизация развертывания моделей LLM: vLLM PagedAttention и будущее эффективного обслуживания ИИ

mm
Deploy the vLLM Inference Engine to Run Large Language Models

Большые языковые модели (LLM) представляют уникальные проблемы при развертывании в реальных приложениях, особенно в плане вычислительных ресурсов, задержки и эффективности затрат. В этом всестороннем руководстве мы исследуем ландшафт обслуживания LLM, с особым вниманием к vLLM (векторная модель языка), решению, которое меняет способ развертывания и взаимодействия с этими мощными моделями.

Проблемы обслуживания больших языковых моделей

Прежде чем приступить к конкретным решениям, давайте рассмотрим ключевые проблемы, которые делают обслуживание LLM сложной задачей:

Вычислительные ресурсы

LLM известны своими огромными параметрами, которые варьируются от миллиардов до сотен миллиардов. Например, GPT-3 имеет 175 миллиардов параметров, а более новые модели, такие как GPT-4, оцениваются в еще большее количество. Это огромный размер переводится в значительные вычислительные требования для вывода.

Пример:
Рассмотрим относительно скромную LLM с 13 миллиардами параметров, такой как LLaMA-13B. Даже эта модель требует:

– примерно 26 ГБ памяти только для хранения параметров модели (при условии 16-разрядной точности)
– дополнительной памяти для активаций, механизмов внимания и промежуточных вычислений
– существенной мощности GPU для реального вывода

Задержка

Во многих приложениях, таких как чат-боты или генерация контента в реальном времени, низкая задержка имеет решающее значение для хорошего пользовательского опыта. Однако сложность LLM может привести к значительному времени обработки, особенно для более длинных последовательностей.

Пример:
Представьте себе чат-бот для обслуживания клиентов, работающий на LLM. Если каждый ответ занимает несколько секунд для генерации, разговор будет казаться неестественным и раздражающим для пользователей.

Стоимость

Оборудование, необходимое для запуска LLM в крупном масштабе, может быть очень дорогим. Часто необходимы высокопроизводительные GPU или TPU, и энергопотребление этих систем существенно.

Пример:
Запуск кластера GPU NVIDIA A100 (часто используемых для вывода LLM) может стоить тысяч долларов в день в качестве облачных вычислительных сборов.

Традиционные подходы к обслуживанию LLM

Прежде чем исследовать более продвинутые решения, давайте кратко рассмотрим некоторые традиционные подходы к обслуживанию LLM:

Простое развертывание с помощью Hugging Face Transformers

Библиотека Hugging Face Transformers предоставляет простой способ развертывания LLM, но она не оптимизирована для высокопроизводительного обслуживания.

Пример кода:

“`python
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(“Будущее ИИ”))
“`

Хотя этот подход работает, он не подходит для высоконагруженных приложений из-за неэффективного использования ресурсов и отсутствия оптимизаций для обслуживания.

Использование TorchServe или аналогичных фреймворков

Фреймворки, такие как TorchServe, предоставляют более прочные возможности обслуживания, включая балансировку нагрузки и версионность модели. Однако они все еще не решают конкретные проблемы обслуживания LLM, такие как эффективное управление памятью для крупных моделей.

Понимание управления памятью в обслуживании LLM

Эффективное управление памятью имеет решающее значение для обслуживания крупных языковых моделей (LLM) из-за обширных вычислительных ресурсов, необходимых для этого. Следующие изображения иллюстрируют различные аспекты управления памятью, которые являются важными для оптимизации производительности LLM.

Сегментированная память против страниц памяти

[Подпись к изображению: Управление памятью в ОС против vLLM]

 

[Подпись к изображению: Управление памятью в ОС против vLLM]

Эти два диаграммы сравнивают техники управления памятью сегментированной памяти и страниц памяти, обычно используемые в операционных системах (ОС).

  • Сегментированная память: Этот метод делит память на разные сегменты, каждый из которых соответствует разному программе или процессу. Например, в контексте обслуживания LLM разные сегменты могут быть выделены для различных компонентов модели, таких как токенизация, встраивание и механизмы внимания. Каждый сегмент может независимо увеличиваться или уменьшаться, обеспечивая гибкость, но потенциально приводя к фрагментации, если сегменты не управляются должным образом.
  • Память страниц: Здесь память делится на фиксированные блоки страниц, которые сопоставляются с физической памятью. Страницы можно заменять по мере необходимости, обеспечивая эффективное использование ресурсов памяти. В обслуживании LLM это может быть важно для управления большими объемами памяти, необходимыми для хранения весов модели и промежуточных вычислений.

Управление памятью в ОС против vLLM

Это изображение контрастирует традиционное управление памятью ОС с подходом к управлению памятью, используемым в vLLM.

  • Управление памятью ОС: В традиционных операционных системах процессы (например, Процесс А и Процесс Б) выделяются страницы памяти (Страница 0, Страница 1 и т. д.) в физической памяти. Это выделение может привести к фрагментации со временем, поскольку процессы запрашивают и освобождают память.
  • Управление памятью vLLM: Фреймворк vLLM использует кэш Key-Value (KV) для более эффективного управления памятью. Запросы (например, Запрос А и Запрос Б) выделяются блоки кэша KV (Блок KV 0, Блок KV 1 и т. д.). Этот подход помогает минимизировать фрагментацию и оптимизировать использование памяти, позволяя быстрее и более эффективно обслуживать модель.

Механизм внимания в LLM

[Подпись к изображению: Механизм внимания в LLM]

Механизм внимания является фундаментальным компонентом моделей трансформеров, которые обычно используются для LLM. Этот диаграмма иллюстрирует формулу внимания и ее компоненты:

  • Запрос (Q): Новый токен на шаге декодера или последний токен, который модель видела.
  • Ключ (K): Предыдущий контекст, на который модель должна обратить внимание.
  • Значение (V): Взвешенная сумма по предыдущему контексту.

Формула вычисляет баллы внимания, взяв скалярное произведение запроса с ключами, масштабируя по квадратному корню размерности ключа, применяя функцию softmax и, наконец, взяв скалярное произведение с значениями. Этот процесс позволяет модели сосредоточиться на важных частях входной последовательности при генерации каждого токена.

Сравнение пропускной способности обслуживания

[Подпись к изображению: vLLM: Легкое, быстрое и дешевое обслуживание LLM с PagedAttention]

Это изображение представляет сравнение пропускной способности обслуживания между различными фреймворками (HF, TGI и vLLM) с использованием моделей LLaMA на различных конфигурациях оборудования.

  • LLaMA-13B, A100-40GB: vLLM достигает в 14-24 раза более высокой пропускной способности, чем Hugging Face Transformers (HF), и в 2,2-2,5 раза более высокой пропускной способности, чем Hugging Face Text Generation Inference (TGI).
  • LLaMA-7B, A10G: Аналогичные тенденции наблюдаются, при этом vLLM значительно превосходит как HF, так и TGI.

vLLM: Новая архитектура обслуживания LLM

vLLM, разработанный исследователями в Университете Калифорнии в Беркли, представляет собой значительный шаг вперед в технологии обслуживания LLM. Давайте исследуем его ключевые функции и инновации:

PagedAttention

В основе vLLM лежит PagedAttention, новый алгоритм внимания, вдохновленный управлением виртуальной памятью в операционных системах. Вот как он работает:

Разделение кэша Key-Value (KV): Вместо хранения всего кэша KV непрерывно в памяти PagedAttention делит его на фиксированные блоки.
Непрерывное хранение: Эти блоки могут храниться непрерывно в памяти, обеспечивая более гибкое управление памятью.
Выделение по требованию: Блоки выделяются только при необходимости, снижая浪费 памяти.
Эффективное совместное использование: Несколько последовательностей могут совместно использовать блоки, позволяя оптимизировать техники, такие как параллельное выборочное моделирование и поиск лучшего варианта.

Иллюстрация:

“`
Традиционный кэш KV:
[Токен 1 KV][Токен 2 KV][Токен 3 KV]…[Токен N KV]
(Непрерывное выделение памяти)

Кэш PagedAttention KV:
[Блок 1] -> Физический адрес А
[Блок 2] -> Физический адрес С
[Блок 3] -> Физический адрес Б

(Непрерывное выделение памяти)
“`

Этот подход значительно снижает фрагментацию памяти и позволяет использовать память GPU намного более эффективно.

Непрерывная пакетная обработка

vLLM реализует непрерывную пакетную обработку, которая обрабатывает запросы динамически по мере их поступления, а не ожидая формирования фиксированных пакетов. Это приводит к более низкой задержке и более высокой пропускной способности.

Пример:
Представьте себе поток входящих запросов:

“`
Время 0 мс: Запрос А поступает
Время 10 мс: Начинается обработка запроса А
Время 15 мс: Запрос Б поступает
Время 20 мс: Начинается обработка запроса Б (параллельно с А)
Время 25 мс: Запрос В поступает

“`

С непрерывной пакетной обработкой vLLM может начать обработку каждого запроса сразу, а не ожидать, пока они будут сгруппированы в предварительно определенные пакеты.

Эффективное параллельное выборочное моделирование

Для приложений, которые требуют нескольких выходных образцов на запрос (например, творческих помощников по написанию), возможности vLLM по совместному использованию памяти отлично подходят. Он может генерировать несколько выходов, повторно используя кэш KV для общих префиксов.

Пример кода с использованием vLLM:

“`python
from vllm import LLM, SamplingParams

llm = LLM(model=”meta-llama/Llama-2-13b-hf”)
prompts = [“Будущее ИИ”]

# Генерировать 3 образца на запрос
sampling_params = SamplingParams(n=3, temperature=0.8, max_tokens=100)
outputs = llm.generate(prompts, sampling_params)

for output in outputs:
print(f”Запрос: {output.prompt}”)
for i, out in enumerate(output.outputs):
print(f”Образец {i + 1}: {out.text}”)
“`

Этот код эффективно генерирует несколько образцов для заданного запроса, используя оптимизации vLLM.

Тестирование производительности vLLM

Чтобы по-настоящему оценить влияние vLLM, давайте посмотрим на некоторые сравнения производительности:

Сравнение пропускной способности

На основе предоставленной информации vLLM значительно превосходит другие решения обслуживания:

– до 24 раза более высокая пропускная способность по сравнению с Hugging Face Transformers
– в 2,2-3,5 раза более высокая пропускная способность, чем у Hugging Face Text Generation Inference (TGI)

Иллюстрация:

“`
Пропускная способность (токенов в секунду)
|
| ****
| ****
| ****
| **** ****
| **** **** ****
| **** **** ****
|————————
HF TGI vLLM
“`

Эффективность памяти

PagedAttention vLLM приводит к почти оптимальному использованию памяти:

– только около 4%浪费 памяти, по сравнению с 60-80% в традиционных системах
– эта эффективность позволяет обслуживать более крупные модели или обрабатывать больше одновременных запросов с тем же оборудованием

Начало работы с vLLM

Теперь, когда мы исследовали преимущества vLLM, давайте пройдемся по процессу его настройки и использования в ваших проектах.

6.1 Установка

Установка vLLM проста с помощью pip:

“`python
!pip install vllm
“`

6.2 Основное использование для автономного вывода

Вот простой пример использования vLLM для автономной генерации текста:

“`python
from vllm import LLM, SamplingParams

# Инициализация модели
llm = LLM(model=”meta-llama/Llama-2-13b-hf”)

# Подготовка запросов
prompts = [
“Напишите короткое стихотворение об искусственном интеллекте:”,
“Объясните квантовые вычисления в простых терминах:”
]

# Установка параметров выборочного моделирования
sampling_params = SamplingParams(temperature=0.8, max_tokens=100)

# Генерация ответов
outputs = llm.generate(prompts, sampling_params)

# Печать результатов
for output in outputs:
print(f”Запрос: {output.prompt}”)
print(f”Сгенерированный текст: {output.outputs[0].text}\n”)
“`

Этот скрипт демонстрирует, как загрузить модель, установить параметры выборочного моделирования и сгенерировать текст для нескольких запросов.

6.3 Настройка сервера vLLM

Для онлайн-обслуживания vLLM предоставляет сервер API, совместимый с OpenAI. Вот как его настроить:

1. Запустите сервер:

“`bash
python -m vllm.entrypoints.openai.api_server –model meta-llama/Llama-2-13b-hf
“`

2. Запросите сервер с помощью curl:

“`bash
curl http://localhost:8000/v1/completions \
-H “Content-Type: application/json” \
-d ‘{
“model”: “meta-llama/Llama-2-13b-hf”,
“prompt”: “Преимущества искусственного интеллекта включают:”,
“max_tokens”: 100,
“temperature”: 0.7
}’
“`

Эта настройка позволяет вам обслуживать вашу LLM с интерфейсом, совместимым с API OpenAI, что делает его легко интегрируемым в существующие приложения.

Расширенные темы vLLM

Хотя vLLM предлагает значительные улучшения в обслуживании LLM, есть дополнительные соображения и расширенные темы, которые необходимо исследовать:

7.1 Квантование модели

Для еще более эффективного обслуживания, особенно на оборудовании с ограниченной памятью, можно использовать техники квантования. Хотя vLLM сам по себе не поддерживает квантование, его можно использовать в сочетании с квантованными моделями:

“`python
from transformers import AutoModelForCausalLM, AutoTokenizer
import torch

# Загрузка квантованной модели
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)

# Использование квантованной модели с vLLM
from vllm import LLM

llm = LLM(model=model, tokenizer=tokenizer)
“`

7.2 Распределенное вывод

Для очень крупных моделей или высоконагруженных приложений может потребоваться распределенный вывод на нескольких GPU или машинах. Хотя vLLM не поддерживает это родно, его можно интегрировать в распределенные системы с помощью фреймворков, таких как Ray:

“`python
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)

# Инициализация распределенных LLM
llm1 = DistributedLLM.remote(“meta-llama/Llama-2-13b-hf”)
llm2 = DistributedLLM.remote(“meta-llama/Llama-2-13b-hf”)

# Использование их параллельно
result1 = llm1.generate.remote(“Запрос 1”, sampling_params)
result2 = llm2.generate.remote(“Запрос 2”, sampling_params)

# Получение результатов
print(ray.get([result1, result2]))
“`

7.3 Мониторинг и наблюдаемость

Когда вы обслуживаете LLM в производстве, мониторинг имеет решающее значение. Хотя vLLM не предоставляет встроенный мониторинг, вы можете интегрировать его с инструментами, такими как Prometheus и Grafana:

“`python
from prometheus_client import start_http_server, Summary
from vllm import LLM

# Определение метрик
REQUEST_TIME = Summary(‘request_processing_seconds’, ‘Время обработки запроса’)

# Инициализация vLLM
llm = LLM(model=”meta-llama/Llama-2-13b-hf”)

# Обнаружение метрик
start_http_server(8000)

# Использование модели с мониторингом
@REQUEST_TIME.time()
def process_request(prompt):
return llm.generate(prompt)

# Ваш цикл обслуживания здесь
“`

Эта настройка позволяет вам отслеживать метрики, такие как время обработки запроса, которые можно визуализировать в панелях Grafana.

Вывод

Эффективное обслуживание крупных языковых моделей является сложной, но важной задачей в эпоху ИИ. vLLM, с его инновационным алгоритмом PagedAttention и оптимизированной реализацией, представляет собой значительный шаг вперед в том, чтобы сделать развертывание LLM более доступным и экономически эффективным.

Улучшая пропускную способность, снижая浪费 памяти и позволяя более гибкие варианты обслуживания, vLLM открывает новые возможности для интеграции мощных языковых моделей в широкий спектр приложений. Будете ли вы строить чат-бот, систему генерации контента или любое другое приложение, работающее на NLP, понимание и использование инструментов, таких как vLLM, будут ключом к успеху.

Я провел последние пять лет, погружаясь в увлекательный мир машинного обучения и глубокого обучения. Моя страсть и экспертиза привели меня к участию в более чем 50 различных проектах программной инженерии, с особым акцентом на ИИ/МО. Мое непрекращающееся любопытство также привело меня к обработке естественного языка, области, которую я с нетерпением жду возможности изучить дальше.