Марков цепи пропил
2.64K subscribers
209 photos
30 videos
1 file
69 links
Download Telegram
В скором времени либо отъеду в дурку от поиска потерянного @(posedge clk), либо накачу пару длиннопостов
💅33👻1
Hm, okay
🕊32🤡1👻1
Red eyes is all you need, или пихаем LLM в FPGA

Вдохновился недавней новостью, о том, что LLM зашили в железо, и решил попробовать повторить в меньших масштабах, написав проект на verilog, где ~854K модель зашивается в Artix-7 (XC7A200T). Задачей было уложиться в бюджет 365 BRAM блоков (потому что я слишком нищий для более серьезной борды), поэтому была выбрана архитектура с 128 embedding dim, 8 attn heads, 4 слоя, и размером контекста 256. Оно упирается как раз впритык - веса заняли 209 блоков, KV-кэш - ещё 128.

Из интересного - веса/активации находятся сразу в BRAM в int8, разбиваясь на отдельные файлы через extract_weights.py (LayerNorm’ы пихаются в один файл, так как они мелкие и тратить по блоку на каждый из них - слишком дорого). Попутно генерируется weight_scales.vh, чтобы в рантайме адекватно перевести все это в fp16 для активаций.

Для Softmax и sqrt(1/x) использовал статью, которую вкратце описал выше [тык]

GELU был реализован по этой статье [ссылка]: erf аппроксимируется кусочно-линейной функцией, используя нечётную симметрию erf(-x) = -erf(x), что вдвое сокращает область аппроксимации. Breakpoints ищутся через EPSS (Error Peak Search Strategy) - это итеративный алгоритм: на каждом шаге находит локальные максимумы ошибки аппроксимации внутри каждого сегмента через argrelextrema и вставляет туда новые breakpoints. В результате breakpoints концентрируются там где erf кривее (около нуля) и разреживаются на плоском хвосте.

На данном этапе проект доведен до полной RTL-симуляции: есть тесты сравнения идеальных операций в ideal_ops.py, RTL операций на питоне rtl_ops.py (pure-python fp16-примитивы, которые воспроизводят поведение RTL бит-в-бит, включая rounding и flush-to-zero) и сравнение полученных результатов из xsim. В принципе transformer_top.v выдает что-то похожее на когерентный текст в симуляциях, и осталось только дописать поддержку temperature, top-k и т.п., а также интерфейсы для самой железки. В дальнейшем, наверное, напишу еще один пост про результаты и оптимизации (потенциально можно улучшить скорость инференса, если распараллелить операции с плавающей точкой)

Поковырять исходники можно здесь [тык]
🔥427👻1🗿1
💊173😱2👻1
Максимально проклято
😁125👻2
Марков цепи пропил
Максимально проклято
С огромной долей вероятности оно все сведется к +/- этому
11👻2
iCTS: Iterative and Hierarchical Clock Tree Synthesis With Skew-Latency-Load Tree [ссылка]

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

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

Но "одновременно" физически невозможно. Сигнал идёт от одного источника до тысяч триггеров по металлическим проводам с сопротивлением и емкостью, разные триггеры находятся на разном расстоянии, и сигнал приходит в разное время (эта разница называется skew).

Решение - буферы. Они восстанавливают деградировавший фронт и добавляют контролируемую задержку, и если вставить буферы в нужных точках сети, суммарная задержка по всем путям выравнивается и каждый триггер получает фронт в +/- одно и то же время. Собственно, автоматическое построение такого дерева буферов и называется Clock Tree Synthesis.

Звучит как инженерная задача с однозначным решением, но внутри три цели, которые конфликтуют между собой: минимальный skew, минимальная длина проводов и минимальная latency. Получить всё три одновременно - NP-hard.

Стандартный CTS flow разбит на два независимых шага без обратной связи: сначала DME (алгоритм балансировки топологии тактового дерева) фиксирует структуру дерева: где провода соединяются и как ветвятся. Потом отдельный алгоритм (как правило, ван Гинекен) вставляет буферы уже в готовую структуру: обходит дерево снизу вверх, в каждом узле оценивает варианты буферов с учётом ёмкостной нагрузки downstream и выбирает лучший. Топологию изменить уже нельзя, поэтому алгоритм подстраивается под то, что есть.

Чтобы выровнять задержки на коротких ветках, DME добавляет wire elongations - буквально удлиняет провода змейкой, из-за чего растёт ёмкость и мощность. Буферы потом сайзятся под худший случай нагрузки, часто избыточно.

И это бьёт не только по мощности. Буферы занимают площадь кристалла, тактовые провода съедают ресурсы роутинга, рядом с кластерами буферов нужны decap-ячейки. Место, которое могло быть вычислениями, занято инфраструктурой доставки сигнала.

Тактовое дерево переключается каждый такт, независимо от того что делает логика. На высокопроизводительных процессорах это может отъедать до 50% от TDP, то есть если чип греется на 100 Вт, то до 50 Вт уходит только на доставку тактового сигнала, а не на вычисления (пара статей про это - [тык], [тык], [тык])

Исследователи из CUHK и Pengcheng Lab предложили строить топологию и буферизацию одновременно с явным trade-off между skew, latency и wirelength. В классическом DME точка слияния двух поддеревьев единственная, где задержки выравниваются, и никакого выбора нет. iCTS расширяет это до отрезка допустимых точек слияния, где любая точка даёт skew в пределах заданной границы, и на этом отрезке алгоритм выбирает точку, минимизирующую сумму с явными весами для latency и wirelength.

Поверх этого иерархическая кластеризация группирует синки не по геометрической близости, а по ёмкостной нагрузке, потому что физически близкие синки могут нагружать дерево по-разному и ломать балансировку. Результат кластеризации дополнительно оптимизируется отжигом. Буферы оцениваются до вставки, что позволяет отсекать плохие варианты раньше. После буферизации ISCA итеративно перезапускает BST-DME на зафиксированной топологии, каждый раз уточняя оценки задержек, пока skew не достигает целевого значения.

На бенчмарках ISCAS'89, OpenLane, OpenCores и ysyx (от 1248 до 22810 flip-flop) при 28nm результат такой: коммерческий P&R инструмент проигрывает iCTS на 39.5% по skew, 13.0% по latency и 18.5% по capacitance, OpenROAD - на 101.6%, 50.7% и 25.5% соответственно. По clock power коммерческий инструмент потребляет в среднем на 32% больше, OpenROAD - на 81% больше.

Хоть в максимальном бенчмарке всего ~23к триггеров, иерархическая архитектура iCTS должна масштабироваться. Не знаю, применит ли это кто-нибудь в продакшене, но звучит многообещающе
🔥106👌1👻1
разработчик мессенджера Max может добиться эрекции только когда его жена грязно шепчет ему на ухо, что выбрала его, только потому что все другие мужики, которые её реально возбуждали, оказались недоступны, а не потому что она типа его реально любит и хочет
😁48🤡4🙏3👻211
This media is not supported in your browser
VIEW IN TELEGRAM
Прикольное (хоть и не понимаю, для чего оно существует)

https://vail-ucla.github.io/JOSH/
5😁1👌1
Simple Recipe Works: Vision-Language-Action Models are Natural Continual Learners with Reinforcement Learning [ссылка]

Tldr: челы решили проверить, есть ли смысл в существующих методах Continual RL для обучения роботов, или можно обойтись простым Sequential Fine-Tuning с LoRA и on-policy RL.

Большие VLA-модели вроде OpenVLA или Pi-0 хорошо обобщаются, но ломаются при деплое в меняющейся среде. Чтобы агент мог адаптироваться к новым задачам через взаимодействие со средой, его нужно дообучать с RL постепенно, не имея доступа к данным предыдущих задач. Но есть проблема: Sequential Fine-Tuning в такой постановке ведёт к катастрофическому забыванию, модель переобучается на текущей задаче и теряет навыки предыдущих.

Существующие методы Continual RL решают это тремя способами: регуляризацией весов (EWC штрафует обновления параметров, важных для прошлых задач), воспроизведением прошлого опыта (Expert Replay и Dark Experience Replay хранят демонстрации или логиты и перемешивают их с текущим обучением) и изоляцией параметров (Dynamic Weight Expansion выделяет отдельный LoRA-адаптер на каждую задачу). Для больших моделей есть и более свежие подходы: SLCA применяет разные learning rate для разных слоёв, RETAIN после каждой задачи вмёрживает веса обратно в базовую модель с коэффициентом дисконтирования.

Авторы берут простейший Seq. FT с LoRA и GRPO и гоняют его вместе со всеми перечисленными методами на трёх VLA-моделях (OpenVLA-OFT, OpenVLA, Pi-0) и пяти бенчмарках (LIBERO-Object, LIBERO-Spatial, LIBERO-Long, RoboCasa, ManiSkill). И в результате Seq. FT с LoRA и GRPO выигрывает или не уступает во всех сетапах, при этом падение успешности на прошлых задачах меньше 2%, нередко уходя в минус, то есть обучение на новых задачах ещё и улучшает старые. EWC, SLCA и RETAIN хуже учатся новым задачам - ограничения на обновления параметров мешают не только забывать старое, но и усваивать новое, поэтому итоговый avg ниже. DWE вообще не получает transfer между задачами. Replay требует хранить демонстрации и при этом ничего не выигрывает. Zero-shot на незнакомых задачах у Seq. FT в большинстве сетапов не уступает модели, обученной сразу на всех задачах одновременно, то есть верхней границе качества. А там, где Seq. FT всё же отстаёт, хватает просто подольше потренировать слабые задачи.

Авторы объясняют это синергией трёх вещей. On-policy RL неявно удерживает политику близко к базовой, потому что обновления не могут сдвинуть вероятностную массу туда, где базовая политика почти не имеет поддержки. Большой размер модели помогает потому, что в пространстве миллиардов параметров обновление по новой задаче почти не затрагивает направления, важные для предыдущих. LoRA не даёт отдельным слоям переписываться полностью, при этом пластичность не страдает: on-policy обучение при разреженном вознаграждении информационно дёшево, и ёмкости адаптера хватает.

Пока все эксперименты проводились в симуляции. Решат ли авторы главную проблему RL - он не работает плохую масштабируемость в реальных средах, пока неизвестно. Но понаблюдать за развитием можно здесь [тык]
3👻11
Авторесерч, который мы заслужили

https://github.com/karpathy/autoresearch/blob/master/progress.png
🔥11😁42😱1👻1
Dial-up 2.0, или гоним трафик в обход белых списков через звонки в ВК

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

VK-звонки работают через WebRTC с Selective Forwarding Unit, который пробрасывает SCTP DataChannel между участниками, не заглядывая внутрь. Помимо своего animoji-канала (id:1) VK туда ничего больше не кладёт, поэтому можно создать рядом свой DataChannel (id:2) и использовать его как двунаправленный пайп для произвольных данных. Весь трафик при этом идёт через TURN-серверы VK, которые находятся в белых списках - для DPI это выглядит как обычный звонок.

На стороне Creator'а (тот, у кого есть доступ в интернет) запускается Go relay и hook.js сниппет в браузере. Сниппет хукает RTCPeerConnection, перехватывает ICE-конфигурацию прямо из конструктора, после чего создаётся туннельный DataChannel и бриджится с локальным WebSocket'ом, через который relay раздаёт трафик наружу.

На стороне Joiner'а (тот, кто в зоне белых списков) всё чуть интереснее. Приложение открывает VK-звонок в WebView, поднимает VpnService, который перехватывает весь IP-трафик устройства, прогоняет его через tun2socks, дальше в SOCKS5 прокси на Go, и уже оттуда через WebSocket в тот же DataChannel. Go-часть собирается через gomobile в .aar и линкуется прямо в APK, поэтому можно обойтись без рута/termux.
На speed test получилось добиться 9.57 Мбит/с на скачивание, 4.15 Мбит/с на загрузку с задержкой 14 мс до Брюсселя с мобильной сети.

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

Код/билды здесь [тык]
419🔥14026😁9👻3🦄1