Много нас, а GPU один. Как делиться?

1bdf473eb611323b1d489621fd002c01.png

Краткое содержание

Нет, этот пост не про то, как на простом ноуте без NVIDIA гонять Stable Diffusion с вполне вменяемой скоростью.

Да, этот пост про то, как на простом ноуте без NVIDIA гонять Stable Diffusion с вполне вменяемой скоростью.

Но только если карточка у вас все-таки где-то есть. Пост не про халяву :)

Часто задают вопрос: «У нас маленькое агентство, как бы сделать, чтобы 4 человека работали на одной видеокарте?». То же самое относится и к «мама-папа-я — дружная семья, и все мы любим Stable Diffusion».

Это становится еще более актуальным в связи с появившимися сложностями при попытках бесплатно гонять SD в Google Colab (а Kaggle и другие заменители не такие щедрые).

В этом посте я опишу несколько вариантов «совместной работы с одним GPU», их плюсы и минусы. В основном, на примере Stable Diffusion, хотя Vicuna я тоже гонял параллельно.

Оборудование и ОС

Итак, есть некая машина с хорошей видеокартой. Я экспериментировал на внешней RTX 3090 (Gigabyte AORUS BOX) и Intel NUC 9. Буду называть эту машинку «GPU сервер» или просто «сервер».

К сожалению, я не смог расшарить эту карту в ESXi. Это стандартно делается только для профессиональных видеокарт и требует дополнительного лицензирования. Для Proxmox встретился workaround, но не для Ampere карточек (2060 можно, а 3090 не получится). Так что я решил обойтись без виртуализации.

Больше всего материалов, как установить Stable Diffusion и прочие прибамбасы типа Kohya_ss именно на Windows. Есть прекрасная portable сборка. Для Vicuna тоже есть куча скриптов на powershell. Хоть сейчас с драйверами для NVIDIA под условной Убунтой ситуация намного лучше, чем много лет назад, я решил не заморачиваться и установить Windows.

Сначала я установил Windows Server 2019. Обнаружил, что под NUC 9 там с драйверами не очень хорошо. В итоге откатился на самый обычный Windows 10 Pro.

Headless

Я хотел, чтобы к этому серверу каждый член семьи мог подключиться со своего ноутбука. Т.е. он стоит себе и работает. Либо любой может подойти, нажать кнопку включения, но работать не с него, а со своего ноута. (Всякие навороты типа дистанционно включить умную розетку я опускаю, ибо это вкусовщина и выходит за рамки этого поста).

Иными словами — сервер должен уметь после включения обслуживать дистанционные запросы без логина. И тут возникла сложность.

Все настроил с клавиатурой и монитором, с соседнего ноута подключился через Remote Access — все хорошо. Выключил, убрал под стол, включил, подключился к рабочему столу, а карточки-то нет. Точнее она видна, но не работает. Достаю сервер, подключаю монитор и клавиатуру — все запускается суперски.

Оказалось, что хотя в настройках Thunderbolt (карточка-то у меня внешняя) я устройство авторизовал и позволил ему всегда подключаться, в Windows есть дополнительная защита — Kernel DMA Protection. Если полноценно залогинился — все хорошо (поэтому с монитором и клавиатурой все работало). Но если просто включил сервер, карточка будет видна в диспетчере устройств, но не будет работать полноценно.

Пришлось эту защиту отключать (Allow all вместо Only while Logged in)

Web-интерфейс через LAN

Тут все просто, только небольшие особенности.

Поскольку мы хотим подключаться по сети, к параметрам командной строки нужно добавить --listen. Если мы в LAN, работать через публичный адрес (--share) было бы странно. А если нужен доступ издалека, я предпочитаю ZeroTier.

Теперь сервер слушает не только на localhost, и к нему можно обратиться стандартно (http://192.168.X.X:78XX).

Только вот установить расширения вы не сможете. Из соображений безопасности: чтобы подключающиеся удаленно не могли установить «нехорошее» и получить избыточный доступ к вашему серверу. Либо убирать --listen, переключать на 127.0.0.0, устанавливать расширения и возвращать все обратно. Либо, если доверяете другим своим пользователям, есть специальный ключик --enable-insecure-extension-access.

Для portable сборки примерно так:

set COMMANDLINE_ARGS= --api --listen --port 78XX --theme dark --enable-insecure-extension-access

(оптимизации типа --opt-sdp-attention или --xformers не указываю, это индивидуальное).

Отдельно укажу нюанс для желающих подключаться с авторизацией. Да, можно указать --listen --share --gradio-auth user:password. И при подключении браузером вас действительно попросят ввести пароль. Что интересно, плагин для фотошопа (в моем случае StableArt), при этом подключится легко и непринужденно, не спрашивая у вас пароля. Так же может подключиться и кто-то еще.

А потому что не надо забывать требовать пароль и для api (--api-auth)!

Впрочем, плагин StableArt у меня после добавления этого ключика пароль спросить не сумел и в таком виде работать отказался. И это еще одна причина, почему я не использую --share, а подключаюсь как бы по локальной сети (Wireguard, ZeroTier…).

Теперь собственно к делу (генерации картинок).

Варианты совместной работы

1.     Всем дать доступ к Web интерфейсу

Вариант самый простой. И, если вы не работаете одновременно, имеет право на жизнь. Но вот если несколько человек попробуют что-то генерировать одновременно, возможны глюки. Web интерфейс AUTOMATIC1111 не рассчитан на такое.

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

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

2.     Запустить несколько инстансов SD

На мой взгляд, оптимальный вариант. Просто и удобно.

Взяли portable сборку, установили в разные директории. Для тяжеловесных файлов типа моделей и директорий с ними сделали ссылки, чтобы не хранить гигабайты в нескольких экземплярах. И запустили независимо на разных портах.

Каждый пользователь может себе собственные параметры настраивать, собственные расширения устанавливать. Его картинки будут падать в его собственную папку. И именно ее он может смотреть через расширение sd-webui-infinite-image-browsing или настроить для просмотра в breadboard-web в своем браузере.

Автоматический запуск

Первый вариант автоматически стартовать webui-user.bat — это превратить его в сервис с помощью, например, с помощью «NSSM is a service helper program similar to srvany and cygrunsrv». У меня именно так и работает. В описании каждого сервиса я указываю запуск не под LocalSystem, а под конкретным пользователем (.\WinUser). Нужно только проверить, как все запускается под этим пользователем, зайдя под ним по RDP. Иногда при запуске webui-user.bat может ругаться, что extensions под другим пользователем устанавливались, и подсказывать, какую команду выполнить, чтобы это поправить.

Запуск удаленно вручную

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

Если такое требуется — вместо сервиса можно позволить пользователям подключаться к консоли через ssh и запускать искомый батник. Нет проблем, что к Win10 невозможно подключиться по RDP нескольким пользователям, каждый может видеть логи своего инстанса. Да, в Win10 можно штатными методами добавить OpenSSH server, а не только клиента.

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

Можно, конечно, написать дополнительный батник с tasklist /fi "USERNAME eq WinUser" /v | find "python" и taskkill (добавить такие строчки в webui-user.bat), но я до такого пока не дошел.

Может быть есть что-то «родное виндовое» (winrm/psremoting, psexec…), что окажется проще для таких целей.

Отмечу, что конфликтов не встречал. Если некто запустит генерацию кучи картинок через XYZ, остальные продолжат работать. Если видеокарта позволит, конечно (имеет достаточно VRAM). Даже при обучении LoRa я мог продолжать генерировать картинки (благо в 3090 целых 24GB).

И это относится не только к Stable Diffusion. Параллельно я запускал Vicuna.

Вот эту картинку я ваял, пока другой человек болтал с Викуной. Картинки генерировались параллельно с текстовым чатом. Но видеопамяти Викуна требует очень много, это было просто «попробовать».

3.     GPU-over-IP

Пожалуй, самый навороченный способ. Речь о том, что на GPU-сервере не запускается «клиентского» софта, а только некая серверная часть. Всякие Stable Diffusion устанавливаются на пользовательских ноутбуках. Но запускаются они через клиентскую часть, которая перехватывает обращения к GPU и перенаправляет их на сервер.

Т.е. RAM, CPU используются ноутбучные. Нет проблем с консольными сообщениями, с безопасностью расширений — все это находится локально у пользователя. И только обращения к GPU пересылаются по сети.

Есть кеширование, не надо бояться, что многогигабайтная модель будет по сети пересылаться каждый раз. Хотя переключение модели на совсем новую заставит подождать первую генерацию с ней. Может даже сначала ошибка выскочит, пока гигабайты через слабенький WiFi протискиваются.

Это делается через https://github.com/Juice-Labs/Juice-Labs/wiki

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

По скорости — на КДПВ в зависимости от batch size скорость была от 3.25 до 10.78 итераций в секунду. После апгрейда до torch:2.0.0+cu118 поднялась до 5.66. Впрочем, когда я изначально подключал eGPU непосредственно к этому ноуту, скорость была тоже не выше 3.5 it/s. Помню, я еще сильно испугался, как это 3090 так медленно генерирует. Просто у этого ноута есть ряд проблем, и частота понижена.

Что касается меня — я остановился на способе №2. Несколько SD инстансов на разных портах. При этом напрягала невозможность подключиться по RDP к Win10 нескольким пользователям одновременно для работы с SD в Photoshop через плагин, но с появлением расширения Photopea и эта проблема исчезла.

А у вас было желание совместно использовать GPU?

Как решали? Буду рад услышать ваш опыт.

© Habrahabr.ru