Telegram Group Search
Forwarded from rizzearch
ADOPT: Modified Adam Can Converge with Any β2 with the Optimal Rate

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

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

но вот авторы-японцы (возможно) смогли это исправить и нескромно назвали метод ADaptive gradient method with the OPTimal convergence rate

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

по экспам где-то даже резы лучше достигаются - в том числе и на 7б лламе прогоняли (правда только ммлу, как любит замечать наш дорогой друг, без алаймент бенчмарков это не особо релевантно) + для мниста и цифара брали только резнет-18 но допууууустим

к тому же тут есть тоже предположение в их теории - о том что второй момент градиентов ограничен (менее сильное предположение в сравнении с предыдущим о том, что первый момент тож ограничен)

позабавило еще то, что в вывод в конце они зачем-то решили вставить проблему социального импакта мл алгоритмов (хотя статья чисто про оптимизатор)

а код оч классный, челики с сурс коде торча знатно так разбираются

👀LINK
🔬 Новые концепции в бенчмарках LLM

В моей голове уже давно существует большое количество сомнений по поводу честности, правильности и полезности существующих классических бенчмарков, вроде MMLU, GSM8k и других, впрочем и онлайновая Chatbot арена с человеческими оценками меня тоже по многим причинам смущает. Но сейчас не хочется спекулировать о том, что существует какой-то кризис в оценке LLM (по крайней мере в публичных бенчмарках), а хочется поговорить о том, что исследователи с этим пытаются делать и получается довольно интересно.

WIldBench и ArenaHard

Оба бенчмарка представляют из себя комплексный подход к оценке ответов одной LLM с помощью Chain-of-Thought размышлений другой LLM. Каждый делает акцент на реальных и сложных пользовательских инструкциях, первый содержит 1к, а второй 500 задач. WildBench от AllenAI в отличие от ArenaHard старается оценивать модели по зафиксированному чек-листу в равномерной разбивке по навыкам, также он считает как Pairwise скоры (против бейзлайна) так и Individual (с оценкой от 1 до 10 на подобии MT-Bench).

В целом, WildBench можно считать примером очень хорошего и полностью автоматизированного бенчмарка. Однако даже подобные усилия не дают всегда справедливую оценку, так как зависят от сложности инструкций, ответа-бейзлайна, промпта самой оценки, а также стиля (что я не считаю чем-то плохим) и длины ответов (что уже более сомнительно). Но все же, эти методы дают куда более приближенную к реальности оценку чем MMLU, так как требуют от моделей высокое качество осмысленных генераций в целом.

MMLU-Redux и загадка порядка ответов

Авторы статьи с говорящим названием “Are We Done with MMLU?” решили плотно пройтись с человеческими экспертами по MMLU и выявить, что в некоторых областях вопросы были плохо составлены, а ответы либо неоднозначны, либо и вовсе неправильны, как например в Virology, где из оригинального датасета больше половины ответов оказалось неверной. Они представили сабсет MMLU-Redux из 30 областей по 100 исправленных в ручную вопросов и ответов. Интересным стало то, что качество моделей на исправленных доменах возросло и довольно сильно, а также то, что ни одна LLM не справляется с задачей поиска сломанных вопросов, лучше всех это получается у Claude 3 Opus с 41 F1-Score.

Кроме того, исследователи из FAIR в недавней статье “Changing Answer Order Can Decrease MMLU Accuracy” показали, что изменение порядка выбора мультичойс ответа в промпте приводит к довольно сильному дропу перформанса до 40%, который отличается от модели к модели, что вполне может быть индикатором обмана LLM вендоров на метрики…

ZebraLogic

Снова исследователи из AllenAI порадовали и решили автоматизировать оценку логических способностей LLM предложив им разбираться в так называемой задаче Эйнштейна (он же Zebra Puzzle). Головоломка состоит в наборе стейтментов о жителях домов и некоторых их характеристиках, ответом является таблица с распределением кто в каком доме живет и кому что принадлежит. Можно генерировать такие задачи с разным количеством условий, варьируя сложность раскручивания. Для оценок LLM они форсируют ее подумать (это не CoT) и отвечать в формате JSON возвращая построчное описание таблицы. Синтетическая природа такого бенчмарка не дает заранее на нем обучится и позволяет генерировать задачи при желании почти бесконечной логической сложности.

ZeroEval

Совсем новый бенчмарк, еще даже поста нет, но это обобщение подхода ZebraLogic от тех же создателей, но на более общие классические задачи (MMLU-Redux, CRUX, MATH Lvl 5, GSM8k). Обобщение заключается в Zero-Shot подходе, где от моделей требуют принудительный ризонинг, через структурированные ответы в формате JSON, что на мой взгляд является более простой и полезной формой бенчмарка чем стандартный lm-eval-harness. Лидерборд ZeroEval же дает неплохое представление о тех моделях, которые вероятно могли использовать MMLU в своем обучении, при этом имея слабые размышляющие способности, например к таким можно отнести Qwen2.5 и Gemma2, но чем больше модель тем меньше она поддается такому эффекту.
Вслед за постом от @fminxyz. Удобный сайт для наблюдения за ICLR 2025 и лучшими статьями, потом обязательно разберу из топа то что понравится:

https://papercopilot.com/statistics/iclr-statistics/iclr-2025-statistics/
Please open Telegram to view this post
VIEW IN TELEGRAM
Добавили новые модели от T-Tech в репозиторий на github Ru General Arena.

Напомню, что тут бейзлайн это все еще gpt-3.5-turbo-0125, а судья gpt-4-1106-preview, промпты засепмлпены по 50 разным топикам (т.е. и сложные и просптые вперемешку).

Интересно, то что по метрикам которые репортит T-Tech в своем посте на хабре, вихрь немо стоит довольно низко в лидерборде, в отличие от их моделек. Мое мнение если кратко: в текущей ситуации сранивать что-то довольно сложно, так как квены изначально довольно оверфитнутые на многие классические бенчмарки, переведенные промпты AlpacaEval и ArenaHard это конечно хорошо, но под них уже много кто заоферфитился на английском и без изменений промптов оценки результаты на русском могут выходить как минимум неоднозначные, что и показывает большое количество сильных шейкапов между зарепорчеными авторами бенчмарками.

В целом, мне кажется, что таблица на скрине отображает мое понимание, но объективная реальность думаю всегда где-то посередине...
Forwarded from Душный NLP
Технический отчёт Qwen2.5

Создатели линейки языковых моделей Qwen2.5 представили технический отчёт. Вот что мы из него узнали.

Претрейн

На претрейне использовали датасет объёмом 18 триллионов токенов против 7 триллионов у Qwen 2. В частности, были данные, применявшиеся для обучения Qwen2.5-Math и Qwen2.5-Coder, что позволило улучшить результаты модели в вопросах, связанных с математикой и программированием. Также применяли синтетические данные, сгенерированные Qwen2. Scaling laws использовали для предсказания оптимальных гиперпараметров — например, для learning rate или вычисления размера батча.

Во время первой фазы претрейна длина контекста составляла 4096 токенов, а на второй и финальной — 32 768 токенов для всех моделей семейства, кроме Qwen2.5-Turbo. В её случае претрейн проходил в четыре этапа, начинаясь с 32 768 токенов и заканчивая 262 144 токенами. В каждой фазе претрейна Qwen2.5-Turbo максимального значения достигали только 40% данных, а остальные были короче. По словам авторов, это позволило модели плавно адаптироваться к новой длине контекста.

Благодаря стратегиям YaRN и Dual Chunk Attention удалось увеличить максимальную длину обрабатываемой на инференсе последовательности в четыре раза: до миллиона токенов у Qwen2.5-Turbo и до 131 072 токенов у других версий.

Алаймент

SFT-датасет состоял из более чем миллиона примеров. Длина выхода Qwen2.5 — 8192 токена, в то время как обычно она составляет менее 2000. Улучшения удалось добиться благодаря наборам данных для длинных ответов. Разработчики использовали back-translation, чтобы генерировать запросы на основе данных для предварительного обучения, ограничивали длину выхода и отфильтровывали низкокачественные пары с помощью Qwen2.

Для задач, связанных с математикой, использовали CoT-данные из Qwen2.5-Math. Кроме того, применяли rejection sampling вместе с размеченными данными и моделью награды для пошагового рассуждения. Что касается генерации кода, то здесь было несколько агентов и пары инструкций на примерно 40 языках программирования.

В части instruction following модели генерировали инструкции, проверочные коды и юнит-тесты для перекрёстной проверки. Это позволило LLM лучше следовать промптам. А благодаря внедрению цепочек рассуждений в ответы, Qwen2.5 стала лучше извлекать информацию из структурированных данных — например, таблиц.

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

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

На этапе DPO в качестве позитивных примеров использовали хорошие ответы с SFT. Те же, которые не прошли проверку на SFT, стали негативными примерами.

Для создания датасета задействовали как автоматические, так и ручные методы оценки. В итоге получился набор данных из 150 тысяч пар. Qwen2.5 обучалась на нём в течение одной эпохи с применением Online Merging Optimizer c learning rate 7 × 10⁻⁷.

Reward-модель тренировали на двух наборах данных: общедоступном и проприетарном, содержащем запросы со сложной структурой. Ответы генерировались с чекпоинтов Qwen-моделей, прошедших файнтюнинг разными методами (SFT, DPO, RL), и при разных температурах. Для онлайн-обучения с подкреплением применяли Group Relative Policy Optimization (GRPO) с набором, аналогичным тому, что был на этапе RL. Для каждого запроса отбирали по 8 ответов.

Душный NLP
42-ух минутный доклад с NeurIPS 2024 об основных конкурентах архитектуры трансформера

Вам в очень энергичной манере поведают:

- В чем логика заменять трансформер
- Общий таймлайн развития альтернативных архитектур с 2020 года и причем тут LSTM
- Что же там в итоге с линейным атеншеном в 2024том
- Кто же этот такой ваш RWKV, кто за ним стоит и почему он не хочет умирать в 2025том
- Как быть отчаяным ресерчером и в одиночку успешно линеаризовывать opensource LLM без собственного претрейна
- Что еще случилось за год (Jamba, Sana, DNA Models и что еще нас ждет

Смотреть на Ютубе
Про нашумевший Titans или как не оказаться в Платоновской пещере

Недавно вышла статья от ребят из Google Research и очень сильно завирусилась, сначала на реддите и в твиттере, а потом и в общественных СМИ и куче телеграмм каналов. Большинство заголовков о ней содержат что-то вроде: "Transformer 2.0", "преемник трансформера" или вобще "убийца трансформера" (особенно тут забавно, что трансформер в гугле то и придумали),

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

Во-первых это не революция, и идея далеко не новая, достаточно просто посмотреть с чем авторы сравниваются в самой работе. Среди кучи разных модификаций линейного атеншена, можно обнаружить TTT (Test-Time Training) - то, что на этом канале уже обсуждалось, но под призмой решения ARC-AGI. Сами авторы говорят, что их решение довольно сильно похоже по концепции на это (modern linear recurrent models with a gradient-based updating rule), но содержит некоторые новвоведения связанные с ручным forgeting механизмом, а также что их Neural Memory (LMM) можно воспринимать еще и как генерализацию Gated DeltaNet. Подробнее про сравнение можно прочитать в аппендиксе в части C.

Я же хочу сказать, что тут упускается бэкграунд происходящего, большинство моделей с которыми авторы сравниваются работают в парадигме линейного атеншена и его проблем в задачах требующих in-context retrieval, поэтому такие архитектуры как DeltaNet, Hyena, Mamba-2 пытаются разными путями улучшить этот аспект. Здесь речь идет только о работе с обычными последовательностями и не всегда даже длинными, даже не о внешней памяти напрямую.

Теперь вернемся к TTT, сами авторы же называют свое решение LMM "a meta in-context learner, learns to memorize at test time", что обозначает тоже самое, что и в концепции TTT, с разницой лишь в том, что в LMM есть weight decay и momentum при тренировке памяти. Важно, что речь идет именно о inference-time тренировке, тоесть решение авторов это даже не архитектура, а способ внедрения TTT более хитрыми путями, например через добавление хиденов памяти в контекст атеншена. Сама по себе же разработка не призвана улучшить какие-либо способности трансформера как такового, ее единственная цель это увеличение контекста до 2M токенов за счет inference-time тренировки. Это и есть самое важное в этой работе, все остальное, что приписывают Titans (убийца трансформера и тд) находится на грани с бредом.

На мой взгляд, при очевидных возможных плюсах такого подхода, статья содержит ряд существенных минусов. Во-первых ее просто сложно читать, а во-вторых сам по себе внешний механизм нелинейной памяти обучаемый во время инференса очень неоднозначен с точки зрения способностей моделей и ее алайнмента, о чем в статье не говорится ни слова. То есть очевидно, что такая память, вполне способна повлиять на поведение модели на инференсе самым непредсказуемым образом, и к задачам RAG в обычном пользовательском варианте она врятли пригодна. Но в ARC-AGI мы уже видели успешное использование TTT, правда там речь шла совсем не о памяти, а о LoRA адаптере, который учился для каждого примера отдельно на инференсе на его few-shot примерах. Такой же способ можно воспринимать и как вариант памяти, если учить только ассоциативные KV матрицы или MLP, для меня это еще один минус, что авторы не рассмотрели нечто подобное.

Вобще, в контексте выхода интересного трансформера от Minimax, все это уже кажется устаревшим еще вчера, так как в Minimax показано как эффективная связка Lightning Attention (вариация линейного) и обычного softmax attention дает возможность тренироваться на контекстах до 1M и скейлится до 4M на инференсе, при этом имея лучшие скоры на RULER бенчмарке. При существвовании такой архитектуры и ее доказанной эффективности в Titans просто нет смысла из-за ее излишней усложненности и неизящности.
🤯 Reasoning-паранойя: o1-like модели все еще не думают как люди

В самом конце 2024 года вышла статья от Tencent AI Lab с интересным названием "Do NOT Think That Much for 2+3=? On the Overthinking of o1-Like LLMs", в которой авторы обнаружили несколько интересных свойств в ответах популярных ризонинг моделей.

Все началось с простого вопроса "сколько будет 2+3". Оказалось, что большинство LRM (Large Reasoning Model) имеют неадекватно длинные ответы на такой простой вопрос, в то время как обычные модели отвечают кратко и правильно. Среди LRM таким страдают все o1, Deepseek-R1 и QwQ-32B. А так же обычные модели специализирующиеся на математике, вроде Qwen-2.5-Math, но в меньшей степени, чем LRM.

Авторов заинтересовало такое поведение и они решили взять математические бенчмарки с градацией уровней сложности (MATH-500), выделить из размышлений моделей сегменты с решениями, где она уже пришла к какому-то финальному ответу с помощью Llama-3.3-70B и посмотреть на распределения количества таких сегментов в зависимости от бенчмарка и на каком сегменте ответ уже стал правильным.

Выяснилось следующее:
1) В среднем модели вроде QwQ и Deepseek-R1 на один вопрос генерируют 2-4 сегмента с одним и тем-же ответом. При этом есть странная зависимость - чем проще вопрос тем больше сегментов с ответом на него будет, Так для вопроса про 2+3 модели генерируют решение по 10 раз прежде чем дать финальный ответ.
2) Правильный ответ, в 92% случаев содержится уже на первом сегменте с решением, все последующие раунды решения почти не прибавляют в качестве.
3) Иногда разные решения после первого, просто рассматривают задачу с другой перспективы, например решают 2+3 как задачу об объектах, но чаще всего это просто повторение первого результата, т.е. отсутствует разнообразие решений.

Для того чтобы лучше оценивать эти эффекты авторы вводят две метрики: эффективность ответа и разнообразие решений в ответе (эффективность процесса размышления). Эффективность ответа меряется как отношение числа токенов до достижения первого верного ответа на все токены в ответе, разнообразие замеряют через кластеризацию ответов с помощью промпта GPT-4o. "Overthinking issue" таким образом определяется как низкая разнообразность ответов и их плохая эффективность.

Авторы предлагают и способы лечения. В частности, предлагается делать self-training (т.е. учится на своих же ответах) через SFT и оффлайн RLHF с помощью SimPO (показал себя лучше DPO). Эксперименты делались с QwQ-32B. Для майнинга данных использовался датасет задач PRM12K, где генерировалось по 10 решений с температурой 1.0, из них выбирались наиболее эффективные по двум метрикам, т.е. короткие, на них делался SFT. А в качестве rejected для RLHF выбирались просто наиболее длинные генерации. Так же показали, что при выборе короткого ответа недостаточно брать просто самый короткий, лучшей стратегией оказалась брать первый правильное рассуждение с верным ответов + последующее верное за ним (просто эвристика).

В результате получилось значительно уменьшить эффект overthinking (ответы стали в 2 раза короче) на всех основных математических бенчмарках и даже улучшить метрики относительно оригинальной модели. К сожалению: я не нашел у них объяснения почему вобще этот эффект в итоге возникает, но как мне кажется дело может быть в PRM (Process Reward Model) моделях и в целом тренировке только на сложных задачах, где ответы длинные. По моему предположению, PRM, которые часто используются для тренировки таких моделей, как и обычные RM легко хакатются моделями, когда они просто генерируют тот же самый ответ, но в немного другом формате и за этим не следят при тренировке. Вобщем, с текущими моделями-параноиками выгоду получают в основном только инференс-провайдеры :)
Please open Telegram to view this post
VIEW IN TELEGRAM
FlexAttention: Новый стандарт для реализации Attention в PyTorch

Кажется добавление такой фичи в Pytorch 2.5.0 осталось немного незамеченным, но так как его активно использует в своем коде lucidrains я решил про нее написать подробнее.

В теории, Attention is All You Need, но на практике оптимизированные реализации блоков внимания, такие как FlashAttention, стали необходимостью. Они добились значительного улучшения производительности относительно текущей реализации в Pytorch, позволив эффективно работать с длинным контекстом и не только. Однако, за такую эффективность пришлось заплатить — гибкость решений сильно пострадала. Сегодня внедрение новых вариантов Attention зачастую требует написания кастомных CUDA-ядер, что превращает экспериментирование в настоящую лотерею для резерчеров. Если ваши идеи не укладываются в уже существующие ядра, вас ждут медленный runtime или проблемы с памятью, а также куча низкоуровневой возни.

И к чему все это идет?

Разнообразие модификаций Attention уже велико и продолжает расти: Causal, Relative Positional Embeddings, Alibi, Sliding Window Attention, PrefixLM, Document Masking, Tanh Soft-Capping, PagedAttention и многие другие. Более того, комбинации этих технологий часто необходимы для конкретных задач — например, сочетание Sliding Window Attention + Document Masking + Causal. Однако существующие подходы предлагают крайне ограниченную поддержку таких возможностей, что серьезно ограничивает свободу разработчиков.

FlexAttention: новый подход, нативный для Pytorch

В Pytorch с этим не хотят мирится, поэтому принялись за разработку нового стандарта. Среди свойств нового модуля torch.nn.attention.flex_attention:

• Гибкость API — теперь реализация новых вариантов Attention занимает всего несколько строк кода.
• Оптимизация производительности — API автоматически преобразует ваш код в оптимизированное FlashAttention-ядро через torch.compile, избегая материализации лишней памяти.
• Автоматический backward pass — PyTorch autograd берет на себя генерацию обратного прохода.
• Работа со спарсностью — FlexAttention эффективно использует разреженные attention-маски, что дополнительно ускоряет вычисления.

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

Производительность

FlexAttention уже демонстрирует конкурентоспособные результаты. На A100 решение достигает 90% производительности FlashAttention2 в прямом проходе и 85% в backward pass. Тем не менее, за универсальность приходится платить: некоторое падение производительности связано с дополнительными вычислениями во время работы. Разработчики планируют оптимизировать backward pass и минимизировать это отставание в скором будущем.

Несмотря на небольшие компромиссы в производительности, FlexAttention уже показал значительную практическую ценность. Например, он позволил увеличить throughput в torchtune (PyTorch native post-training library) на 71% и избавил исследователей от необходимости тратить недели на разработку кастомных ядер.

Ограничения и перспективы
• Ведутся работы над улучшением производительности до уровня FlashAttention3 на H100 GPU.
• Пока что длина последовательностей должна быть кратна 128, но это будет исправлено.
Пока я готовлю некоторый основательный материал по распределенному обучению (вот, теперь я вам его пообещал, придется сделать...), можете посмотреть отличную библиотеку picotron с реализацией 4-D параллелизма на чистом torch.distributed от Huggingface,

Кроме того, это все сопровождается ongoing серией видео-туториалов от основного разработчика на его канале [ссылка на плейлист].

А еще есть более хардкорная версия 3-D параллелизма - nanotron, так же от HF.
Forwarded from rizzearch
Lightning Attention-2: A Free Lunch for Handling Unlimited Sequence Lengths in Large Language Models

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

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

в чем вообще суть - вот у нас есть

softmax(Q @ K^T) @ V, где иннер продукт между запросами и ключами выдает матрицу seq_len x seq_len, что довольно много

→ приходит в голову идея линеаризовать аттеншн, то есть делаем просто из softmax(Q @ K^T) ~= phi(Q) @ phi(K^T) ⇒ [phi(Q) @ phi(K^T)] @ V, что можно переписать как из left product в right product

phi(Q) @ [ phi(K^T) @ V ], где не будем напрямую высчитывать seq_len x seq_len матрицу, а будет только hidden_dim x hidden_dim. profit?

не совсем, когда в дело приходит понятие каузальности, ибо тогда формула становится (phi убрал для удобства) снова left product

[Q @ K^T * causal_mask] @ V

снова получаем seq_len x seq_len момент, это дело можно исправить алгоритмом Linear Attention Right Product (на предпоследней фотке), но тогда встревает кумулятивная сумма, которую не распараллелить

ну и авторы довольно красивое решение предлагают в виде того, что как раз и называется Lightning Attention

- во-первых, го вычислять аттеншн по блокам, по которым и будет идти цикл как обычно
- а в каждом блоке будем одновременно вычислять аттеншны и первым, и вторым способом: через left product с каузальной маской будет вычисляться intra block (как я понял потому что он находится рядом с диагональными элементами как раз, где и нужна каузальная маска), а через right product inter block (который/которые не соприкасаются с диагональю и можно без каузальной маски их использовать, да еще и этот блок вычислить можно через накопленную кумулятивную сумму KV), а в конце просто просуммируем, не забыв обновить KV
- тут получаем трейдофф между лево- и правоматричным умножениями, который еще и к тому же нетяжело под хардвейр оптимизировать - перетаскивать поочередно блоки между High Bandwidth Memory & SRAM (последняя картинка для иллюстрации отсюда, по всем правилам - чем больше по памяти вмещается, тем медленее работает)

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

реализовано все на тритоне, метод в принципе применим не только к их ТрансНормеру

👀 link, code
2025/01/31 02:24:47
Back to Top
HTML Embed Code: