В первой части статьи я описывал свой опыт использования локальных моделей при разработке кода. В частности, столкнулся с тем, что без видеокарты скорость работы 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 — и физически всё заработало. Вентилятор на блоке питания включился, индикаторы на видеоплате и на адаптере загорелись! Примерно так оно выглядело в сборе:

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

  1. Включить туннелирование в BIOS. Дело в том, что обычно проброс PCI-устройств через Thunderbolt запрещён в целях безопасности. В зависимости от ноутбука, настройка может быть в разных местах — в моем случае в разделе config.

  1. Установить драйверы видеокарты. В Linux это делается через Additional Drivers, и я установил последний стабильный драйвер:

  1. По умолчанию для 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 увидел видеокарту, требуется доустановить ещё несколько пакетов.

  1. CUDA — для использования видеокарты для расчёта данных. Если версия вашего драйвера Nvidia совпадает с версией CUDA, всё пройдет без проблем. Если нет — предстоит небольшое приключение по обновлению сначала драйвера, а потом и CUDA.

    sudo apt install nvidia-cuda-toolkit

    И сразу для мониторинга:

    sudo apt install nvtop
  1. Дополнение для Docker, умение работы с графическими ускорителями:

    sudo apt-get install nvidia-docker2
  2. Можно проверить, что все хорошо, запустив Nvidia-SMI (информация о видеокарте) непосредственно в Docker:

    sudo docker run --rm --runtime=nvidia --gpus all ubuntu nvidia-smi

Корпус устройства

Поработав немного и насмотревшись на внутренний внешний вид моей видеокарты, я решил, что надо придать устройству некую форму. Хлипкость конструкции меня пугала. Например, в кабеле M2 море контактов, а их ширина не видна невооруженным глазом, то же самое можно сказать и про саму видеокарту. В общем, хотелось, чтобы хотя бы визуально всё это выглядело надёжней.

В домашнем хозяйстве была найдена неиспользованная стальная полка для ванной, чудесным образом туда всё уместилось. Немного доработал её болгаркой и сверлом — получилась импровизированная рама (аналог рамного автомобиля).

Далее раму нескучно покрасил:

Верхнюю часть спроектировал в Inkscape, вырезал из акрила лазерным резаком, склеил и добавил кусок светодиодной ленты от китайского кулера:

Дети попросили добавить наклейки — как им можно возразить?

И финальный вид устройства:

Визуально и технически результатом я доволен, мой субъективный взгляд радуется. Ноутбук стал умнее и красивее — ну и я стараюсь не отставать, тоже учусь работать с генеративными моделями.

Комментарии (22)


  1. evr1ka
    07.10.2024 18:09
    +1

    Круто. Но почему просто не сделать отдельную сборку на Mini-ITX или Micro-ATX? В Качестве монитора использовать USB-C монитор мобильный, аля Viewsonic. Для мобильных решений можно какой-нить телефон типа S10. Клавиатуру и мышь блютузные, конечно.
    Так, в порядке бреда. Но изыскания класс, интересно было про проброс Thunderbold в тунеле и крепление конструктором к блоку питания.


    1. Antra
      07.10.2024 18:09
      +2

      Да для LLM можно было бы и просто через API работать. Типа Ollama на этом внешнем сервере, а к ней уже какой-нибудь extension (а-ля Continue для VSCode) или AnythingLLM на ноуте. Разве что на ноуте видео не ускорится, в игрушки так не поиграешь, конечно.


    1. Nikolay_Pervukhin Автор
      07.10.2024 18:09
      +1

      Спасибо большое за хороший комментарий! Так как ollama выставляет 1 порт, то действительно можно собрать на отдельном устройстве (мини сервер) и сделать доступ по сети. Быстрая работа с ollama - это конечно большой плюс, но и для повседневных задач мне лично хотелось иметь на рабочем ноутбуке видеокарту побыстрее. После установки работа стала намного комфортнее со всеми приложениями, любящими аппаратное ускорение (Chrome, electron и тп). Еще из важных плюсов то, что встроенная видеокарта на одном кристалле с самим CPU, и когда она перестала использоваться, то температура процессора снизилась.


      1. evr1ka
        07.10.2024 18:09
        +1

        Про снижение нагрузки на CPU - прям довод! Да и если машина доменная, возможно в этом смысл. Вашу позицию я понял. Удачных изысканий!


  1. Antra
    07.10.2024 18:09
    +2

    Плюсанул, потому что "во-первых, это красиво"

    Хотя и не понял, как в итоге все-таки подключили. Вроде бы карту в PCIe, который в eGPU адаптер, который по M2 включен не в "ноут", а в дополнительный SSD-шный переходник, который уже стандартно вставляется в ноут (благо Thunderbolt оказался в наличии).

    Но тогда почему "также я заказал новую видеокарту" идет уже после "SSD эпопеи? Какая видюха изначально подключалась, когда внутрь ноута пытались подключиться, а он ничего поддерживаемого не обнаружил?

    Не то, чтобы было актуально, сам просто Aorus Gaming Box в Thunderbolt втыкаю. Но хинт, что SSDшная коробчонка на самом деле дает полноценный M2, а не только для дисков, восхитил.


    1. Nikolay_Pervukhin Автор
      07.10.2024 18:09

      Спасибо большое за плюс! Вы все правильно поняли, в китайский адаптер egpu вставлена видеокарта, туда же подключается блок питания ATX. От адаптера egpu идет шлейф M2, в который вставляется в SSD-ный (Nvme) переходник, который в свою очередь имеет порт Thunderbolt, который в итоге вставляется в ноутбук. Изначально тестировал с видеокартой от стационарного домашнего компьютера (старая Nvidia GTX 760), так не был уверен, что все взлетит. Когда все заработало, то уже смело заказал видеокарту. Когда подключал M2 в тот порт под LTE/GPRS модем, адаптер egpu и видеокарта стартовали (вентиляторы на видеокарте начинали крутиться, индикаторы на egpu переключались), но ноутбук зависал с тем информационным сообщением, что я описал.


      1. Antra
        07.10.2024 18:09
        +1

        Понял, спасибо!

        А внутренний M2 разъем "для модема" действительно ограниченный. В нем, скорее всего, даже NVMe диск не завелся бы, не то, что такая хитрая конструкция.


  1. evgeniy_kudinov
    07.10.2024 18:09
    +1

    Возможно ли параллельно подключить таким образом несколько видеокарт. Например, 4 по 8ГБ.


    1. Nikolay_Pervukhin Автор
      07.10.2024 18:09
      +1

      Спасибо большое за отличный вопрос! О каких-то явных ограничениях мне не известно. Порт Thunderbolt не ограничивается подключением одного устройства. Ollama может работать с несколькими ускорителями, docker тоже может прокидывать несколько карт в контейнер. Полагаю, что узким местом может стать пропускная способность Thunderbolt, например при подключении через hub, что возможно скажется на производительности.


    1. Antra
      07.10.2024 18:09
      +2

      Если и можно, это останется 4 карты по 8 ГБ. Модель на 20ГБ все равно не запустится :(

      Разве что разные модели параллельно (на одной карте llama, на другой условный starcoder...


      1. Moog_Prodigy
        07.10.2024 18:09
        +1

        В интерфейсе oogabooga есть интересная галочка "row split", вот перевод подсказки:

        Разделите модель по строкам по GPU. Это может улучшить производительность нескольких GPU.

        Не совсем понимаю, что это означает, но в глубине души очень надеюсь что это то, о чем идет речь.


        1. Antra
          07.10.2024 18:09
          +1

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


          1. evgeniy_kudinov
            07.10.2024 18:09

            Я не эксперт в этой области, но кажется в теории можно использовать партиционирование(partition), как например в БД. Возможно уже есть решения или они появятся в будущем. Тогда можно было бы в "домашних" наращивать произвольный объем памяти и запускать большие модели.


            1. Antra
              07.10.2024 18:09
              +2

              Я видел

              you can run an LLM much larger than your VRAM to answer a yes/no question every 5 seconds on average, for throughput use cases. 1

              This is possible with batching and layer-wise inferencing from disk, where we stream an LLM's layers from the hard drive into VRAM, and run each layer against multiple in-progress prompts before moving on to the next layer.

              И даже в LM Studio видел выбор, сколько слоев помещать в VRAM. Но это все было в контексте "что не влезло в VRAM доделаем в обычной памяти, пусть и медленно".

              А сейчас нашел на реддите пост двухмесячной давности:

              So the layers across multiple GPUs doesn’t run in parallel or faster than if the model layers could fit on one single GPU, the water has to flow in sequence through all the layers. Ideally we would all have a GPU with enough memory to fit the big models, but we don’t so we have to split big models across multiple GPUs. The multi GPUs don’t run in parallel and make things magically faster, they run in series.

              Если я правильно понял, "второй процессор на GPU" выгоды не даст (сначала отработает на первой карте, потом начнет работать на второй карте). Но вот "продолжение" будет все же работать быстро в VRAM, а не тормозить в обычной памяти.

              Так что да, выглядит не идеальным, но вполне приемлемым. При том, что RTX 3090 gaming box aorus (GV-N3090IXEB-24GD) на авито продается за 75-85 тыс. руб, выглядит реалистичным иметь таких две штуки и грузить 40GB модели.


  1. Apxipelag
    07.10.2024 18:09
    +1

    Игрался с таким переходником пару лет назад. вполне прекрасно запитывается от sff БП, через полноценный м.2 в материнке потерь в попугаях почти не было(в пределах погрешности). как испытуемую брал 3070ти.
    единственный минус - как и у автора, требуется удлинитель, чтобы красиво спрятать. китайцы постоянно что то новое рожают, поэтому у каждого это свой путь. но это довольно интересная тема, если вы не хотите заводить полноценный системник


  1. event1
    07.10.2024 18:09
    +1

    Статья отличная, но не могу удержаться от лёгкой душинки

    Но отключить в горячем режиме не получится: PCI — не USB, и требует подключения модуля ядра.

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


    1. Nikolay_Pervukhin Автор
      07.10.2024 18:09

      Все верно, спасибо за уточнение!


    1. 104u
      07.10.2024 18:09
      +1

      Разве спецификация PCI-e не поддерживает горячее подключение? Другое дело, конечно, что оно не реализовано (по крайней мере в бытовом железе)


      1. event1
        07.10.2024 18:09
        +1

        да, вы правы. Вот интересная статья про обработку подключений/отключений в ядре


  1. yppro
    07.10.2024 18:09
    +1

    А на Windows такое можно сделать? У меня в ноуте уже стоит 4060/8, но только я проапгрейдился, как вышел Flux, а ему, гаду, уже минимум 16 подавай


    1. Nikolay_Pervukhin Автор
      07.10.2024 18:09
      +1

      Я думаю можно, поискал, нашел официальную инструкцию у докер через wsl2:
      https://docs.docker.com/desktop/gpu/


      1. yppro
        07.10.2024 18:09

        Спасибо