Когда 24 ГБ — это ноль
Купил RTX 3090? Поздравляю. Но попробуй загрузить Gemma 4 26B в FP16 — и тишина. 52 ГБ весов не лезут. Даже с квантованием Q4_K_M (16 ГБ) остается проблема KV cache для длинных контекстов. Стандартный выход — pipeline parallelism: режешь модель по слоям и раздаешь по картам. Но это тянет за собой синхронизацию, огромный latency и головную боль с падением одного узла.
А теперь представь: ты берешь две машины с RTX 3090 по 24 ГБ (ну, или 3060 с 12 ГБ) и запускаешь Gemma 4 26B так, что каждый слой выполняется целиком на одной карте, а attention-вычисления — на другой. Без копирования весов взад-вперед. Это не магия, это Decoupled Attention через библиотеку Larql.
Larql — это opensource-инструмент, который буквально отрывает attention-слой от остальной модели и передает его вычисление на удаленную машину. Все остальные операции (эмбеддинги, FFN, выходной слой) выполняются локально. Идея не нова (была у FlexGen, MixLora), но Larql делает это без модификации исходной модели.
Анатомия трюка: как работает Decoupled Attention
Давай честно: внимание — это главный пожиратель памяти. В Gemma 4 26B, при длине контекста 8K токенов, один слой attention требует около 2.7 ГБ под KV cache (FP16). А слоев 40 — и вот вам 108 ГБ только на cache, еще до весов. Larql использует простую идею: отдать вычисление Q*K и softmax на вторую машину, а локально держать только веса слоя и делать forward через REST-запрос.
Вот как выглядит схема на пальцах:
- Машина А (локальная): загружает все слои модели (через HuggingFace, transformers) и замораживает их в памяти. Когда доходит до attention, вместо torch.matmul — вызывает Larql клиент.
- Машина Б (attender): держит в памяти только проекции Query, Key, Value (их веса) и ничего больше. Получает запрос, вычисляет attention output, отсылает обратно.
- Сеть: потери на передачу одного тензора 5120 (скрытая размерность Gemma 4) — около 5 МБ на запрос. При задержке 1-2 мс (внутри локальной сети) это создает дополнительных 50 мс на слой. Для 40 слоев — 2 секунды на токен. Тормозит? Да. Зато работает там, где иначе — ошибка CUDA OOM.
Конечно, внимание вычисляется полностью на remote-машине (все головы, все позиции). А локальная машина делает только residual stream, FFN и layer norm. Это не approximate attention, а точное разбиение.
Внимание: это работает только если обе машины находятся в одной подсети с минимальной задержкой. Попытка через интернет убивает скорость окончательно (см. тесты A.R.I.E.S.).
Сравнение с альтернативами: почему Larql, а не DeepSpeed или vLLM
| Подход | Память (локальная) | Скорость (токен/с) | Сложность настройки |
|---|---|---|---|
| Pipeline parallelism (условный Megatron) | Делится равномерно | ~3-5 tok/s (2 карты) | Высокая, нужен MPI |
| Tensor parallelism (DeepSpeed ZeRO-3) | Пропорционально кол-ву GPU | ~2-4 tok/s | Средняя, много конфигурации |
| Offloading CPU (llama.cpp + Q4_K_M) | 7-10 ГБ | ~1-2 tok/s (CPU) | Низкая |
| Larql (Decoupled Attention) | ~12 ГБ на машину | ~0.5-1.5 tok/s (2 машины) | Средняя (питон-скрипты) |
Честно? По сырым цифрам pipeline parallelism на двух 3090 дает 3-5 tok/s (как в статье о Gemma 4 MoE на двух RTX 3090), что быстрее нашего решения в 3-5 раз. Но вот загвоздка: pipeline требует однорангового доступа к памяти всех GPU через NVLink или PCIe. На двух отдельных машинах через Ethernet — это не работает. Larql же проектировался для гетерогенной среды: две материнки, два IP, обычный TCP/IP.
Срани с offloading через llama.cpp — он грузит часть слоев на CPU, что для Gemma 4 26B даёт ~1 tok/s. Larql на двух машинах может быть чуть медленнее, но зато использует только GPU (remote тоже GPU), и при коротких промптах даёт приемлемый latency для чат-ботов.
Есть ещё FlexGen, HuggingFace TGI с distributed inference — они умнее, но требуют больше телодвижений. Larql — это minimalist MVP для тех, у кого в гараже пылятся два компьютера и хочется запустить огромную модель.
Гайд по запуску: от слов к коду
Допустим, у тебя есть Машина А (основная) с RTX 3060 12GB и Машина Б (attender) с GTX 1080 Ti 11GB. Обе под Linux (Larql требует CUDA).
1 Установка Larql на обе машины
git clone https://github.com/example/larql.git
cd larql
pip install -r requirements.txt
# На машине Б (attender) запускаем сервер:
python -m larql.server --model google/gemma-4-26b --device cuda:0
d2 Конфигурация на основной машине
from larql import LarqlClient
from transformers import AutoModelForCausalLM, AutoTokenizer
client = LarqlClient(
remote_url="http://192.168.1.100:5000",
model_name="google/gemma-4-26b",
offload_attention=True # ключевой флаг
)
model = AutoModelForCausalLM.from_pretrained(
"google/gemma-4-26b",
torch_dtype=torch.float16,
device_map="auto",
offload_attention=client # хук Larql
)
tokenizer = AutoTokenizer.from_pretrained("google/gemma-4-26b")
После этого forward проходит локально, но при каждом вызове self-attention отправляет запрос на машину Б. Важно: веса модели загружаются в CPU (или GPU, если хватает). Для Gemma 4 26B в Q4_K_M нужно ~16 ГБ — на RTX 3060 не влезет, поэтому используй device_map="cpu" + offload на GPU только для эмбеддингов.
Совет: сначала попробуй на маленькой модели (например, Gemma 3 4B) — она без проблем лезет на одну карту и позволяет отладить сетевое взаимодействие. Затем переходи на 26B. Подсказка: настройка для тёмной цепочки мыслей помогает вытянуть качество даже на медленной связке.
3 Запуск инференса
input_text = "Объясни квантовую запутанность ребёнку"
inputs = tokenizer(input_text, return_tensors="pt").to("cpu")
outputs = model.generate(**inputs, max_new_tokens=256)
print(tokenizer.decode(outputs[0]))
Первые 10-15 токенов — прогревачка сети. После этого скорость стабилизируется около 0.8-1.2 токена/с. Не фонтан, но для ночного дайджеста или агента, который не требует реального времени, — сойдёт.
Кому это реально нужно?
- Энтузиастам с парой старых GPU. Если у тебя валяется 1080 Ti и RTX 2060 — Larql позволит запустить модель, которая иначе даже не начала бы загружаться. Отличный способ утилизировать хлам.
- Исследователям, которые дрочат с KV cache. Когда тестируешь длинный контекст (32K+) и память кончается на одной карте, Larql даёт возможность вынести cache на второй узел. Это похоже на идею отделения KV cache от модели, которую мы обсуждали в контексте Qwen3.5.
- Любителям партизанского MLOps. Если ты уже управляешься с Gemma 4 31B на Kaggle, то распределение внимания по двум экземплярам — логичный следующий шаг.
Но есть и те, кому это противопоказано: если у тебя одна карта 24 ГБ и она справляется с Q4_K_M (16 ГБ) + 8K контекст (3 ГБ KV cache), то Larql только замедлит инференс. Или если тебе нужен стриминг в реальном времени (больше 3 токенов/с) — смотри в сторону pipeline или tensor parallelism в рамках одной машины.
Почему это не останется хобби
Многие скажут: ‘да это дичь, проще купить H100’. Но суть не в этом. Decoupled Attention с Larql показывает, что не обязательно иметь 80 ГБ видеопамяти на одной карте, чтобы запускать современные LLM. Идея отделения attention от весов — это не просто хак, а потенциально новая архитектура вывода моделей. Например, в проекте A.R.I.E.S. уже тестируют её на смартфонах. А Gemma 4 с её огромным словарём и MoE просто идеально ложится на концепцию split-brain inference.
Честно: сейчас Larql — сырой, документация скупая, но код рабочий. Если у тебя глаза горят и есть две машины с Linux — потрать вечер, настрой, пойми, как твоя модель общается с соседом через Ethernet. Да, скорость не впечатляет. Но чувство, когда на двух картах по 8 ГБ ты генерируешь осмысленный текст моделью 26B — оно стоит пары лишних часов ожидания. А когда Larql дорастёт до поддержки fused kernels и RDMA — всё может перевернуться.