AI и DIY,  Статьи

llama.cpp на двух компьютерах через прямое сетевое соединение

Для увеличения доступного объема VRAM при локальных AI-вычислениях можно использовать распределённый инференс больших моделей между двумя машинами, соединёнными патч-кордом напрямую (без свитча), через встроенный RPC-backend llama.cpp. Он специально создан для распараллеливания инференса одной нейросети на нескольких компьютерах (технология pooling VRAM — запуск моделей, которые не влезают в память одной видеокарты).

В режиме rpc одна машина выступает координатором (запускает llama-cli или llama-server), другая — вычислительным узлом (rpc-server), который просто исполняет операции над тензорами по сети. При этом слои модели распределяются между локальными GPU и удалёнными узлами.

Важно понимать ограничения такой «солянки»:

Это не настоящий tensor-parallelism с overlap вычислений и передачи данных, здесь каждый слой считается последовательно, и пока узел B не получит активации с узла A, он не начнёт работу. Поэтому сеть должна быть быстрой и с низкой задержкой, для этого лучше использовать прямой патч-корд 10GbE ,что близко к идеальному варианту для двух машин.

При отстуствии такового, а также для тестирования работы llama.cpp RPC можно задействовать тестовое соединение двух компьютеров через встроенные сетевые карты по обычному сетевому кабелю RJ45 (1GbE). Предварительная настройка работы через обычный гигабитный патч-корд позволит впоследствии быстро нарастить возможности кластера за счет добавления быстродейстующих 10G карт.

Как настроить совместную работу двух компьютеров, соединенных патч-кордом 1G в llama.cpp?

В первую очередь обеспечиваем надежное физическое соединение двух PC по качественному патч-корду (CAT5e/CAT6 или луше) через порты встроенных сетевых карт компьютеров напрямую, без свитча. Благодаря тому, что современные гигабитные карты (Intel I219, Realtek RTL811x и т.п.) поддерживают автоопределение кроссировки (Auto-MDIX), соединение по каналу связи, созданному таким образом, обычно работает без проблем.

Затем нужно настроить IP-адреса на обоих компьютерах для работы в отдельной подсети. Для этого:

На машине A (координатор) выполняем команду:

  ip link show

Получаем вывод, подобный такому:


1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000

link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00

2: enp0s31f6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq state UP mode DEFAULT group default qlen 1000

link/ether 88:88:88:88:35:35 brd ff:ff:ff:ff:ff:ff

altname enx888888883535

Отсюда берем имя интерфейса встроенной сетевой карты, в данном случае enp0s31f6.

Присваиваем этой карте статический сетевой адрес, например, так:

sudo ip addr add 192.168.10.1/24 dev enp0s31f6


sudo ip link set enp0s31f6 up

Для избежания конфликтов нельзя использовать адрес из основной локальной сети (например, 192.168.2.35).

На машине B (вычислительный узел) делаем то же самое:

  ip link show

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000

link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00

2: enp0s29u1u2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq state UP mode DEFAULT group default qlen 1000

link/ether 00:e0:4c:78:27:83 brd ff:ff:ff:ff:ff:ff
sudo ip addr add 192.168.10.2/24 dev  enp0s29u1u2

sudo ip link set enp0s29u1u2 up

На главном компьютере (A) выполняем команду:

  ip link show enp0s31f6

В итоге должно быть state UP, и в логе ядра, например:

  dmesg | grep -i "link is up"

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

С машины A

  ping -c 4 192.168.10.2

а также:

sudo ethtool enp0s31f6 | grep -E «Speed|Link detected»

Speed: 1000Mb/s

Link detected: yes

Такой ответ означает, что сеть физически работает.

Если не пингуется, проблема может быть в файрволе, который блокирует ICMP. Временно для теста можно разрешить соединение командой:

  sudo iptables -I INPUT -s 192.168.10.0/24 -j ACCEPT

Замеряем скорость связи на компьютере B (сервер):

  sudo emerge --ask net-misc/iperf
  iperf3 -s

На машине A (клиент):

  iperf3 -c 192.168.10.2 -t 10

На гигабитном соединении максимальная скорость не может быть более примерно 940 Mbit/s.

После перезагрузки компьютеров заданные IP-адреса будут пропадать так как конфигурация через ip addr add временная.

Для постоянной настройки в linux на OpenRC прописываем в /etc/conf.d/net нужные адреса, например:

  sudo nano /etc/conf.d/net 
# /etc/conf.d/net

config_enp0s31f6="192.168.10.1/24"
  sudo rc-update add net.enp0s31f6 default

Сборка llama.cpp под разную конфигурацию компьютеров

Далее собираем llama.cpp с RPC (на обеих машинах с флагом -DGGML_RPC=ON):

  git clone https://github.com/ggerganov/llama.cpp && cd llama.cpp

На компьютере с видеокартами Nvidia — с поддержкой CUDA + NCCL, для Nvidia Tesla V100 (Compute Capability 7.0):

  cmake -B build -DCMAKE_BUILD_TYPE=Release -DGGML_CUDA=ON -DGGML_RPC=ON -DCMAKE_CUDA_ARCHITECTURES="70" -DCMAKE_C_COMPILER=gcc-14 -DCMAKE_CXX_COMPILER=g++-14 -DCMAKE_C_FLAGS="-march=native" -DCMAKE_CXX_FLAGS="-march=native" && cmake --build build -j$(nproc)

На компьютере без GPU (инференс только на CPU) командой:

  cmake -B build -DCMAKE_BUILD_TYPE=Release -DGGML_RPC=ON -DCMAKE_C_FLAGS="-march=native" -DCMAKE_CXX_FLAGS="-march=native" && cmake --build build -j$(nproc)

На компьютере с видеокартами AMD с поддержкой Vulkan:

  cmake -B build -DCMAKE_BUILD_TYPE=Release -DGGML_VULKAN=ON -DGGML_RPC=ON -DCMAKE_C_FLAGS="-march=native" -DCMAKE_CXX_FLAGS="-march=native" && cmake --build build -j$(nproc)

Запуск llama.cpp на двух компьютерах, соединенных напрямую

Запускаем RPC-узел на машине B (из каталога, в котором находятся файлы llama.cpp), например, так:

  ./rpc-server --host 0.0.0.0 --port 50052

Получаем вывод:

  Starting RPC server on 0.0.0.0:50052

После этого запускаем координатор с подключением узла (машина A) с AI-моделью, для теста можно использовать маленькую, например, так:


./llama-server \

-m ~/models/small-model-Q4_K_M.gguf \

--host 127.0.0.1 \

--port 8080 \

--rpc 192.168.10.2:50052 \

-ngl -1 \

-c 8192

# --host 127.0.0.1 на координаторе можно заменить на 0.0.0.0, если нужен доступ по сети.

где

  -c 8192 или больше — размер контекста.

Для нескольких RPC-узлов используем синтаксис:

  --rpc ip1:port1,ip2:port2

На компьютере B (rpc-сервер) используем в качестве основной команду:

  ./rpc-server  --host 0.0.0.0  --port 50052  -c

Для ограничения памяти можно добавить аргумент m, например, до 24GB:

  ./rpc-server  --host 0.0.0.0  --port 50052  -c -m 24576

В логе основной машины должна должна появиться строка с распределением слоёв между локальным GPU и удалённым узлом:

  load_tensors: layer split: [local: X layers] [RPC 192.168.10.2:50052: Y layers]

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

  --tensor-split 5,5

Заключение

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

  • физическое соединение между компьютерами работает и держится стабильно;
  • обе сборки llama.cpp с GGML_RPC=ON корректно компилируются и общаются друг с другом;
  • проверить в логах llama.cpp, что распределение слоёв между машинами реально происходит.

В будущем это позволит быстро перейти на более совершенное сетевое оборудование 10GbE, или хотя бы 2.5-5GbE просто заменой IP-настроек на тех же интерфейсах, без изменений в командах llama.cpp.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *