Esakov


Гео и язык канала: Россия, Русский
Категория: Познавательное



Гео и язык канала
Россия, Русский
Статистика
Фильтр публикаций


Ну да, я 🙄




🍵 Мемо правок за день

Интересную и при этом супербанальную штуку для себя открыл в codex/claude - мемо правок за день. Очень помогает перед дейликом или викликом: не мямлить, не вспоминать на ходу, чем вообще занимался, и не создавать ощущение, что за вчера ты ничего не сделал. Потому что «пилил сервис, делал таску» звучит так себе.

Главное - перед дейликом проговорить все пункты, продумать речь, чтобы не читать сгенерированный список (это сразу видно) ❤️


🙄


✏️ Слово дня - "Disambiguation"

Disambiguation — это устранение неоднозначности и выбор точного значения слова или запроса на основе контекста. Процесс помогает понять, что именно имеется в виду. Т.е. это процесс устранения омонимии.

Если в системе есть сущности "Париж, Франция" и "Париж, Техас", то дизамбигуация (жесть, лучше по английски это слово говорить и писать) — это этап, на котором по контексту определяется, какой именно Париж имеется в виду.

В NLP/LLM это встречается постоянно: entity disambiguation — определить, какая конкретно сущность имеется в виду; word sense disambiguation (WSD) — определить значение многозначного слова; а в RAG/GraphRAG — понять, к какому объекту базы знаний привязать упоминание.

Если вам стало страшно при виде этого слова, не переживайте, мне тоже 🔦


Видео недоступно для предпросмотра
Смотреть в Telegram
Это база 💧


🍊 Впихиваем невпихуемое. Видеопамять в GPUStack, vLLM и KV-cache
(монстр-текст 😐)

Недавно на работе немного пришлось поиграть в тетрис. Две видеокарты вышли из чата, но сервисы от этого работать перестать не должны. Значит, оставшиеся модели нужно как-то перераспределить по живым GPU и попытаться впихнуть невпихуемое.

И вот тут началось интересное.

Одна из моделей — Qwen — при развёртывании в GPUStack как будто фантомно требовала заметно больше памяти, чем потом реально занимала. На карте вроде бы есть свободная VRAM, по расчётам модель должна помещаться, а GPUStack говорит: нет, места недостаточно.

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

Часть проблемы оказалась связана с тем, что модель VL. При развёртывании она прогоняет изображение максимально допустимого разрешения, из-за чего на старте потребление памяти временно раздувается. При обычной работе таких эксцессов уже не возникает.

А дальше выяснился ещё один нюанс — поведение vLLM и параметра:

--gpu-memory-utilization 🍊

Интуитивно хочется думать так: поставил 0.5 — значит разрешил модели занять половину той памяти, которая сейчас свободна.

Но работает это иначе.

vLLM считает эту долю от полного объёма VRAM видеокарты, а не от памяти, которая свободна в данный момент.

Например, если на GPU 24 ГБ:

gpu_memory_utilization = 0.5

означает бюджет примерно в 12 ГБ.

Если при этом свободно только 10 ГБ, это не превращается в «ну тогда дадим новой модели 5 ГБ». vLLM всё равно ориентируется на свои 12 ГБ.

И эти 12 ГБ — это не просто веса модели.

Если совсем грубо:

бюджет vLLM = weights + activations + overhead + KV-cache

Веса особо никуда не денутся, поэтому уменьшение gpu-memory-utilization — это не способ магически «сжать» модель. В первую очередь мы начинаем откусывать память у KV-cache и остальной рабочей памяти.

Из-за этого некоторые модели действительно удаётся довольно прилично поджать. Например, с Whisper у меня это сработало вполне успешно.

А с другими можно крутить параметр вниз сколько угодно: в какой-то момент веса плюс необходимый runtime overhead просто перестают помещаться в заданный бюджет. И всё — модель говорит: спасибо, я лучше вообще не запущусь.

А что вообще такое KV-cache? 😐

Если очень упрощённо — это память модели о том, что она уже успела «прочитать».

Когда LLM генерирует следующий токен, attention нужны данные по предыдущим токенам контекста. Можно было бы на каждом шаге пересчитывать всё заново, но это было бы очень дорого.

Поэтому уже вычисленные Key и Value складываются в кэш и потом переиспользуются.

Отсюда простая зависимость:

больше контекст → больше KV-cache → больше VRAM

Причём дело не только в длине одного запроса. Важно ещё и количество запросов, которые модель обрабатывает одновременно. Поэтому модель, которая спокойно живёт при одном пользователе, под нормальной нагрузкой уже может начать заметно сильнее есть память.

И вот тут как раз становится понятно, за что мы платим, уменьшая gpu-memory-utilization.

Сама модель легче не становится. Мы просто оставляем меньше памяти под KV-cache и всё остальное вокруг неё.

То есть модель в GPU вроде бы влезла — отлично. Но дальше где-то придётся расплачиваться: количеством одновременно обрабатываемых токенов и запросов, запасом под длинный контекст или всем сразу.

Никакой бесплатной памяти тут, к сожалению, не появляется. 🚫




😨


🎰 Видимо надо учиться рационально использовать токены..


🚬


🍊


🚬 Люблю запах рефакторинга по утрам


ну да, я 🍊


✏️ LLM's Backends (монстр-текст)

Как встроить LLM в сервис?
Можно просто поднять на сервере контейнер, внутри запустить Python-процесс, загрузить модель через transformers и обращаться к ней из приложения.
Для одного прототипа — нормально. Но дальше появляются вопросы.

А если эта LLM нужна сразу нескольким сервисам? Каждый сервис будет отдельно грузить свою копию модели? Или все будут ходить по HTTP в один контейнер? А если запросов станет много? Как управлять доступом? Как обновлять модель? Как распределять несколько моделей между несколькими GPU?

В итоге приходим к довольно стандартному для system design решению — LLM как отдельный микросервис.

Сервисы не знают, где физически лежит модель и как она запущена. Они просто делают запрос:

Service
↓ HTTP
LLM API
↓
Model

У нас обслуживание этого слоя упрощает GPUStack.
Один раз настраиваем GPUStack и подключаем к нему GPU-серверы, а дальше можем централизованно разворачивать модели и обращаться к ним через единый OpenAI-compatible API.

Получается примерно так:

Service
↓ API
GPUStack
↓
Worker
↓
Container
↓
Inference Backend
↓
Model
↓
CUDA
↓
GPU

Но что вообще происходит внутри контейнера?
В Jupyter Notebook мы обычно делаем что-то в духе:

model = AutoModel.from_pretrained(...)

Библиотека создаёт модель, загружает её веса в RAM/VRAM, после чего мы можем запускать inference.

В production эту работу выполняет inference backend.

Inference backend — это программа, внутри процесса которой загружается и исполняется модель. Он принимает запросы, токенизирует текст, управляет памятью и KV-cache, объединяет запросы в batch, запускает вычисления на GPU и возвращает результат.

При этом одна и та же модель может работать через разные backend'ы.
Например Qwen можно запустить через vLLM, llama.cpp или SGLang.

Почему?

Потому что модель определяет, что считать, а backend — как это эффективно посчитать и обслужить запросы (и запомнить историю запросов, например)
Backend'ы отличаются поддерживаемыми архитектурами и форматами моделей, работой с VRAM, batching, KV-cache, quantization, parallelism и оптимизациями инференса.

Из тех, с которыми сталкивался:

vLLM — быстрый inference и высокий throughput. Хорошо подходит для production-нагрузки и множества параллельных запросов. При этом любит активно кушать доступную VRAM под модель и KV-cache.

llama.cpp — более гибкий вариант, особенно для квантованных GGUF-моделей. Может работать на GPU, CPU или одновременно использовать и то, и другое. Хороший выбор, когда железо ограничено и важнее экономия ресурсов, но имхо вообще не могу придумать кейсы, где скорость не важна. Если только для пэтпроект дома, на старенькой 3060 ti.

SGLang — лично пока не пробовал. По назначению это скорее конкурент vLLM: backend для быстрого production inference LLM и VLM.

В итоге схема такая (еще раз, но конкретнее):

Приложение
↓
GPUStack
↓
Worker
↓
Docker-контейнер
↓
vLLM / llama.cpp / SGLang
↓
Qwen / Llama / DeepSeek / ...
↓
GPU

И вот в этом для меня главное удобство GPUStack: прикладному сервису уже не нужно знать, на какой машине, на какой GPU и через какой backend сейчас работает модель.

Для приложения LLM превращается в обычный внешний сервис:
model + API key + endpoint

А вся работа с GPU, контейнерами и inference backend'ами остаётся внутри инфраструктурного слоя.




😐 всмысле параллельные прямые пересекаются? еще скажите, что у вас в треугольнике не 180°


😱 84% влажности в мск, вообще не терпимо, сомнительно, я бы сказал, поганенько


😁 Чет в голос

(Не, ну я бы его точно на собес позвал)


😕Мем смешной, ситуация страшная

Показано 20 последних публикаций.