download more GPUs
前往频道在 Telegram
Личная помойка Максима Афанасьева
显示更多未指定国家未指定类别
694
订阅者
+824 小时
+127 天
+10930 天
吸引订阅者
九月 '26
九月 '26
+17
在0个频道中
八月 '26
+109
在2个频道中
Get PRO
七月 '26
+26
在0个频道中
Get PRO
六月 '26
+17
在0个频道中
Get PRO
五月 '26
+44
在0个频道中
Get PRO
四月 '26
+19
在0个频道中
Get PRO
三月 '26
+64
在1个频道中
Get PRO
二月 '26
+424
在5个频道中
| 日期 | 订阅者增长 | 提及 | 频道 | |
| 09 九月 | +2 | |||
| 08 九月 | +8 | |||
| 07 九月 | 0 | |||
| 06 九月 | 0 | |||
| 05 九月 | +1 | |||
| 04 九月 | +2 | |||
| 03 九月 | +1 | |||
| 02 九月 | +1 | |||
| 01 九月 | +2 |
频道帖子
btw я чуть-чуть теперь в Лондоне, буду здесь делать разные штуки, если кто-то хочет увидиться - пишите
| 2 | The d9d Project
В июле рассказывал в солнечном Ереване о своём distributed training фреймворке на PyData Pycon Yerevan :) . Вот наконец ребята-организаторы выложили запись, велком смотреть, если интересно!
https://www.youtube.com/watch?v=BGTtk3geHoY | 10 717 |
| 3 | Конец Точковской арки
Где-то в далёком 2021 году я пришел в Точку интерном, только закончив 10 класс школы и выиграв местный хакатон по AutoML. Проработал я там, получается, уже больше 5 лет.
Ну и вот, в конце августа, у меня будет последний день в компании. Ухожу сам, куда и зачем - расскажу позже :)
Как водится, во время таких перемен, хочется подводить разные ретроспективы. Что же я успел сделать за 5 лет? Из недавнего - стал стафф рисерч инженером, собрал свою команду из 20 замечательных человек, сделал Точку одной из немногих ру компаний, у которых есть свои трейны LLM-ов и своя норм DL и Distributed экспертиза, родил большой опенсорс проект. Поиграл в рисёрч. Успел поскакать по доменам - до ЛЛМов я там ASRы с нуля делал, претренил вав2веки2, посттрейнил их, лукалайками позанимался и потренил иерархических бертов.
Что ещё я хочу сказать? Для меня Точка успела стать чем-то достаточно личным, - я познакомился с огромным количеством классных ребят там, с кем до сих пор плотно и дружно общаюсь. Я болел за компанию и хотел, чтобы тот кусок Точки, к которому приложил руку я, оставался тем самым оплотом адекватности на русском рынке, в который крутой чувак может прийти и приносить пользу себе и компании - без нонсенса и буллшита. Получилось ли у меня это сделать - тут уже решать моей команде :) | 1 726 |
| 4 | misis finished 🫡 | 711 |
| 5 | Я иногда здесь пишу про разное не только в ML/AI, но и про другие штуки, которые мне интересны. Сейчас как раз такой случай. Вчера была одна из самых больших атак на Arch User Repository, - пользовательский репозиторий пакетов для дистрибутива Arch Linux. Были инфицированы более чем 1500 пакетов. И как-то эта атака недостаточно хорошо освещена, хотя в ней есть очень много вещей, которым можно поучиться не только пользователям арча, но и маководам, и всем-всем-всем.
Вектор атаки был следующий:
* Челы автоматически просканировали AUR, чтобы найти orphaned пакеты, - пакеты, имеющие такой статус, считаются "ничейными", и любой пользователь может их забрать под свой контроль.
* Атакующие наплодили фейковых учёток, забрали кучу orphaned пакетов под своё управление и выпустили для них вредоносный патч.
* Сам вредоносный патч ставил в систему инфицированный пакет через npm (который наверно уже пора переименовать в mpm - malware package manager)
* Вредоносный npm-пакет дальше делал всю грязь: искал на устройстве ssh-ключи, читал сохранённые в chromium-based браузерах пароли, и много всего разного. Дальше отправлял это куда-то в Интернет.
Это не проблема AUR или Arch Linux. Похожий вектор работает в npm, PyPI, Homebrew, VS Code Marketplace, GitHub Actions. Меняется только экосистема. Так что выводы - для всех. Вот, например, в этом году LiteLLM компроментировали.
Мораль какая:
1. Ставьте как можно меньше всего в вашу хост-систему. Почти весь софт, в том числе клиентский, нужно запускать в нормальных сандбоксах. Если вы пишете код, то вы его потом запускаете где-нибудь в докере, верно? Вот для клиентского софта это тоже актуально. Если пакет есть в Flatpak (актуально почти для всех пакетов), - ставьте его через Flatpak, а затем дополнительно затягивайте ему гайки через Flatseal. Чем меньше прав имеет приложение - тем лучше, тем меньше оно нанесёт вреда, если будет компроментировано. Если вдруг чего-то нет во флатпаке - напишите манифест сами, дайте приложению минимум прав, в этом сейчас вам поможет любой клод код. В идеале в хост-системе должна жить только ваша система (включая десктоп), необходимые драйвера, штуки для запуска всего остального в сандбоксах.
2. Если вы используете AUR - обязательно проверяйте все диффы перед обновлениями любого пакета оттуда. Такую возможность предоставляют каждый AUR Helper - не ленитесь! Разработчики сами настоятельно рекомендуют так делать. AUR всегда был исключительно user-maintained ресурсом, без своей модерации, работающей по принципам "любой может загрузить свой пакет, любой может установить чужой пакет, всё at your own risk". И это в целом работало, ведь по умолчанию просто так поставить пакет из AUR нельзя, нужно вручную зайти в документацию, прочитать что это такое, увидеть красную большую надпись про возможные риски, вручную поставить какой-нибудь пакетный менеджер с доступом до AUR, в общем, отдать отчёт тому, что ты делаешь. Но современные дистрибутивы на базе Arch Linux, такие как CachyOS, решили включать в себя AUR Helpers по умолчанию, поэтому пользователи начали всё чаще воспринимать AUR как какой-то 'базовый минимум, да и чё с ним будет, несколько лет оттуда пакеты ставлю и ничё'. Ну вот, собственно, к чему это и привело. Всегда знайте что вы устанавливаете, откуда, и какой уровень доверия к этому 'откуда'. То же самое относится к PPA в Ubuntu и прочим 3rd party экосистемам.
3. Защищайте SSH-ключи пассфразами, используйте хардварный ключ. YubiKey и пассфраза сможет спасти вас, если даже базу вашего менеджера паролей и ключики сольют, - без физической части паззла они будут просто тыквой. | 1 517 |
| 6 | Летом буду рассказывать про ллмки на английском в Ереване 🤠 | 1 002 |
| 7 | Про zero-centered RMSNorm'ы
Классический RMSNorm инициализирует вектор параметров единичками и применяет его при вычислении так: y = x * w / RMS(x).
Однако в некоторых новых моделях, например, Qwen3.5 и Qwen3-Next, ребята стали делать чуть по-другому, - инициализируют вектор весов нулями, и вычисляют RMSNorm как y = x * (w + 1) / RMS(x).
Мотивация у этого следующая, - теперь можно применять weight decay к этому параметру, и не бояться того, что будет w -> 0, что является очень нежелательным, потому что мы будем "гасить" наш инпут.
Подробнее можно прочитать в блогпосте от чуваков из Ceramic AI: https://www.ceramic.ai/blog/zerocentered
И в репорте Qwen3-Next: https://qwen.ai/blog?id=4074cca80393150c248e508aa62983f9cb7d27cd | 488 |
| 8 | Тем временем в flash-linear-attention появились кернели для context parallelism 👀
https://github.com/fla-org/flash-linear-attention/blob/main/fla/ops/cp/README.md | 513 |
| 9 | Недавно ползал по arxiv'у в поисках малоизвестных работ вокруг распределённого вычисления аттеншона, и вот что нашёл.
Чуваки из Together AI выложили препринт работы Untied Ulysses, включающей доработки в DeepSpeed Ulysses, которые экономят пиковое потребление VRAM.
В классическом Ulysses и вычисления, и коммуникации происходит сразу по всем локальным головам. Untied Ulysses предлагает делать вычисления в несколько шагов по чанкам - сначала считать одну часть локальных голов, потом другую часть, и т.д. Это позволяет сэкономить в том числе на размере буферов для A2A-коммуникаций, которые теперь переиспользуются.
Также авторы отдельно прописали, как их сетап должен работать для Grouped-Query Attention и переиспользовать KV-головы.
Самое главое - все эти доработки действительно несложно реализовать и затестить 🙏.
Читать: https://arxiv.org/abs/2602.21196
Код: https://github.com/togethercomputer/Untied-Ulysses | 978 |
| 10 | - чуваки, мы уже взрослые, давайте пожалуйста больше не будем кидать друг другу юпитер ноутбуки по почте и введём vcs
- | 435 |
| 11 | 🧐 Part II. Джентльменский набор статических анализаторов кода для Python ML проекта
Часто вижу, как кодовая база без жёстких правил превращается в неконсистентное месиво. Часть этого месива позволят не допустить, а ещё и сильно упростят вам жизнь, правильно настроенные статические анализаторы кода. Статья ориентирована в основном на MLE и DS-ов, потому что, товарищи SWE, вы, скорее всего, всё это и так уже 300 раз знаете :) .
В статье, которую я наконец добрался написать, делюсь небольшим стартер-паком статических анализаторов для построения чистого ML-проекта:
* Как Ruff помогает находить антипаттерны
* Почему тайп-чекеры нужны (с примером небольшой грязьки из HuggingFace Transformers)
* Как намертво зашить проверки в pre-commit и CI/CD, чтобы грязный код не улетал в main
🇷🇺 Читать на русском: https://teletype.in/@mrapplexz/0QflVvQcMEY
🇬🇧 Читать на английском (Medium): https://medium.com/p/7ce8bc7d8e87/
🇬🇧 Читать на английском (Substack): https://open.substack.com/pub/mrapplexz/p/bulletproof-your-python-ml-code | 911 |
| 12 | United Ulysses - чуваки из Together AI оптимизировали коммуникации в Ulysses'е | 1 |
| 13 | Немного из моей биографии - ещё до того как заниматься all the AI things, я какое-то время делал библиотеки и тулы для Kotlin Multiplatform. И я до сих пор считаю, что Kotlin - один из самых хорошо задизайненных general purpose языков, жаль, что рынок у него очень узкий вне мобильной разработки.
И вот сейчас заметил, что одна из довольно нишевых старых моих штук собрала 100 звёзд на GH 🫡. Приятно, что какие-то вещи живут даже после того, как ты перестаёшь ими заниматься | 898 |
| 14 | Мой коллега Стас дропнул вот такую имбу
aiofence — библиотека для для удобного cancelling'а вашего асинхронного кода.
https://github.com/stanislaushimovolos/aiofence
Проблема: таска отменилась — это таймаут? клиент отключился? graceful shutdown? Из коробки такая информация не доступна. Кроме того, вы не контроллируете момент прерывания вашего кода — обычно любой CancellError это убийство вашей таски без предупреждения.
Решение: явно объявить и зарегистрировать все источники отмен вашего кода. Отменять только в допустимых точках. Важный код ничего не знает про причины прерывания (пока явно не спросит) — информация о отмене передаётся через контекстные переменные и применяется явно только в определённых блоках вашего кода.
@app.get("/work")
async def handler(fencing: Fencing = Depends(disconnect_fencing)):
await do_work() # не нужно руками прокидывать контекст
async def do_work():
# нет работы с БД - можно смело отменять и не бояться сломанных транзакций
# подхватываем disconnect fencing из контекста
# добвляем отмену по таймауту
with Fencing.current().timeout(30, code="budget").move_on_cancel() as fence:
await expensive_llm_call()
if fence.cancelled_by("disconnect"):
await save_partial_result()
elif fence.cancelled_by("budget"):
await return_cached()
Из коробки — интеграция со Starlette/FastAPI: зависимость disconnect_fencing() автоматически отменяет код при отключении клиента. Комбинируется с таймаутами, другими событиями и кастомными триггерами — всё в одном контекстном менеджере. | 1 034 |
| 15 | 🐞 Как я баги в PyTorch находил
Иногда кажется, что вероятность найти баг в каком-то очень большом инструменте, где куча контрибьюторов из Калифорнии на зепешке, стремится к нулю. Но нет, достаточно просто начать пользоваться каким-то нишевым функционалом 💅.
1️⃣ Первую проблему я нашёл ещё в конце октября прошлого года, когда экспериментировал с пайплайнингом (да, я люблю пайплайны, зовите меня Марио). Суть в чём - у ребят движок для прокрутки пайплайна ломался при использовании zero-bubble schedule (что это такое - читайте предыдущий пост) и модельки, в которой были кастомные autograd-операции. Если поглубже поразбираться, то суть там была в том, что у ребят высвобождались из памяти ещё нужные узлы графа перед backward pass до весов модели (читайте про zb schedules), и из-за чего автоград просто не мог посчитать градиенты. В целом, проблема верхнеуровневая, я её нашёл, зарепортил, но дальше особо не следил за статусом, т.к. ушёл писать свой pipelining-движок, в котором этой проблемы не было, поэтому сей issue меня не блокировал. Сейчас ребята вроде докатывают какие-то изменения, которые это порешают. Но issue всё ещё открыт.
2️⃣ А вот вторую проблему я нашёл совсем недавно, и она мне очень нравится! Это довольно низкоуровневая хрень в автограде, которая вроде не особо влияет на работоспособность, однако влияет на производительность. В чём суть - когда мы пишем кастомные автоград-операции, мы часто делаем проверки вида ctx.needs_input_grad[EDGE], чтобы узнать, нужно ли считать градиент по указанному направлению. Это нужно, чтобы не считать градиент, например, до весов модели, если его считать не нужно, - если мы сделали param.requires_grad = False или если мы делаем разделенный dInput / dWeight backward pass (читайте про zb schedules). Ну дак вот, эти проверки работают корректно для первого сценария с отключенным requires_grad, но работают некорректно (всегда возвращают True) для второго сценария. Из-за чего, когда мы пытаемся сделать split backward для таких вот autograd операций, мы во время dInput считаем градиент и по входам, и по параметрам, а затем во время dWeight - считаем градиент по параметрам ещё раз. Делаем двойную работу. Не то что мы хотим, верно? Что самое интересное, ребята из DeepSeek когда делали свой DualPipe zero-bubble schedule, они эту проблему тоже нашли, но судя по всему не зарепортили, и закрыли костылём на своём уровне (держат global объект, который управляет состоянием dI/dW). В моём трейн фреймворке тоже есть похожий костыль, но я, на мой скромный взгляд, всё-таки сделал его чуть чище и понятнее для восприятия. В общем, я эту проблему сам посидел порасследовал, зарепортил ребятам, и в проекте уже даже висит PR от одного из мейнтейнеров автограда, в котором эта проблема исправляется. Оперативно!
❓ Чему это нас учит?
Да в общем-то довольно очевидным вещам:
* даже в очень крупных проектах могут быть какие-то проблемы, которые возникают в различных (не)стандартных сценариях использования;
* не скупитесь репортить issues, самостоятельно проводить расследование и хорошо описывать результат - часто хорошо зарепорченные проблемы действительно решаются за довольно короткие сроки. | 1 068 |
| 16 | А напишите пж в комменты, какой контент вы бы хотели видеть в канале, - про инженерку, разборы актуальных статей, мемы, мб что-то ещё? | 806 |
| 17 | Совсем недавно ребята из Z.ai опубликовали техрепорт GLM-5. Что из важного можно сказать об их трейн инфре:
* Всё делалось на китайских чипах, - чуваки проделали большую работу чтобы адаптировать различные существующие GPU-кернелы под них. Партия довольна.
* Используют Pipeline Parallelism, - это когда модель делится на кусочки вертикально, и каждый PP-ранг обладает срезом слоёв всей модели. Пайплайнинг очень вкусный для 'распила' больших моделей по серверам, - ведь все коммуникации являются P2P, и передаются только hidden states. Но не всё так просто, - основной челлендж с пайплайнингом - это минимизация bubbles - отрезков времени, когда какие-то воркеры простаивают, ожидая, результат воркера-соседа. Существуют разные schedules (расписания), одни предоставляют время простоя меньше, другие - больше.
* Самые новые расписания для PP - это так называемые Zero Bubble Schedules, и именно такой используют авторы. ZB характерны тем, что классический backward pass разделяется на два этапа - первый этап делает backward исключительно до входов в pipeline stage, а второй делает backward до параметров модели. Это работает, т.к. для того чтобы запустить backward в ранге-соседе, нам нужно лишь досчитать первый этап, а второй этап можно посчитать когда-нибудь позже. Это позволяет минимизировать простой. Единственное, что не сказали, - zero-bubble расписаний существует много разных, - есть ZBV, есть 1F1B с ZB, есть дипсиковские DualPipe и DualPipeV. Подозреваю (напишите в комментах, если кто-то знает точно), что таки использовался 1F1B с ZB, т.к. авторы упоминают термин pipeline warmup, который характерен для него.
* В статье мелькает Data Parallelism, его тоже используют.
* Т.к. модели - MoE, то предполагаю, что Expert Parallelism тоже есть. Но в статье про него написано только в секции про инференс. В трейне никаких подробностей. Подробно писать про EP не буду, иначе пост не влезет в лимит тг 😭.
* Для длинных последовательностей используют Context Parallelism, не говорят какой конкретно, но судя по тому какие работы цитируют, похоже, что используют что-то Ulysses-style. Это когда мы делим последовательность по CP-рангам, перед вычислением SDPA делаем All2All коммуникацию, считаем разные attention-головы на разных рангах, потом снова раскидываем результаты через All2All. Чтобы паковать батчи, опять же, судя по цитате, - используют китайский планировщик FlexSP.
* Напихали разных стандартных и не очень штук для экономии памяти. Из важного - шардируют градиенты как в ZeRO2, выгружают ненужные активации в RAM во время выполнения пайплайнга, считают кроссэнтропию не для всей последовательности сразу, а по чанкам (как было, например, в Liger Kernel), используют оптимизированную реализацию оптимизатора Muon.
PS: Полностью репорт можно прочитать здесь, в своей краткой выжимке я описал далеко не всё.
PPS: Если кому интересно почитать более-менее чистую (at least I believe so) имплементацию пайплайнинга и современных скедулей - можно глянуть в моём трен фремворке: user api дока , дока по реализации, код. Сам фреймворк еще не готов к релизу, я позже буду делать большой анонс, как доедут фичи, которые хотим к 1.0 доделать и как мы ещё шушуть его побатлтестим. | 969 |
| 18 | Короткий пример RFC: https://gist.github.com/mrapplexz/045c2ec9a1f202dc4311a00d3dd628dd | 711 |
| 19 | 🤔 Part I. Как принимать технические решения?
Часто в работе приходится принимать какие-то решения: как должна выглядеть архитектура проекта, какую метрику измерять, как сделать интерфейс forward(...) у кусочка модельки, чтобы его можно было легко поменять. И причём самое противное, - эти решения не принять экспериментальным путём, в отличие от, скажем, выбора лосса.
Обычно это происходит так: созвонились в Зуме или перетёрли в Слаке, решили «а давай сделаем вот так, вроде норм» и побежали писать код. Спустя полгода приходит новый человек (или вы сами возвращаетесь к проекту) и думаете: «А чё, почему мы так сделали?», и ничего не можете вспомнить, бегаете по слак-тредам в попытках найти правду, или запускаете весь мыслительный процесс заново. Или ещё хуже, если вдруг вам нужно доработать какую-то штуку, и вы не просто не можете что-то вспомнить, а упёрлись в ограничения своей реализации, и думаете «блин, а почему я норм не продумал это раньше». Или вы решаете какую-то задачку, а потом на код-ревью выясняется что вы всё сделали неправильно и приходится переделывать. Больно, страшно, печально. Но у всех перечисленных кейсов есть что-то общее: решения в них принимались непрозрачно и неявно.
Чтобы такого не было, люди придумали писать RFC и ADR. Основная идея этих штук - давайте думать прежде чем делать, а также формализовывать процесс нашего "думания" в виде текстовых документов.
📢 RFC (Request for Comments) — для стратегии и валидации идей
Это когда вы хотите внедрить что-то большое, что затронет много людей или изменит процесс работы глобально.
Цель: Собрать фидбек, найти "unknown unknowns", убедить людей.
Механика: Нам нужно, чтобы большинство согласилось, что идея норм. Иногда это может быть долгий процесс.
Примеры:
* «Давайте переедем с PyTorch на JAX» (затронет всех, нужно много обсуждений).
* «Внедряем Feature Store для шаринга фичей между командами поиска и реков» (большая идея, тоже нужно много обсуждений).
🏗 ADR (Architecture Decision Record) — для тактики и фиксации решений
Это инструмент команды. ADR создается, когда нужно принять конкретное техническое решение быстро. У ADR тоже есть стадия Draft/In Discussion.
Цель: Зафиксировать контекст и получить «добро» от тех, кого это касается напрямую.
Механика: Вопрос ставится в формате «Я предлагаю решение Х. Есть ли серьезные возражения (blockers)? Если нет — принимаем».
Примеры:
* «Используем Pydantic для валидации конфигов обучения».
* «Для сервиса X мы конвертируем веса в ONNX».
⚔️ RFC vs ADR: А в чём таки разница?
Это, наверное, спорный топик, и главное - это концепция «я сначала подумал, обсудил, а потом сделал», однако я привык к такому разделению:
* Масштаб: RFC — про идеи и влияние на многих. ADR — про реализацию и контекст внутри команды.
* Скорость: RFC может висеть неделями. ADR должен пролетать быстро.
* Результат: Принятый RFC часто рождает пачку конкретных ADR-ов о том, как именно мы это сделаем. Принятый ADR рождает уже конкретные задачи что-то сделать.
😭 Дак зачем это MLE?
Это понятный и прозрачный лог принятия решений в проекте, который упростит онбординг новичков и что-то подзабывших вас самих же.
ADR и RFC заставляют вас прийти к какому-то консенсусу с другими участниками команды заранее, существенно уменьшая количество недопонимания (как с вашей, так и с чужой стороны) во время реализации. Эти подходы провоцируют вас думать и заведомо принимать более хорошие и устойчивые решения, защищая от «да фиг с ним, го так, потом если чё поменяем». Это замечательный способ защититься от «синдрома вечного ресёрча». RFC/ADR ставит точку: «Мы исследовали 3 варианта, выбрали этот, тема закрыта. Двигаемся дальше». А ещё! Вы можете скормить свой ADR клод коду, и он с большей вероятностью сделает хорошо.
🚀 Как начать?
Не усложняйте. Если изменение большое и страшное — пишите RFC в Google доках/Notion, и кидайте ссылку на всех в каком-нибудь мессенджере, иногда созванивайтесь, чтобы какие-то совсем спорные и животрепещущие штуки закрыть. Если локальное — делайте Markdown файл прям в репозитории, отправляйте его в Pull Request, там же обсуждайте. | 702 |
| 20 | ⚙️ Инженерные подходы в ML-проектах.
❓Зачем нужна эта серия постов?
В сообществе, причём как в русскоязычном, так и в англоязычном, довольно много освещается то, как делать ML/AI/LLM/DL/any-other-buzzwordish-abbreviation-проекты быстро и какие новые штуки в них внедрить, однако почти не освещается то, как делать эти проекты с нацеленностью на поддерживаемость и "понятность". То, о чём я буду писать, наверное, лютая база для софтвейр инженеров, но, предполагаю, что мои посты принесут пользу для ребят из ML, которые меньше сталкивались с подобным. | 550 |
