Когда начинаешь изучать или использовать машинное обучение, то думаешь, как приспособить те устройства, которые есть в наличии, чтобы снизить свои траты на вход. И, в частности, обладатели довольно мощных старых карт AMD (типа AMD Fury), на которых легко идут довольно тяжёлые игры типа Cyberpunk 2077 или Atomic Heart, сталкиваются с тем, что эти GPU бесполезны для PyTorch и других фреймворков машинного обучения. Да и самые современные карты AMD 7900-й серии работают с PyTorch только из под Linux. Также есть редкие карты других брендов, типа Intel Arc или китайские, которые хотелось бы использовать для машинного обучения.

Итак, в этой статье я приведу подход, который в некоторых случаях может помочь. Он сыроват, но других работающих вариантов под PyTorch я не нашёл. Итак, речь пойдёт о проекте израильского разработчика Артёма Бейлиса (Тонких) pytorch_dlprim.

Предыстория проекта pytorch_dlprim


Артём Бейлис — человек широко известный в узких кругах тем, что в своё время написал CMS для сайтов и шаблонизатор на чистом C++. Самый частый вопрос в FAQ этого проекта звучит так: «Вы сумасшедший или мазохист?»

Его, как и многих других, расстраивало то, что хорошее (но старое, до эпохи ROCm) железо AMD и других брендов нельзя использовать в современных фреймворках машинного обучения, хотя оно поддерживает вычисления общего назначения через OpenCL. К слову говоря, в какой-то степени это универсальная проблема. Которая касается и Nvidia, которая не выпускает новейшие версии CUDA для карт прошлых поколений.

AMD с появлением ROCm и ROCm HIP (аналог CUDA) тоже не решила проблему, так как каждая следующая версия ROCm отказывалась от поддержки какого-то предыдущего поколения видеокарт. В данный момент ROCm 6.2 поддерживает Radeon 7900, Radeon VII, ускорители MI100, MI210, MI250, MI300 и некоторые модели PRO-карт. Это очень и очень скудная поддержка.

Почему я тут вообще заговорил о ROCm? Потому что PyTorch с недавних пор начал работать с ROCm.

Но ROCm поддерживает очень мало видеокарт AMD. И только под Linux.

Суть проекта pytorch_dlprim


Так вот, возвращаемся к Артёму Бейлису. Этот титан мысли (без доли сарказма) задумал подружить все устройства с поддержкой OpenCL с фреймворками машинного обучения.

Идея такая: OpenCL — это очень похожая на CUDA вещь. Тот же Си-подобный синтаксис. Похожие цели. Поэтому Артём понял, что если устройство поддерживает OpenCL, то его можно использовать в машинном обучении. Неважно, что за устройство: FPGA, видеокарта, специализированная плата или процессор. Главное, чтобы для него был драйвер OpenCL.

История проекта


Вооружившись недюжинным фанатизмом, он с 2021 года несколько лет тянул этот Сизифов камень. Один. И сделал-таки библиотеку DLPrimitives. Что расшифровывается как «Deep Learning Primitives». Эта библиотека написана на C++ и реализует стандартные функции DL на C++ и OpenCL.

Потом Артём написал бэкенд для Pytorch под названием pytorch_dlprim. И ещё несколько других бэкендов: для Caffe и даже начальную поддержку TensorFlow.

Естественно, период такого фанатизма не может продолжаться вечно, предполагаю, что Артёму нужно как-то зарабатывать на жизнь, кормить семью. А, как я понял, руководство AMD не поняло, что им достаточно нанять одного чувака, чтобы решить кучу проблем с поддержкой старых карт. Поэтому сейчас Артём возвращается к этому проекту примерно раз в полгода.

Автор этой статьи, кстати, тоже отметился внесением большого патча в проект Артёма. Коммита которого мне пришлось ждать 4 месяца. Репозиторий Артёма. В конце статьи ещё дан мой репозиторий, на случай если Артём забросит разработку. Сейчас нужно использовать только его репозиторий, мой на текущий момент устарел.

Однако для многих ситуаций то, что уже Артёмом сделано, решает свои задачи. Иными словами, если не использовать редких функций PyTorch, то мы можем использовать старые карты AMD для обучения и тестирования нейронок в PyTorch.

Устанавливаем pytorch_dlprim под Windows


Естественно, драйвера OpenCL для вашей видеокарты уже должны быть установлены. Часто это происходит автоматически, и, как правило, специально их устанавливать не нужно.

Для того, чтобы избавить пользователей Windows от мук компиляции с недавних пор Артём запустил поддержку бинарных релизов в формате whl. Эти релизы работают, начиная с версии PyTorch 2.4.0.

Достаточно скачать со страницы релизов файл whl для нужной версии python, а потом установить примерно такой командой:

pip install pytorch_ocl-0.1.0+torch2.4-cp312-none-win_amd64.whl

В самом коде достаточно сделать:

import pytorch_ocl
# Цифра после ocl может быть любой, но скорее всего 0 или 1. Зависит от числа поддерживаемых OpenCL-платформ
device=torch.device("ocl:1")

Для того, чтобы можно было приступить к экспериментам. Однако, если вы работаете с PyTorch 1.13, то компилировать всё-таки придётся.

Как я запустил под Linux PуTorch на AMD Radeon Fury и Radeon R9 280X


Вообще, дела у AMD с поддержкой OpenCL под Linux у старых карт обстоят плохо. Есть несколько вариантов OpenCL и большинство из них уже не поддерживаются или убраны из публичного доступа. Есть даже отдельный проект I-love-compute, который помогает разобраться в этом винегрете. Причём это касается как старых карт AMD, так и карт Nvidia.

Иногда получается с помощью I-love-compute включить поддержку OpenCL у старых карт на новых дистибутивах, а иногда нет.

Мне же помогла Mesa, это драйвера OpenCL с открытым исходным кодом. Дело в том, что Mesa использует LLVM для генерации кода на GPU. И с некоторых пор LLVM стал поддерживать бэкенд amdgpu для генерации кода для GPU от архитектуры r600 и GCN 1.0 и выше.

Как говорится, лучше поздно, чем никогда.

▍ Активируем поддержку rusticl в Mesa 3D


Поддержка OpenCL 3.0 для старых карт реализована в Mesa через модуль на языке Rust под названием rusticl. Иногда его требуется активировать. Если эта поддержка уже и так активна, то делать ничего не нужно. Проверяем так:

clinfo

Если в выводе мы видим что-то подобное:

Platform Name                                   rusticl
Number of devices                                 1
  Device Name                                     AMD Radeon R9 Fury Series (radeonsi, fiji, LLVM 17.0.6, DRM 3.57, 6.8.9-calculate)
  Device Vendor                                   AMD
  Device Vendor ID                                0x1002
  Device Version                                  OpenCL 3.0

То rusticl уже активен, тогда просто запоминаем номер платформы. У меня rusticl идёт второй платформой в выводе clinfo, нумерация начинается с нуля, так что номер rusticl — это 1.

Если же rusticl нет в выводе поддерживаемых платформ, то нужно экспортировать переменную

RUSTICL_ENABLE=radeonsi

В данном случае я привёл переменную для карт AMD семейства Southern Islands, для вашего семейства она может быть другой.

Проверку тогда делаем так:

RUSTICL_ENABLE=radeonsi clinfo

Если платформа rusticl появилась, то всё отлично. И эту переменную среды можно вписать в файл, который при загрузке компа будет её активировать.

У меня это файл radeonsi.sh, который лежит в /etc/profile.d.

export RUSTICL_ENABLE=radeonsi

▍ Компилируем pytorch_dlprim


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

Но в ней нет ничего сложного. Клонируем с github и компилируем. Мы должны находиться в виртуальном окружении питона.

Активируем окружение:

. your_path_ve/bin/activate

Компилируем:

# Проект dlprimitives вложен, поэтому ключ --recurse-submodules
git clone --recurse-submodules https://github.com/artyom-beilis/pytorch_dlprim.git
cd pytorch_dlprim
mkdir build
cd build
cmake -DCMAKE_PREFIX_PATH=$VIRTUAL_ENV/lib/python3.10/site-packages/torch/share/cmake/Torch ..
make

При компиляции возможны предупреждения. Игнорируем. Компиляция идёт несколько минут. Это нормально. C++ компилируется медленнее, чем С.

Для ускорения вместо make можем использовать:

# Если у нас 12 логических или физических ядер
make -j12


Если у нас PyTorch 1.13.1 получим библиотеку libpt_ocl.so. У меня она вышла 32 МБ весом. Её можно положить, например, в /usr/local/lib64.

Если же у нас PyTorch 2.4.*, то получим папку pytorch_ocl, а в ней библиотеку примерно на 50 МБ и питон-обвязку к ней. В случае виртуального окружения pytorch_ocl потом нужно скопировать в папку site-packages.

Далее можно подняться на уровень выше и запустить тесты mnist.py и test.py. Чтобы они заработали, в коде тестов или в командной строке нужно подставлять правильный номер платформы. Мне пришлось 0 заменять на 1.

python mnist.py --device ocl:1
# В коде менял privateuseone:0 на privateuseone:1 для PyTorch 1.13.1
python test.py

Скрипт mnist.py может вылететь с ошибкой, об этом нужно сказать Артёму. А вот test.py у меня нормально отрабатывает.

▍ Подключаем pytorch_dlprim к PyTorch 1.13


Далее, в *.py файлах мы подключаем новый бэкенд так:

torch.ops.load_library("/usr/local/lib64/libpt_ocl.so")
# номер платформы может быть другим
device = torch.device("privateuseone:1")

▍ Подключаем pytorch_dlprim к PyTorch 2.4


import pytorch_ocl
# Цифра после ocl может быть любой, но скорее всего 0 или 1. Смотрим через clinfo. Детали выше в статье.
device=torch.device("ocl:1")

Смотрим загрузку GPU во время работы с нейросетями


Есть 2 утилиты: старая и новая. Старая — это radeontop, более новая — это amdgpu_top. Устанавливаем их через пакетный менеджер вашего дистрибутива или компилируем из исходников.

Вот так выглядит вывод amdgpu_top без нагрузки:



А вот я обучаю нейросеть:



Что может и что не может pytorch_dlprim


На странице проекта Артём пишет, что протестировал много нейросетей из PyTorch, и они по большей части успешно отработали.

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

Например, такая штука не работала из-за отсутствия поддержки функций torch.index_select и torch.logical_xor:

# Ищем индекс с максимальным значением, если он совпадает, то засчитываем угадывание.
correct_curr =  torch.index_select(y, 1, torch.tensor(0).to(device)).squeeze(1).logical_xor(pred.argmax(1)).type(torch.int).sum().item()

Но когда я придумал более простой аналог, то pytorch_dlprim справился:

correct_curr = pred.argmax(1).eq(y.argmax(1)).int().sum()

Иными словами, если работать с базовыми функциями, то вполне можно извлечь пользу в DL от старых GPU в PyTorch.

Разные версии OpenCL


AMD за всё время сделала несколько версий OpenCl. И несмотря на то, что их не так-то просто использовать, в некоторых случаях они могут работать быстрее rusticl. Но намного капризнее. Так как возможны конфликты библиотек. И то, что работало ранее, может перестать работать после какого-то обновления. По-хорошему было бы прекрасно их как-то в докер-образы запаковать, а пока есть только проект I-love-compute.

У Mesa также есть более старый проект Clover для OpenCL. В каких-то случаях старого железа он может быть тоже актуален.

Прелесть проекта Артёма Бейлиса заключается в том, что устройство должно поддерживать OpenCL для интеграции с PyTorch, а что это будет за устройство — неважно. Он писал, что люди и с видеокартами Intel и даже FPGA использовали его проект.

Совместимые версии PyTorch


Я использовал pytorch_dlprim с версией PyTorch 1.13, так как с 2.2.1 было уж очень много предупреждений (warnings). Артём говорит, что с версией 2.4 уже работает нормально. С версиями 2.0-2.3 возможны проблемы.

Статус проекта


В данный момент проект активно развивается. Внедрены эпохальные изменения, упрощающие установку, поддерживается последняя версия PyTorch 2.4.0. Артём дорабатывает код, чтобы на pytorch_dlprim заработала нейросеть YOLO, предназначенная для онлайн-распознавания объектов и сегментации изображений. Также он купил видеокарту Intel Arc, чтобы улучшить поддержку этой платформы. Есть блог разработки (редкообновляемый).

Однако история показывает, что Артём может пропасть на несколько месяцев, и в это время вы не дождётесь ответа на ваш тикет. Сейчас у него как раз период активности. Поэтому прошу всех заинтересованных лиц потестировать его проект и прислать ему ошибки, пока у него опять есть запал.

Мне лично пришлось написать несколько патчей, чтобы использовать pytorch_dlprim в своём проекте. И если Артём опять пропадёт с радаров, то я на всякий случай оставлю ссылку на мой репозиторий, так как есть вероятность, что код в нём будет свежее, чем в его оригинальном. Как было последние 4 месяца, которые ему потребовались, чтобы принять мой большой пул-реквест (патч).

Проект pytorch_dlprim нуждается в помощи сообщества, так как многие простые функции до сих пор не написаны. Если вы хотя бы немного знаете OpenCL и средне С++, то можете принести пользу сообществу.

Пожалуйста, тестируйте и присоединяйтесь к разработке!

Telegram-канал со скидками, розыгрышами призов и новостями IT ?

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


  1. nagayev
    21.08.2024 05:25
    +2

    Хорошо бы наработки попали в основной проект.


    1. inetstar Автор
      21.08.2024 05:25

      Вы можете поддержать эту идею в свежем треде на форуме PyTorch.

      А вот тред, который ведётся с 2021 года.


  1. Shannon
    21.08.2024 05:25

    Но ROCm поддерживает очень мало видеокарт AMD. И только под Linux.

    Не то чтобы это важно, но не так уж и мало, включая частичную поддержку даже rx 470/580. Но, конечно, не без бубнов для некоторых моделей. И для версии ROCm 5.7, которой достаточно. Не обязательно иметь именно 6.2, когда под рукой есть AMD карта и хочется с ней что-то ускорить.

    Под Linux, например, для rx 6600/6700 нужно прописывать перед запуском скрипта:
    export HSA_OVERRIDE_GFX_VERSION=10.3.0
    Для rx 470/580:
    export HSA_OVERRIDE_GFX_VERSION=8.0.3

    На Windows есть ZLUDA, которая транслирует вызовы CUDA в ROCm для Windows. Для 6800 и выше это заведется само, а для моделей ниже нужно взять скомпилированные ROCmLibs отсюда: https://github.com/brknsoul/ROCmLibs

    Можно использовать как с pytorch, заменяя библиотеки вручную, и работать как будто бы работа идут с CUDA, но замененные библиотеки будут ссылаться на ROCm, либо запускать вот так:
    .\zluda.exe "C:\Program Files\Blender Foundation\Blender 4.0\blender.exe"

    Но pytorch_dlprim конечно, удобнее, если он не требует ничего делать, хоть и OpenCL не самое быстрое из возможных решений.


    1. inetstar Автор
      21.08.2024 05:25

      Спасибо за ценный комментарий.

      Есть где-то полный список этих HSA_OVERRIDE?

      Пока нашёл частичный тут.

      Под ROCm под Windows вы имеете ввиду HIP SDK?