Обновить

Нафиг NVIDIA! Я запустил Qwen на FPGA за $50 — а свой TPU назвал бы «КЕДР». Часть 1

Уровень сложностиПростой
Время на прочтение2 мин
Охват и читатели14K
Всего голосов 41: ↑37 и ↓4+40
Комментарии64

Комментарии 64

Очень интересно. Хотелось бы деталей.
Это прям было б как на старом добром хабре

Сейчас пожалуюсь своей Qwen3-0.6B, посмотрим, что она скажет про Боромира. Теперь она ещё и моим психологом по совместительству будет :)

 Она старалась. 0,6 миллиарда параметров на плате за $50, что вы хотели :)
Она старалась. 0,6 миллиарда параметров на плате за $50, что вы хотели :)


Я Вам больше скажу, я cпросил у 6.0 Sol про вторую часть:

Скрытый текст
https://habr.com/ru/articles/1092504/
как может выглядеть рассказ с подробностями от первого лица автора? сделай интересно и драматично в чтении.

и получил вполне себе продолжение — до того, как Вы его опубликовали:

‑--‑--‑--‑--

КЕДР: как я запустил нейросеть на списанной FPGA за $50 и теперь хочу собрать из них маленький суперкомпьютер

Плата на AliExpress выглядела как обычный серверный металлолом. Полноразмерный PCIe, здоровенная микросхема Xilinx посередине, восемнадцать чипов памяти и почти никаких разъёмов. Продавец просил около пятидесяти долларов.

Я открыл фотографию покрупнее. На главной микросхеме читалось XC7K480T. Это уже было интересно: Kintex-7, 1920 DSP-блоков, почти 300 тысяч LUT и несколько мегабайт внутренней блочной памяти. Довольно серьёзная FPGA, которую когда-то устанавливали в дорогостоящее специализированное оборудование.

Сама плата оказалась Inspur YPCB-00338-1P1, по всей видимости, из списанного серверного ускорителя. На ней стояли четыре гигабайта DDR3, причём с двумя независимыми контроллерами памяти.

Я стал искать, что с ней вообще можно сделать.

Через некоторое время обнаружил китайский блог, автор которого разобрал эту плату, восстановил часть схемы, нашёл JTAG и подготовил необходимые файлы для Vivado. Затем нашёлся openTPU — открытый нейросетевой процессор Felipe Sens Bonetto, который уже работал на точно такой же Kintex-7.

В репозитории были исходники RTL, компилятор, симулятор, PCIe-драйвер, инструменты диагностики и, главное, результаты настоящего инференса. Qwen3-0.6B выдавала около 31 токена в секунду, Qwen3.5-2B — около 12.

На 133 МГц. С DDR3. На плате за пятьдесят долларов.

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

У меня давно крутилась идея сделать собственный inference-процессор. Название даже придумал — «КЕДР». Правда, дальше размышлений об архитектуре дело пока не заходило.

Теперь появился хороший повод наконец заняться железом.

Я заказал плату.

Чужая серверная плата и мой MINISFORUM

Когда посылка приехала, первым делом я сверил фотографии с документацией. У подержанных FPGA-плат есть неприятная особенность: внешне похожие изделия могут отличаться распиновкой памяти, схемой питания или загрузки конфигурации. В обычном компьютере такие различия скрывает производитель, а здесь приходится учитывать всё самому.

Восемнадцать микросхем DDR3 оказались объединены в две группы по девять. В каждой восемь чипов обеспечивают 64-битную шину данных, девятый предназначен для ECC. Два канала по два гигабайта, теоретически около 17 ГБ/с суммарной пропускной способности при DDR3-1066.

На самом деле чипы памяти рассчитаны на DDR3-1600, но это ещё не значит, что контроллер на FPGA сможет устойчиво работать с ними на такой скорости. В подобных конструкциях частота определяется не только маркировкой микросхем, но и разводкой платы, таймингами PHY и настройками контроллера.

С подключением пришлось повозиться.

Хостом я выбрал мини-ПК MINISFORUM. Проблема в том, что внутри такого компьютера не найдёшь свободного полноразмерного PCIe x8. Пришлось выводить PCIe наружу через переходник, отдельно организовывать питание и охлаждение.

В результате получилась конструкция, совершенно непохожая на обычный компьютер: мини-ПК, кабель, переходник, серверная плата и вентилятор. Главное, что всё можно было проверить по отдельности.

Сначала питание, затем обнаружение устройства через lspci, потом проверка согласованной скорости и ширины PCIe-линка.

Нужно понимать, что надпись x8 на разъёме ничего не гарантирует. Если подключение выполнено через M.2 с четырьмя линиями, устройство будет ограничено этими четырьмя линиями. Для запуска openTPU этого достаточно, но при последующей подгрузке больших моделей пропускная способность PCIe уже может иметь значение.

И тут возник следующий вопрос: как вообще заставить компьютер общаться с процессором, которого ещё нет?

Процессор, который сначала нужно собрать

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

В случае openTPU в Kintex-7 создаётся собственный вычислительный процессор. С матричным MXU, векторным VPU, секвенсором инструкций, DMA и подсистемой памяти.

Причём это не RISC-V с приделанным сопроцессором. У openTPU собственная специализированная ISA. Компилятор составляет последовательность инструкций, которая управляет вычислительными блоками и перемещением данных.

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

Например, можно взять матричное умножение, скомпилировать его, посмотреть последовательность команд, затем прогнать эти команды в симуляторе. После этого ту же программу можно выполнить на настоящем FPGA-процессоре и сравнить результат.

Для разработки нового железа такой цикл почти идеален: меняешь схему, проверяешь арифметику, ищешь расхождения.

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

Если при частоте 133 МГц критический путь не укладывается примерно в 7,5 наносекунды, придётся менять размещение, архитектуру или частоту.

Дополнительной неприятностью оказалась лицензия Vivado. Бесплатная редакция не поддерживает XC7K480T, поэтому для сборки потребовалась соответствующая лицензия. Для первого знакомства хватило ознакомительной, но при дальнейшем развитии проекта этот вопрос придётся решить.

Зато после сборки я получил файл конфигурации, который можно было загрузить в Kintex через JTAG.

Заводскую Flash я трогать не стал. Если записать конфигурацию только в оперативную часть FPGA, после выключения питания карта снова загрузит заводский образ. Для экспериментов удобно: неудачный bitstream не превращает плату в дорогую подставку под кружку.

После загрузки конфигурации пришлось заново обнаружить PCIe-устройство в Linux. BIOS уже успел выполнить первоначальное сканирование шины, когда внутри FPGA ещё находилась старая логика.

Штатная утилита otpu-setup --rescan решила вопрос.

Наконец, появились управляющие регистры openTPU и интерфейсы XDMA. Можно было записывать данные в память FPGA и читать обратно.

Когда память начинает врать

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

На плате четыре гигабайта, но физически это две независимые области по два гигабайта. Программе же удобнее видеть единое адресное пространство. Поэтому контроллер openTPU чередует данные между каналами блоками по 64 байта.

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

Поначалу сравнение давало ошибки, причём штатная диагностика при этом проходила успешно.

Неприятная ситуация. Можно потратить несколько дней на поиски неисправного чипа DDR3, хотя проблема находится в собственном коде.

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

После исправления адресации тест стал проходить.

Я прогнал разные шаблоны данных, частичные записи и обращения к обоим каналам. Затем оставил длительную диагностику, чтобы проверить стабильность работы контроллеров.

Особенно заинтересовало, можно ли увеличить частоту DDR3.

У разработчика openTPU в документации описаны эксперименты с более быстрыми режимами. Некоторые конфигурации проходят тесты, но на DDR3-1333 появляются таймауты DMA и даже пропадание PCIe-соединения.

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

Я оставил штатные DDR3-1066.

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

Ну что, Qwen, знакомиться будем?

После проверки памяти дошла очередь до нейросети.

Для первого запуска я взял Qwen3-0.6B. Подготовил веса, настроил программное окружение openTPU и запустил:

otpu-chat --backend board

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

Но я держал открытым второй терминал с otpu-smi.

Там менялись аппаратные счётчики, обновлялась статистика работы блоков, увеличивались объёмы передачи данных. Можно было убедиться, что модель действительно исполняется на FPGA, а не незаметно переключилась на CPU.

На этом месте я надолго застрял с профилировщиком.

Хочется ведь понять, что конкретно делают эти несколько тысяч логических элементов и DSP-блоков, пока нейросеть подбирает следующее слово.

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

Всё довольно последовательно, пока не начинаешь смотреть на временную диаграмму.

Здесь вычислительный блок ждёт память. Здесь DMA ещё не закончил передачу. Здесь очередной матричный блок уже освободился, но следующий набор весов ещё не готов.

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

Главный сюрприз оказался в цифрах DDR3

В openTPU уже проделана большая работа по оптимизации матричных вычислений. Тем интереснее было разобраться, почему Qwen3-0.6B даёт примерно 31 токен в секунду.

В опубликованных измерениях проекта на каждый токен приходится около 442 МБ прочитанных весов.

Умножаем на 31 токен в секунду — получаем приблизительно 13,7 ГБ/с.

А реальная пропускная способность DDR3 в этом режиме составляет примерно 13,9 ГБ/с.

Получается почти идеальное совпадение. Процессор выбрал практически всю полезную полосу памяти, которую ему удаётся получить из этих двух каналов.

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

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

Я полез смотреть отчёт синтеза.

По данным автора исходной статьи, в одной из конфигураций openTPU использует примерно 58% LUT, 19% FF, 61% BRAM и 37% DSP.

Вот теперь стало по-настоящему интересно.

DSP-блоков свободно больше половины. Казалось бы, добавляй вычислителей сколько нужно. Но для каждого нового вычислительного блока потребуются локальные буферы, логика управления, мультиплексоры, дополнительные соединения. А LUT и BRAM уже заняты больше чем наполовину.

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

В этом месте я перестал рассматривать свободные DSP как обещание дополнительной производительности.

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

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

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

Получается сразу несколько направлений для экспериментов: пакетная обработка запросов, предвыборка весов, оптимизация внутренних буферов и уменьшение числа обращений к DRAM.

А ещё можно использовать более компактные представления весов.

Почему четыре бита иногда полезнее четырёх новых процессоров

В openTPU есть поддержка четырёхбитного представления весов FP4 E2M1 с блочным масштабированием. Это позволяет примерно вдвое уменьшить объём данных по сравнению с восьмибитным форматом.

В тестах разработчика Qwen3-0.6B в INT8 выдаёт около 22 токенов в секунду, а в FP4 — уже примерно 31.

Сама FPGA осталась прежней, частота не изменилась. Просто каждому токену требуется существенно меньше чтений из DRAM.

Разумеется, у квантования есть цена — потеря точности модели. Поэтому проверять нужно не только скорость, но и качество получаемых ответов, желательно на заранее подготовленном наборе данных.

Однако идея мне понравилась.

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

Я стал думать, как организовать эксперименты так, чтобы каждое изменение можно было оценить объективно.

Один и тот же checkpoint, одинаковые промпты, одинаковая длина генерации, измерение prefill и decode раздельно. Плюс контроль совпадения результатов с эталонным симулятором.

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

Именно в этот момент мне пришла в голову мысль о второй плате.

Но прежде я решил разобраться с ещё более странным результатом openTPU.

Как на четырёх гигабайтах помещается Qwen на 35 миллиардов параметров

В репозитории приводится результат запуска Qwen3.5-35B-A3B на той же Kintex-7. Около четырёх токенов в секунду.

Меня заинтересовало, как разработчик вообще сумел разместить такую модель на карте с четырьмя гигабайтами DDR3.

Технически он её там целиком и не размещал.

Qwen3.5-35B-A3B использует Mixture of Experts. При генерации токена активируется лишь часть экспертов, поэтому нет необходимости одновременно загружать все веса в память ускорителя.

В openTPU реализован механизм подгрузки экспертов с хоста. В DDR3 выделены слоты, в которых находятся наиболее востребованные эксперты, а остальные веса хранятся в оперативной памяти компьютера или на накопителе.

Если нужного эксперта нет на FPGA, хост получает запрос и отправляет его по PCIe через DMA.

Ключевой вопрос — сколько таких запросов возникает на каждый токен.

По измерениям разработчика, локальный кеш экспертов обеспечивает около 62% попаданий. В среднем на один токен приходится передавать по PCIe примерно 153 МБ данных.

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

И здесь обнаружилась очень интересная подробность.

Разработчик ускорил систему, изменив способ хранения экспертных весов на хосте. Вместо того чтобы читать данные, затем перекладывать их в нужном порядке и только после этого отправлять через DMA, он начал заранее сохранять веса в раскладке, соответствующей структуре DDR3 на плате.

В результате удалось убрать часть лишнего копирования и существенно увеличить скорость генерации.

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

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

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

А поскольку FPGA можно перепрограммировать, ничто не мешает экспериментировать с этим непосредственно на аппаратном уровне.

Почему я теперь рассматриваю две FPGA

У одной Kintex-7 есть два ограничения: четыре гигабайта памяти и примерно 17 ГБ/с теоретической полосы DDR3.

Предположим, купить вторую.

Вместо одной FPGA получим две, у каждой будет собственная DDR3, контроллеры и вычислительные блоки. Суммарная память увеличится до восьми гигабайт, а теоретическая полоса — до 34 ГБ/с.

Но здесь есть важная тонкость.

Нельзя просто установить вторую карту и ожидать, что одна Qwen начнёт генерировать токены вдвое быстрее. На каждой FPGA находится отдельное адресное пространство. Между ними нужно организовать обмен, а вычисления модели придётся распределить.

Самый очевидный способ — разделить модель по слоям.

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

Зато появляется возможность разместить модель, которая раньше не помещалась целиком.

Для второго эксперимента можно попробовать pipeline parallelism. Пока первая FPGA обрабатывает следующий запрос, вторая завершает предыдущий. Это должно повысить суммарную производительность при нескольких одновременных запросах, хотя задержка отдельного ответа может не уменьшиться.

Ещё интереснее распределять экспертов MoE.

Например, часть экспертов размещается на первой FPGA, часть — на второй. Хост выступает диспетчером, а программная часть планирует вычисления так, чтобы реже передавать большие блоки весов.

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

При этом обе FPGA остаются полностью управляемыми. Можно экспериментировать не только с программной логикой, но и с собственными командами обмена.

Теперь понятно, зачем мне может понадобиться вторая пятидесятидолларовая плата.

Следующая находка — Kintex UltraScale+ с DDR4

Пока я рассматривал варианты с двумя Kintex-7, на AliExpress нашлись платы с XCKU5P — более современными FPGA семейства Kintex UltraScale+.

У некоторых есть PCIe Gen3, DDR4, FMC и даже QSFP28. Цены китайских плат начинаются с нескольких сотен долларов, хотя нужно внимательно проверять комплектацию.

Тут я снова достал калькулятор.

Один 64-битный канал DDR4-2400 теоретически способен передавать 19,2 ГБ/с. Две FPGA с одним таким каналом каждая дадут суммарно 38,4 ГБ/с. Если удастся найти платы с двумя независимыми 64-битными каналами на каждой, получится уже 76,8 ГБ/с.

Для сравнения, у нынешней Kintex-7 оба канала DDR3 дают около 17 ГБ/с вместе.

А ещё у UltraScale+ более современная внутренняя архитектура, другой DSP48E2 и существенно более широкие возможности для высокочастотной реализации вычислительных блоков.

Однако назвать такую замену простым апгрейдом нельзя. Придётся переносить PCIe-интерфейс, контроллеры памяти, адаптировать тактирование, ограничения выводов и саму реализацию процессора.

Есть и ловушка в объявлениях продавцов: «8Gbit DDR4» означает один гигабайт, а «16Gb» — два гигабайта. Увидев крупную цифру на странице товара, легко решить, что продаётся плата с шестнадцатью гигабайтами памяти.

Для такого проекта ошибиться с объёмом памяти особенно обидно.

Поэтому прежде, чем заказывать две XCKU5P, нужно получить точную схему или хотя бы убедиться по маркировке микросхем, сколько памяти распаяно на плате и сколько независимых каналов доступно FPGA. Также важно выяснить, входит ли в комплект PCIe-плата целиком или продаётся только core module.

Но направление получилось привлекательным.

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

Причём я бы обязательно оставил старую Kintex-7 в качестве эталона. Перенос нового процессора на другую FPGA интересен сам по себе, но гораздо полезнее иметь возможность запускать те же модели и проверять каждую оптимизацию на обеих архитектурах.

Что делать с «КЕДРом»

Пока у меня нет собственного процессора с уникальной ISA и разработанной с нуля микроархитектурой. Есть воспроизведённый openTPU, который действительно исполняет языковые модели на физической FPGA.

Но теперь можно перейти от знакомства с платформой к экспериментам.

Я уже вижу несколько вещей, которые хочется проверить в первую очередь.

Например, изменить организацию локальных буферов весов так, чтобы реже обращаться к DDR3. Или попробовать увеличить число параллельных операций без существенного роста потребления LUT и BRAM.

Отдельный вопрос — использование ИИ-агентов. Сам openTPU создавался при активном участии ИИ, и мне интересно использовать тот же подход при поиске вариантов архитектуры. Агент может предлагать изменения RTL, составлять тесты и анализировать отчёты Vivado, но результат следует проверять симулятором и реальными измерениями.

Хороший эксперимент в моём понимании должен заканчиваться конкретными цифрами: сколько логических ресурсов занято, какой timing slack, сколько байтов приходится читать на токен, сколько циклов занимает операция, совпадает ли результат с эталоном.

На этой основе можно будет уже обсуждать собственный процессор.

А для начала я хочу попробовать три продолжения.

Эксперимент № 1. Две старые Kintex-7 — первый двухпроцессорный «КЕДР». Бюджет $200–400

Покупаю вторую такую же Inspur с четырьмя гигабайтами DDR3, организую два PCIe-подключения и пытаюсь запустить одну модель на двух FPGA.

Суммарно получаю 8 ГБ памяти, четыре канала DDR3 и 34 ГБ/с теоретической полосы. Последняя цифра, разумеется, не означает, что один вычислительный блок сможет использовать все 34 ГБ/с. Память физически разделена между устройствами.

Первый тест — разделение модели по слоям. Следующий — обработка нескольких запросов в конвейере. Если получится, перейду к распределению MoE-экспертов.

Интереснее всего будет измерить, при каких размерах модели и нагрузках вторая FPGA действительно приносит пользу. Можно даже попытаться построить примитивный планировщик, который будет сам выбирать место выполнения слоёв.

Для такого проекта понадобится не только вторая карта, но и подходящий хост с двумя PCIe-подключениями. Нынешний MINISFORUM может оказаться неудобен.

Эксперимент № 2. Две XC7K480T с 16 ГБ DDR3. Бюджет $500–1200

Здесь идея сложнее. Хочется получить по восемь гигабайт памяти на каждой Kintex-7, сохранив два независимых 64-битных канала DDR3.

На существующей Inspur установлено четыре гигабайта, поэтому просто перепрошить её на восемь не получится. Нужно либо найти подходящие платы с большим объёмом DDR3, либо исследовать возможность аппаратной модернизации памяти.

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

Зато если всё удастся, получим две FPGA с суммарными 16 ГБ DDR3 и той же теоретической полосой около 34 ГБ/с.

Дополнительная память особенно интересна для MoE. Можно держать больше экспертов локально и реже обращаться к хосту, не меняя вычислительных блоков.

Я бы попробовал Qwen3.5-35B-A3B и измерил, как увеличивается доля попаданий в локальный кеш экспертов. Тогда будет видно, сколько производительности даёт именно увеличение памяти, отдельно от изменения её скорости.

Эксперимент № 3. Две XCKU5P с DDR4 — уже собственная архитектура ускорителя. Бюджет $1000–2500

Покупаю две подходящие платы Kintex UltraScale+, желательно с 8–16 ГБ DDR4 на каждой, и переношу на них openTPU.

Здесь первым делом потребуется проверить реальную конфигурацию памяти. При одном 64-битном канале DDR4-2400 на плату суммарная теоретическая полоса двух устройств составит 38,4 ГБ/с. С двумя такими каналами на каждой — 76,8 ГБ/с.

После переноса я бы занялся уже самой микроархитектурой.

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

Если удастся разместить 16–32 ГБ весов в совокупной локальной памяти двух плат, можно будет значительно сократить обращения к хосту при запуске больших MoE.

Здесь я уже не ставил бы целью просто получить работающую Qwen. Хочется исследовать производительность собственной архитектуры на реальной модели, понять ограничения DDR4 и оценить, насколько эффективно FPGA использует доступные вычислительные ресурсы.

Дальше можно будет выбирать между более мощной FPGA с HBM и попыткой спроектировать собственный ASIC. Но для такого решения понадобятся убедительные измерения, а не только желание когда-нибудь сделать свой чип.

Пожалуй, именно третий эксперимент уже заслуживает названия «КЕДР».

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

А пока на столе лежит первая Kintex-7.

Я открыл отчёт синтеза и снова посмотрел на использование ресурсов. Больше половины DSP ещё свободно, но LUT и BRAM уже заняты довольно плотно. В профилировщике видно, сколько времени вычислительные блоки проводят в ожидании данных.

Кажется, теперь я знаю, с чего начать следующую итерацию.

Нужно найти способ кормить существующие умножители быстрее, прежде чем добавлять новые. А если получится освободить достаточно логики и буферной памяти, можно будет попробовать и то и другое.

Для начала хватит одного удачного изменения RTL, которое даст измеримое ускорение на той же пятидесятидолларовой плате.

После него я, скорее всего, закажу вторую.

Вывод пока — 1) квантованные китайские модели с русским послабее, и 2) если не хочется ждать вторую часть, есть способ её уже прочесть в ночь на субботу ).

В общем, как сказал когда‑то другой, гораздо более известный, «Кедр», «поехали!»

А вы правы: можно загрузить весь проект в LLM, запускать и дорабатывать его с агентами. Сам openTPU, кстати, так и сделан, с активным участием ИИ-агентов. Такими темпами интернет скоро схлопнется: модели пишут, модели читают )
Но плату в разьем LLM пока не вставит!

Ничего себе, а какой размерности qwen и в какой квантизации используете?

Запускал Qwen3.5-2B (2 млрд параметров). Квантование FP4 для основных слоёв, INT8 для LM head.

На Kintex-7 XC7K480T с 4 ГБ DDR3 при частоте 133 МГц получил 12,35 токена/с на генерации. Prefill на FPGA - 38,5 токена/с, end-to-end — 7,71 токена/с. TTFT — 2,72 с.

Сейчас тестирую и другие модели, включая Qwen3.5-4B.

А для каких задач вы собираетесь использовать данные модели с данной скоростью? Саму идею поддерживаю обеими руками ЗА, но пока что для серьезных задач не годится никак (IMHO).

Да, для серьёзных задач пока слабовато, согласен. Как говорится, я не волшебник, я только учусь :) А так Мне интересно разобраться, как всё устроено на уровне железа, покопаться в архитектуре, прикрутить что-нибудь своё. Есть ещё BCU1525 с 64 ГБ DDR4, хочу и на ней попробовать. А там, кто знает, может, и до своего чипа дойдёт) Вот объединимся всем Хабром и сделаем свой Хабр-Чип для инференса 😁

Попробуйте gemma4 e4b. Мне показалось она быстрее квена

Клёвый проект!

Есть ещё BCU1525 с 64 ГБ DDR4, хочу и на ней попробовать.

У Xilinx ещё семейство Alveo было, там сопоставимые с BCU1525 модели + модели с HBM на борту.

Пока хочу выжать максимум из того, что уже есть, а дальше посмотрим :) Спасибо за наводку на Alveo и за добрые слова!

Из DDR4 много не выжмешь, в генерации токенов узкое место это memory bandwith, который у DDR4 и даже DDR5 весьма грустный. Гугл подсказывает, что у xilinx kintex-7 xc7k480t он в районе 14.9 Гб/с, вы запускали Qwen3.5-2B с 4-м квантом, то есть она у вас чуть больше 1 Гб, пусть будет 1.2 Гб. 14.9 Гб/с разделить на 1.2 Гб, получим 12.4 токена в секунду: именно то, что вы и увидели.

ИМХО, из за того, что мало деталей и статья больше похожа на ИИшную, плюс не поставил. Но вот если будет продолжение с деталями и от себя прямо будет очень интересно!

Справедливо, спасибо за честность. Первая часть вышла анонсом.

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

Согласен. Как минимум это открывает дорогу: теперь такие вещи можно изучать и строить в железе самому, а не только читать о них.

Раз уж речь зашла о кастомной логике, то было бы интересно оценить подход, который использует Tenstorrent в своих чипах.

tldr: Если знать весь граф вычисления, то данные из памяти/SSD можно тянуть заранее и асинхронно, еще до того, как они по факту понадобятся. Это принципиально отличается от банального префетчера в GPU именно тем, что мы не просто идем по индексам, а понимаем логику вычисления и распределяем нагрузку на шину.

В этом смысле FPGA тут оказывается очень кстати.

Судя по всему, статью вам тот же Qwen3-0.6B и написал.

Почти угадали :) Текст действительно причёсывал с помощью LLM, каюсь - правда, только модель была побольше. А вот все остальное....
Кстати, ради эксперимента попросил Qwen3-0.6B прямо на FPGA написать такую же статью. Вот что получилось :)

Текст действительно причёсывал с помощью LLM

Но ведь в статье нет ничего кроме LLM-сгенерированного текста.

Qwen3.5–35B сколько tps ?

По замерам автора openTPU, Qwen3.5-35B-A3B выдаёт около 4 токенов/с на такой же FPGA с 4 ГБ DDR3. Это MoE-модель, поэтому активируются не все 35 млрд параметров одновременно. Сам пока 35B не тестировал.

Без NVIDIA. Без видеокарты. На открытой архитектуре, которая разработана при активном участии ИИ‑агентов.

Вот так машины и вырвутся из под контроля...

Блин, точно! Надо на всякий случай пристегнуть плату на цепь, пока не поздно :)
Сделал) А если серьёзно, то вполне возможно, что однажды ИИ действительно будет проектировать процессоры для самого себя.

Дык об этом ещё в 80-е фантасты писали. И внезапно будущее таки наступило.

Уже

Более быстрая память и более мощная FPGA

Nvidia умеет ждать.

NVIDIA пока может спать спокойно :) А нам есть где поковыряться.

Имхо надо делать несколько fpga, и каждый обвязывать несколькими каналами ddr, расширяя таким образом и dsp, и ширину обмена весами.

Да, например, можно рассмотреть две XC7K480T, на каждой по 8 ГБ DDR3 с двумя независимыми 64-битными каналами. В сумме это 16 ГБ памяти и вдвое больше DSP. Теоретическая суммарная пропускная способность при DDR3-1066 - около 34 ГБ/с.

Ещё интереснее вариант с двумя XCKU5P, по 8-16 ГБ DDR4 на каждую. Это 16-32 ГБ суммарно. С одним 64-битным интерфейсом DDR4-2400 на каждой FPGA теоретическая суммарная полоса составит 76,8 ГБ/с.

DDR4-2400

Даже сильно б/у ПЛИСа с таким интерфейсом будет стоить явно не $50

В удачном случае $500

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

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

 Клигон со Свободной памятью
Клигон со Свободной памятью

штоита??

хорошо бы знать сколько ресурсов съел этот проект на ПЛИС.
сам чип то не маленький, если там меньше половины то в целом можно нарастить число ядер TPU. А еще! насколько я знаю на этих платах ДДР можно покдлючить как два независымых канала, и увеличить скорость за счет того что из одной читают в другую пишут и на оборот. тогда скорость повысится.

По ресурсам после синтеза на XC7K480T проект занимает ~58% LUT, ~19% FF, ~61% BRAM и ~37% DSP. На плате уже работают два независимых канала DDR3.

По DSP запас ещё есть, но LUT и BRAM заняты больше чем наполовину, поэтому просто добавить вычислительных ядер не получится без дополнительной оптимизации.

скрин под рукой?) и еще бы на имплемент посмотреть как по кристалу размазало проект.
и как я понял файл rtl/top/otpu_slice.sv описывает ядро TPU, могли бы его в проекте(на имплементе) цветом подсветить, хочу оценить относительно общего проекта

Да, всё есть, включая отчёты после implementation, размещение на кристалле и Power Report. Под рукой сейчас только оценка после синтеза .

~58% LUT, ~19% FF

Даже не заглядывая в код по такому соотношению видно, что нужно раскладывать логику в конвейер. 133 МГц для этой ПЛИСки - вообще не частота. Но я так понял, более узкое место - это скорость DDR3, а это лечить уже затратно.

Там эта частота как раз из-за ддр, нет смысла делать больше если всеравно ждать ддр...

Я так понял

Да, пропускная способность DDR3 здесь действительно один из основных ограничивающих факторов.

Такие штуки для майнинга раньше пытались использовать. Поэтому именно 4 ГБ. Производительность на каждый $ железа получалась не очень большая, но энергозатраты чуть меньше, чем у GPU выходили.

А чем скорость ограничена? Конкретно эта FPGA может молотить порядка 1 TMAC/s (если нормально написать прошивку). Но память-то не очень быстрая.

Да, память здесь один из главных ограничивающих факторов. На этой плате два независимых канала DDR3-1066, суммарная теоретическая пропускная способность около 17 ГБ/с. А вот реальная производительность TPU зависит не только от количества DSP, но и от повторного использования данных, организации вычислительного массива и загрузки весов.

Даже если вычислительных ресурсов хватает, их ещё нужно постоянно обеспечивать данными.

Я думаю, что на FPGA лучше всего запускать однобитные модели, скорость должна быть заметно выше. Например попробовать запустить вот это - https://huggingface.co/microsoft/bitnet-b1.58-2B-4T

Статья про них здесь же:
https://habr.com/ru/articles/1030938/

Да, BitNet тоже очень интересен! Правда, в текущем openTPU его поддержки нет, придётся дорабатывать архитектуру и программную часть. Но для FPGA тернарные веса - очень перспективная история, особенно с учётом ограничений по пропускной способности памяти. Запишу себе в список экспериментов, спасибо за наводку :)

Тут больше вопрос не в том, на чём именно запускать локальные LLM, а вопрос цены, т.е. как сделать это дешевле. Если появится в свободном доступе TPU\FPGA, на котором будет выгодно запускать нейросети, то как только эта информация получит распространение, цена на это железо резко пойдёт вверх.

В своё время такое уже было с асиками для майнинга криптовалют, где цена выставлялась в зависимости от предполагаемого срока окупаемости, а не от затрат на производство самого асика.

Так что если TPU\FPGA будут давать схожую с видеокартами производительность, то цены на TPU\FPGA будут примерно такими же.

Да, массовый спрос вполне может повлиять на цены.

4 ток\сек на 4 гб "врама" с moE не выглядят чем-то заоблачным. Немного напомнило майнинг биткоина на esp. Оно и на cpu будет бегать и даже побыстрее. Разве по энергопотреблению и только. Старые нвидия видимокарты типа 1060-6 по цене такие же, но - универсальность. Сегодня llm завтра sd, послезавтра whisper. А еще есть p102 серии с 10 гб честного врама... Нвидию так просто не победить.

Потягаться с зелёными всё-таки попробуем :) Не на этой FPGA за $50, конечно, но большие чипы тоже начинались с прототипов. Да и мне просто в кайф поковыряться: ничто так не успокаивает, как запах прожжённой FPGA.

На секунду подумал, что они все без изоляции, и даже задумался, почему не единая, внушительной толщины, шина... )

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

Да, распознавание образов тоже интересно, согласен. Но мне просто захотелось поковыряться именно в LLM, разобраться, как всё работает на уровне железа, где узкие места и что можно улучшить. Тут скорее интерес к самому процессу, чем попытка сделать что-то практичное за $50 :)

По $50 где вы взяли?

что бы получить адекватный результат, нужно взять от 8! штук (приблизительное количество для 8b квантизации весов и 1 batch, на каждый параллельный поток на kv-cache потребуется дополнительные 8гб на полный контекст и меньше), собрать из них пайплайн (там практически каждая будет связана с двумя соседними, т.е. можно городить только 1к1 интерконнект, это проще и главное быстрее) и получить железку, которая сможет в теории давать в разы (6-8 раз) больше токенов в секунду (к сожалению распределение по чипам по слоям а значит на один поток будет даже медленнее но зато можно распределить до количества чипов)

https://aliexpress.ru/item/1005012750282927.html?sku_id=12000059251410042&spm=a2g2w.productlist.search_results.2.26fd28f8wjlvd3

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

А мне доставку выбивает дороже ПЛИСины…

Каким ИИ Вы пользовались для разработки и в какую сумму обошлись потраченные токены?

Напишите, пожалуйста, полную смету, а не только плату. Или она сразу в комп вставляется и ничего больше не нужно? Программатор там или ещё что-то надо?

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации