Технологии

Две видеокарты под одну модель: когда это работает

Разделение по слоям и тензорный параллелизм — это разные вещи с разными последствиями. Для одного пользователя вторая карта даёт объём памяти, а не скорость.

Логика кажется безупречной: одна карта даёт 24 гигабайта и тридцать токенов в секунду, значит две дадут 48 гигабайт и шестьдесят токенов в секунду. Первая половина верна. Вторая — нет, и разочарование от этого открытия обычно наступает уже после покупки.

#Короткий ответ

Вторая видеокарта складывает объём памяти и почти не складывает скорость — если вы один пользователь и работаете в режиме диалога.

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

Прирост скорости от второй карты появляется в другом сценарии: когда запросов много и они идут одновременно. Тогда карты работают параллельно на разных запросах, и пропускная способность системы действительно удваивается.

#Как это устроено

Есть два принципиально разных способа разложить модель по нескольким устройствам.

#Режим первый: разделение по слоям

Запрос → [ Карта 1: слои 1–20 ] → [ Карта 2: слои 21–40 ] → Ответ
              работает                   ждёт
                 ↓                         ↓
               ждёт                     работает

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

Это режим по умолчанию в llama.cpp (-sm layer) и в Ollama. Требования к связи между картами минимальные: передаётся один небольшой вектор состояния на слой-границу, а не гигабайты. Поэтому работает он даже на слабых линиях PCIe и с картами разных моделей.

Что он даёт: суммарный объём памяти. Что не даёт: скорость.

#Режим второй: тензорный параллелизм

Запрос → [ Карта 1: половина каждого тензора ] ─┐
         [ Карта 2: половина каждого тензора ] ─┴→ синхронизация → Ответ
                    обе работают одновременно

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

Здесь прирост скорости возможен — но он ограничен синхронизацией. После каждого слоя карты обмениваются данными через шину PCIe, у которой пропускная способность в десятки раз ниже, чем у видеопамяти. На линии PCIe 4.0 x16 это порядка 32 ГБ/с против почти тысячи внутри карты. Синхронизация съедает значительную часть выигрыша, и удвоения скорости не получается почти никогда.

Этот режим есть в llama.cpp (-sm row) и как основной подход в серверных движках. Его эффективность заметно выше при быстрой связи между картами — например, через прямой мост NVLink на картах, которые его поддерживают.

#Что даёт и чего не даёт

Что вы получаете Разделение по слоям Тензорный параллелизм
Суммарный объём памяти ✓ ✓
Ускорение генерации для одного запроса ✗ частично
Ускорение при многих одновременных запросах ✓ ✓
Работа с картами разных моделей ✓ ✗ или с потерями
Требования к линии PCIe низкие высокие
Простота настройки одна команда подбор параметров

Что здесь смотреть: первая строка заполнена в обоих столбцах, вторая — почти нет. Это и есть суть вопроса. Вторая карта решает задачу «модель не влезает», а не задачу «модель отвечает медленно».

Отсюда практическое следствие, которое экономит деньги: если ваша модель уже помещается в одну карту, вторая карта того же класса не ускорит её. Полезнее потратить те же деньги на одну карту большего объёма.

#Что из этого следует на практике

Настройка в llama.cpp. Режим задаётся флагом, пропорции — отдельно:

./build/bin/llama-cli -m models/model-q4_k_m.gguf -ngl 99 -sm layer -ts 3,1 -mg 0

Здесь -sm layer — разделение по слоям, -ts 3,1 — три четверти слоёв на первую карту и четверть на вторую (нужно, когда карты разного объёма), -mg 0 — какая карта считается главной. Разбор остальных флагов — в гайде по llama.cpp без магии.

Карты не обязаны быть одинаковыми — в режиме по слоям. Можно поставить рядом карты разных поколений и объёмов, распределив нагрузку пропорционально. В тензорном режиме это работает плохо: скорость определяется самой медленной картой.

Считайте суммарную память честно. Две карты по 12 гигабайт — это не 24 доступных: на каждой остаются накладные расходы, а модель делится не идеально ровно. Планируйте с запасом. Методика расчёта — в материале о том, сколько нужно VRAM для локальной LLM.

Проверьте материнскую плату до покупки. Второй слот PCIe часто работает на меньшем числе линий, а физически карты могут не поместиться рядом. Плюс питание: две карты — это удвоенное потребление и требования к блоку.

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

#Где интуиция подводит

«Две карты по 12 гигабайт равны одной на 24». По объёму примерно да, по скорости — нет: одна карта на 24 гигабайта будет быстрее, потому что не тратит время на передачу состояния между устройствами. Если выбор стоит именно так, одна карта предпочтительнее почти всегда. Сравнение вариантов — в разборе того, какую видеокарту взять под локальные LLM.

«Тензорный параллелизм всегда быстрее». Не всегда. На медленной связи между картами он может оказаться медленнее простого разделения по слоям — синхронизация после каждого слоя съедает больше, чем даёт параллельность. Проверять нужно замером обоих режимов.

«Вторая карта нужна, чтобы модель работала быстрее». Она нужна, чтобы модель работала вообще, если не влезает. Это разные задачи, и подмена одной другой — главный источник разочарования.

«Старую карту можно оставить в системе, хуже не будет». Может стать хуже: движок способен выбрать её как одно из устройств и раскидать слои так, что медленная карта станет узким местом. Ограничивайте видимость устройств явно.

«Это дешевле, чем одна большая карта». Иногда да по цене карт, но считать надо систему целиком: блок питания, корпус, охлаждение, шум и электричество. Полный подсчёт для вторичного рынка — в материале о б/у видеокартах под LLM.

#Частые вопросы

#Даст ли вторая видеокарта прирост скорости?

Для одного пользователя в режиме диалога — почти нет. Она даёт суммарный объём памяти, позволяя запустить модель, которая не помещалась. Прирост скорости появляется при одновременных запросах или, частично, в режиме тензорного параллелизма с быстрой связью между картами.

#Можно ли поставить карты разных производителей?

В пределах одного бэкенда — обычно да. Смешивать NVIDIA и AMD в одной модели на практике не работает: движок использует один бэкенд за раз. Смешивать разные карты одного производителя в режиме разделения по слоям можно.

Для разделения по слоям — нет, обмен минимальный. Для тензорного параллелизма быстрая связь между картами существенно влияет на результат, и там он полезен. Поддерживают его не все карты, и на свежих поколениях потребительского сегмента его нет.

#Как понять, какой режим сейчас используется?

В llama.cpp — по флагу -sm, значение по умолчанию layer. В логе запуска видно распределение слоёв по устройствам. Замерьте оба режима на своей связке: разница может оказаться в любую сторону.

#Хватит ли обычного блока питания на две карты?

Считайте по суммарному теплопакету плюс запас на процессор и остальную систему. Две карты по 250–350 ватт требуют блока другого класса, чем одна, и пиковые всплески потребления у видеокарт превышают номинал.

#Три карты и больше имеют смысл?

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

Хотите ИИ, который помнит вас?

Persona держит контекст между чатами и работает на вашем железе — если развернуть её у себя и подключить локальную модель.

Создать аккаунт