В первой части статьи я описывал свой опыт использования локальных моделей при разработке кода. В частности, столкнулся с тем, что без видеокарты скорость работы ollama была достаточно низкой. Далее постараюсь рассказать про техническую часть подключения внешней видеокарты к ноутбуку работающему на Linux.
Информации по теме egpu (external graphics processing unit) не так много. И была большая вероятность, что на некоторых моделях ноутбука адаптеры gpu могут не заработать. Поэтому я пошел по самому бюджетному варианту и заказал адаптер на китайском маркетплейсе.
«Кабель PCIe 3,0 4,0 X16 к TB3 eGPU адаптер Thunderbolt 3 графическая карта для ноутбука внешний адаптер платы док-станция для ITX STX NUC», — по описанию непонятно, но вроде бы то, что нужно. По факту адаптер на конце имел разъем M2. Этот разъем — один из вариантов PCI-E, используется в основном в ноутбуках для подключения SSD (NVMe), либо другой периферии.
Немного расстроившись, что это не кабель Thunderbolt, я залез в спецификацию ноутбука и обнаружил, что кроме основного слота M2 (с подключенным накопителем SSD/NVMe), у меня есть дополнительный слот для подключения GPRS-модема.
Раскурочив ноутбук, я обнаружил сам слот, правда модема там не оказалось, хотя разъем под антенну и сим-карту подведены.
Радость моя была недолгой — производитель ноутбука позаботился о том, чтобы я не подключал к этому порту что попало.
«Unauthorized network card is plugged in — Power off and remove the network card. System is halted», — так Lenovo встроило в BIOS белый список оборудования. И любые другие девайсы, кроме модемов от Lenovo, просто блокируются. Да, есть альтернативные прошивки BIOS, чтобы это убрать — собственно, как и вероятность превратить ноутбук в красивый черный кирпич.
Я стал изучать как подключить M2 к ноутбуку альтернативным способом, через USB 4 или Thunderbolt — даже задал вопрос продавцу адаптера. Но тот ответил, что «переходники» отдельно не продаются. В одном из видео по этой теме я увидел, как подключали похожее устройство через обычный адаптер для накопителя NVMe. Мне это кажется странным: где блочное устройство-накопитель SSD, а где видеокарта. В любом случае, решил попробовать. Предположил (и это оказалось верно), что нужен быстрый адаптер с пропускной способность 40 Гбит/с. Приобрел на Ozon адаптер от JEYI, привлекла в нем пропускная способность, цена и цельноалюминиевый корпус.
Также я заказал новую видеокарту. Выбирал долго и в итоге остановился на одном из самых холодных и тихих вариантов — NVidia GeForce 3060. Для LLM-моделей требуется много видеопамяти. У этой видеокарты 12 ГБ памяти и достаточно производительный видеочип — купил так же на Ozon со скидкой по уценке.
Всё подключил — блок питания, адаптер egpu, адаптер M2-NVMe, Thunderbolt — и физически всё заработало. Вентилятор на блоке питания включился, индикаторы на видеоплате и на адаптере загорелись! Примерно так оно выглядело в сборе:
Для того, чтобы появилось ещё и изображение, нужно проделать серию манипуляций:
Включить туннелирование в BIOS. Дело в том, что обычно проброс PCI-устройств через Thunderbolt запрещён в целях безопасности. В зависимости от ноутбука, настройка может быть в разных местах — в моем случае в разделе config.
Установить драйверы видеокарты. В Linux это делается через Additional Drivers, и я установил последний стабильный драйвер:
По умолчанию для Nvidia в Linux (по-крайней мере, в Ubuntu) внешние видеокарты отключены в целях безопасности. После установки драйверов необходимо в файле /usr/share/X11/xorg.conf.d/10-nvidia.conf добавить Option "AllowExternalGpus" "true". Чтобы получилось примерно следующее:
Словами не передать, сколько гуглений мне это стоило, но после этого всё заработало и изображение появилось! А в стандартной программе настройки NVidia появилась вся информация о видеокарте и PCI-шине.
Эксплуатация устройства показала, что не всё так хорошо. В совершенно неопределенные отрезки времени ноутбук стал зависать, причём сложно было сказать, связано это с нагрузкой, подключением других устройств или чем-то ещё. Происходило это примерно раз в час, иногда через 15 минут после включения — в общем, работать в такой обстановке стало крайне затруднительно.
После долгих поисков я нашел ошибку, которой предшествовало зависание. В логах /var/log/syslog можно было увидеть вот эту строчку и затем дамп всей системы:
NVRM: Xid (PCI:0000:22:00): 79, pid='<unknown>', name=<unknown>, GPU has fallen off the bus.
На одном из форумов нашел хороший вопрос: «Какого чёрта мой графический ускоритель выпал из автобуса?» Если серьезно, то видеокарта перестала отвечать по шине данных. Ошибка 79 — довольно базовая, и к ней может приводить множество причин. Как оказалось, перегрев. В решении помог пирометр. Перед зависанием температура в самой видеокарте и центральном процессоре оставалась в пределах 50°, но в адаптере NVMe поднималась аж до 75° (и это только на корпусе). Дальнейшие изучения показали, что чип, отвечающий за передачу данных, asm2464, — огонь по скорости и, к сожалению, по температуре.
В результате я:
сменил термопасту между чипом asm2464 и корпусом,
установил дополнительный радиатор на адаптер,
разместил сам адаптер на блоке питания (используя детский конструктор).
Идея была в том, что вентилятор в блоке питания всё равно работает, и будет дополнительно охлаждать адаптер снизу, а радиатор сверху будет также эффективно отводить тепло. Радиатор выбирал по виду — мой похож на корабельный двигатель.
Температура адаптера упала до 30-32°, и проблема с зависанием ушла.
Итоги по технической части:
Производительность ноутбука стала выше просто по ощущениям. Скорость переключения между приложениями, количество вкладок в Chrome, отрисовка в Grafana и тп. Замеры в реальной нагрузке тоже показали снижение нагрузки на центральный процессор и понижение его температуры.
Ноутбук сохранил свою мобильность: устройство можно отключить, вынуть кабель Thunderbolt — и после перезагрузки снова работать как на обычном ноутбуке. Для меня это важно, так как иногда требуется поработать из офиса или на даче. Но отключить в горячем режиме не получится: PCI — не USB, и требует подключения модуля ядра.
Решение получилось достаточно бюджетным (если сравнивать с готовыми egpu), порядок цифр:
адаптер egpu + адаптер nvme = 15 тыс. руб.
кулер NVMe — 700 руб.
детали детского конструктора — 1 конфета ребенку
видеокарта — 25 тыс. руб.
источник питания от старого компьютера
Подключение внешней видеокарты для ИИ
Для того, чтобы наш сервис Ollama увидел видеокарту, требуется доустановить ещё несколько пакетов.
CUDA — для использования видеокарты для расчёта данных. Если версия вашего драйвера Nvidia совпадает с версией CUDA, всё пройдет без проблем. Если нет — предстоит небольшое приключение по обновлению сначала драйвера, а потом и CUDA.
sudo apt install nvidia-cuda-toolkit
И сразу для мониторинга:
sudo apt install nvtop
Дополнение для Docker, умение работы с графическими ускорителями:
sudo apt-get install nvidia-docker2
Можно проверить, что все хорошо, запустив Nvidia-SMI (информация о видеокарте) непосредственно в Docker:
sudo docker run --rm --runtime=nvidia --gpus all ubuntu nvidia-smi
Корпус устройства
Поработав немного и насмотревшись на внутренний внешний вид моей видеокарты, я решил, что надо придать устройству некую форму. Хлипкость конструкции меня пугала. Например, в кабеле M2 море контактов, а их ширина не видна невооруженным глазом, то же самое можно сказать и про саму видеокарту. В общем, хотелось, чтобы хотя бы визуально всё это выглядело надёжней.
В домашнем хозяйстве была найдена неиспользованная стальная полка для ванной, чудесным образом туда всё уместилось. Немного доработал её болгаркой и сверлом — получилась импровизированная рама (аналог рамного автомобиля).
Далее раму нескучно покрасил:
Верхнюю часть спроектировал в Inkscape, вырезал из акрила лазерным резаком, склеил и добавил кусок светодиодной ленты от китайского кулера:
Дети попросили добавить наклейки — как им можно возразить?
И финальный вид устройства:
Визуально и технически результатом я доволен, мой субъективный взгляд радуется. Ноутбук стал умнее и красивее — ну и я стараюсь не отставать, тоже учусь работать с генеративными моделями.