.ml
4.34K subscribers
8 photos
3 videos
39 links
Мы — ML-инженеры финтех-компании Точка Банк.

Делаем ML не ради трендов, а ради пользы. Делимся проверенными инструментами, шерим работающие модели, рассказываем, как решаем проблемы бизнеса с помощью ML.

Вакансии в команду 👇🏻
https://tchk.me/Vl306E
Download Telegram
Топ-3 просчёта в А/B-тестировании: технические

В предыдущей части мы рассказали про культурологические просчёты во время планирования, запуска и проведения A/B-тестов. Продолжаем техническими.

1. Убираем выбросы только после эксперимента

Дисперсия — заклятый враг А/В-тестеров во всём мире. Один из самых простых способов борьбы с дисперсией — удаление выбросов. Что может быть проще, чем выкинуть часть выбивающихся данных?


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

- С выбросами можно случайно выкинуть из эксперимента 1-2% пользователей, которые в некоторых продуктах могут генерировать до 50-70% всей выручки.

- Часто с выбросами начинают бороться только на этапе подведения итого, когда эксперимент не даёт прокрас. Это в корне неверно. Чтобы избежать этой ошибки, следуем золотому правилу: как задизайнили эксперимент, так его и проводим. Если на этапе дизайна вы заложили отбросить по 1% выбросов с обеих сторон, значит то же самое нужно сделать, когда подводите итоги. Так не нарушается методология, и мы продолжаем контролировать ошибки первого и второго рода.

2. Стратификация только в сплите

Стратификация работает за счёт того, что разные группы пользователей ведут себя по-разному. Если мы делаем стратифицированный сплит, чтобы сократить дисперсию — в этом случае надо подводить итоги эксперимента с помощью стратифицированного среднего в расчётах p-value. Использование стратифицированного семплирования и обычного среднего — прямой путь к потере контроля вероятности ошибки первого рода.

3. Работа с метриками отношений

Метрики отношений — это отношение сумм двух пользовательских метрик. Например, чтобы посчитать средний чек, нам надо знать сумму покупок клиента (числитель) и их количество (знаменатель). Стоит обратить внимание, что различные заказы для одного клиента не будут независимыми: кто-то в среднем покупает больше, а кто-то меньше. Получается, что для метрик отношений нарушается принцип независимости.

Но t-test рассчитан на использование для независимых данных. С помощью симуляций АА-тестов мы легко можем убедиться, что зависимые данные ломают процедуру теста. Поэтому не стоит забывать использовать бутстрап, дельта-метод или линеаризацию, если работаете с метриками отношений. Тогда результаты ваших экспериментов останутся надёжными, а выводам по ним можно будет доверять.
👍18🔥75
Когда делаем новую фичу, A/B-тестирование кажется чем-то обыденным и очевидным. Но запустить хороший A/B-тест не всегда возможно:

📌 Иногда запуск только ради оценки эффекта экономически нецелесообразен.
📌 Иногда продуктовая команда хочет раскатить фичу сразу на всех пользователей.
📌 Иногда слишком дорого внедрять инфраструктуру для сплита пользователей.

Во всех этих случаях мы хотим как-то оценить сколько пользы причиняем бизнесу.

Как это сделать?

📖 Difference-in-Difference

В методе Diff-in-diff мы подбираем группу, в которой динамика целевой метрики на предэкспериментальном периоде максимально совпадает с группой, на которую мы раскатили фичу. Остаётся только рассчитать разницу целевой метрики между группами во время эксперимента и на пре-периоде — она даст нам оцениваемый эффект. Для этого метода важна параллельность трендов двух групп на пре-периоде.

📖 Синтетический контроль

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

📖 Двойное машинное обучение

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

Двойное машинное обучение основано на теореме Фриша-Во-Ловелла:

✏️ На первом этапе строятся две модели, которые прогнозируют воздействие и результирующие значения на основе конфаундеров.

✏️ Далее рассчитывается разница фактических значений воздействия и результата с их смоделированными значениями. Так происходит «объяснение» влияния конфаундеров на воздействие и результат.

✏️ В конце строим регрессию: Δy= w\* ΔT. Коэффициент “w” даст оценку влияния воздействия на результирующую метрику.
🔥1564👍4
Запуск маркетинговых кампаний – дорогое удовольствие, даже если стоимость воздействия на одного клиента невысокая. Поэтому часто бизнес пытается ограничить аудиторию кампании: иногда ограничения выбираются по наитию, реже выбор делают аналитики, ещё реже для этого используют ML-инструменты.

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


В чём проблема такого подхода?

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

Для решения этой проблемы на помощь приходит uplift-моделирование. Его задача — предсказание, на сколько вырастет вероятность совершения целевого действия при воздействии на клиента:

U = Y[T=1] – Y[T=0], где T — флаг маркетингового воздействия на клиента.


Основное препятствие — невозможность получить для одного и того же клиента Y(T=1) и Y(T=0), так как нельзя одновременно воздействовать и не воздействовать на человека. Соответственно, нельзя для каждого пользователя получить U и построить модель, предсказывающую этот показатель. Поэтому обычно приходят к раздельной оценке поведения пользователей с воздействием и без него:

U = Y[T=1| X] – Y[T=0| X].


Главное условие в таком подходе — независимость T от X в обучающей выборке, то есть, случайное распределение воздействия на клиентов.

С помощью ранжирования по оценке uplift, мы сможем выбрать топ клиентов, на которых маркетинговая компания окажет наибольшее влияние.

В следующих постах мы расскажем про специфичные способы оценки Y[T=1| X] и Y[T=0| X], а если вам не терпится узнать про них прямо сейчас, читайте документацию CasualML.
🔥105👏4👍31
Архитектура LLM

Что вообще такое эти ваши LLM и чем они отличаются от привычных трансформеров? Давайте разбираться.

Если пытаться дать определение, то LLM — это большая языковая модель, которая была обучена генерировать ответ на какую-либо инструкцию.
Тут два ключевых момента, не считая размер модели: то, что модель генеративная, и то, что она умеет принимать на вход какие-либо инструкции.

📝 Разбираемся с генеративностью

Какая часть трансформера умеет в генерацию текста? Правильно, декодер. Собственно, LLM — это просто жирный (с большим количеством параметров) transformer decoder. Или encoder-decoder, но это только у старых моделей, типа T5. Новые GPT-like архитектуры от энкодеров отошли.

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

Особенность этого пайлайна — после этапа pre-train модели проводят этап alignment, дообучая модель на инструкционных датасетах. В таких датасете каждый сэмпл — это диалог человека с LLM, который может включать в себя системный промпт (как раз-таки инструкцию), сообщения от лица человека и сообщения от лица LLM, зачастую промаркированные на предмет «хорошести» ответа. Сейчас самые популярные инструкционные датасеты — это Nectar и UltraFeedback.

Итого, LLM — это просто здоровенный transformer decoder, дообученный на инструкционном датасете.
Если углубляться в детали, то популярными архитектурными особенностями современных LLM являются:

- Rotary Positional Encoding (RoPE) и его модификации в качестве позиционного кодирования — вот наш пост про это.

Почему? Помогает работать с более длинным контекстом без значимой потери качества.

- RMSNorm вместо LayerNorm для нормализации.

Почему? Работает сопоставимо по качеству, но проще (быстрее) вычислять — а скорость нам важна.

- Sliding Window, Grouped-Query или Multi-Query вместо ванильного Multi-Head Attention:

Почему? Чем меньше параметров, тем быстрее вычислять.

- Может использоваться Mixture-of-Experts, но это скорее частные случаи.

Почему? Увеличиваем количество параметров модели, не увеличивая при этом сложность вычислений (хоть и страдаем по памяти).

P.S.: если вы увидели много незнакомых слов — не переживайте, в следующих постах расскажем про то, как именно работают все эти навороты.

Эти же архитектурный особенности характерны и для негенеративных современных моделек: например, для энкодеров. Так что нельзя сказать, что это что-то LLM-специфичное — скорее архитектурная база любых современных трансформеров.
2217👨‍💻17👍4🥴1🤓1
Часто в современных CV/NLP-системах мы используем тяжёлые модели для обработки. А где тяжёлые модели, там и потребность в масштабировании, параллелизме и возможности управлять зоопарком оборудования. Например, раньше у нас в Точке ASR запускалась на видеокартах только в одном ЦОДе, а второй ЦОД обрабатывал аудиозаписи только на CPU.

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


Но меня не отпускала мысль — что же будет, если мы засунем наше видео/аудио в Kafka?

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

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

В чём преимущества батчирования и как оно решает нашу проблему

Представим, что у нас есть кластер железок, который мы делим с другими командами. Мы не можем постоянно занимать все X машин, но в пиковые часы было бы хорошо поскейлиться и занять как можно больше тачек. Мы делим наш топик на X партиций и спокойно скейлимся вплоть до X консьюмеров. Наше приложение даже не знает, сколько инстансов сейчас запущено, и нам не нужно адаптировать логику под это, но мы оставляем достаточно большой простор для up/down-скейлинга.

А теперь эпопея с батчированием

На входе у нас есть h264 видео. Логично было бы использовать батч размером в один кадр, но тут мы встречаемся с очередной проблемой — «P» и «B» кадры.

Здесь можно написать отдельный пост про то, как работает h264. Если коротко:

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


Эту проблему решить достаточно просто — на источнике видео нужно перекодировать каждый кадр в JPEG. Этот подход можно применять для любого видео и использовать только I кадры (аргумент "-intra" для libx264). Или можно использовать MJPEG.

Когда мы разобрали основные вопросы, можем переходить к написанию кода.
Please open Telegram to view this post
VIEW IN TELEGRAM
12🔥93👍1
This media is not supported in your browser
VIEW IN TELEGRAM
На видео — простенькая демонстрация. Потенциально, в этом проекте нужно решить несколько вопросов:

📌 Скорость чтения и отправки батча.
📌 Упорядочивание кадров.
📌 Нормальное конфигурирование Kafka, а не просто дефолтные настройки в docker-образе.

Наше собранное на коленке решение даёт средний размер батча в 150 Кб — этого достаточно для дефолтной конфигурации Kafka. Так же можно использовать и любой другой транспорт — даже RabbitMQ, если отключить репликацию. Но, как говорилось в том меме:

«Вот так, с помощью нехитрых приспособлений буханку белого (или чёрного) хлеба можно превратить в троллейбус… Но зачем?».


P.S. Не рекомендуем использовать такое в продакшене без предварительной консультации с вашими кафководами (мы вот не консультировались).
🔥139🍾5😁4🤓2👍1
Ранее мы обсуждали с вами RoPE, а теперь поговорим о его модификациях. Собрали много интересного, поэтому будет целых три поста по этой теме. Enjoy!

Для начала напомним, что Positional Encoding (кодирование позиций слов/токенов) нужен, чтобы передать модели или трансформеру информацию о позициях слов — относительную или же абсолютную.


Как развивалось позиционное кодирование:

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

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

Минусы — не очень работает на длинных последовательностях, да и вообще не очень хорошо работает.

📆 2018 год
Потом появился гугловский BERT, а вместе с ним новый подход позиционного кодирования: авторы предложиди выкинуть тригонометрию и вместо этого добавить в модель ещё один обучаемый слой nn.Embedding — такой же, как для получения эмбеддингов слов. Он должен кодировать — то есть, превращать в вектор — позицию токена.

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

В это же время впервые появилась идея о том, что нам важны не столько абсолютные позиции слов, сколько относительные. Авторы статьи решили кодировать не абсолютную позицию, а только относительную (Relative Position Encoding, или RPE), то есть близость каждой пары токенов. Здесь же появилась идея, что позицонное кодирование стоит добавлять не в момент создания эмбеддингов слов, а на этапе Attention, добавляя знание о позициии в queries и keys.
14🔥9👍7👨‍💻3🤓1
Продолжаем рассказывать про развитие позиционного кодирования — предыдущий пост выше ⬆️

📆 2021 год
Тут появился RoPE — великий и ужасный убийца остальных методов позионного кодирования. Он унаследовал от предшественников всё лучшее: из ванильного трансформера — идею, что тригонометрия хороша для кодирования позиции, а из RPE — что проворачивать всё это кодирование надо на этапе аттеншена, и не забывать про важнность относительных позиций. В итоге, RoPE реализует и абсолютное, и относительное кодирвоание одновременно.

В это же время зародилась идея о том, что хорошо бы нам уметь работать на инфренсе на текстах, которые превосходят длиной те, которые модель видела на этапе обучения, так как учить модель на длинных текстах изначально нереально из-за нехватки памяти. Предлагается Attention with Linear Biases (ALiBi) — метод позицонного кодирования, который учитывает только лишь относительные позиции слов, которые не выучиваются, а являются статичными. Перед софтмаксом в Attention мы прибавляем значение растяния между токенами, домноженное на некоторый коэффициент, который является гиперпараметром.

В это же время начали активно развиваться LLM-ки, в том числе опенсорсные. И вот, с появлением LLAMA в 2023 году разработчики по всему миру получили возможность руками поработать с LLM-кой и что-то в ней докрутить под себя. Благодаря этому следующая веха развития позиционок началась, внезапно, на Reddit.
🔥1295👍3
Продолжаем рассказывать про развитие позиционного кодирования — вот первый и второй посты.

📆 2023 год
Пользователь Reddit размещает пост о том, что если чуть уменшить основание RoPE-аттеншна, то модель будет отлично работать на текстах длиннее, чем те, на которых она училась. Такой подход называет NTK-Aware Scaled RoPE.

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


Спустя пару недель после реддитовского NTK уже на ACL, большой и уважаемой конференции, появляется xPos: Extrapolatable Position Embedding. Идея тут схожая: мы хотим уметь экстраполироваться на более длинные тексты. Авторы пытаются решить следующую проблему: функция поворота в RoPE не монотонна, так как её монотонность нарушается для углов больше 180 градусов, и поэтому плохо экстраполируется. Решают в статье эту проблему так: уже после домножения queries и keys на матрицы поворота мы так же домножаем их на матрицу «смягчения», которая чуть замедляет вращение и не даёт нам получать углы больше 180 градусов. Так функция получается монотонной, благодяря чему дальние позиции кодируются немного лучше.

Ещё спустя месяц после xPos появился YaRN, или Yet another RoPE extensioN method. Идея у него примерно такая же, как и у предыдущих: давайте перед софтмаксом будем умножать произведение наших queries и keys на некий коэффициент (или scale factor), просто сам этот scale factor считать будем немного по-другому.

Резюмируя: до RoPE методы позиционного кодирования развивались в сторону того, чтобы позиция как можно лучше кодировалась в пределах той длины текста, на которой модель училась. После появления RoPE озиции и так кодируются довольно быстро и эффективно, поэтому новый челендж — уметь эти позиции экстраполировать на длинные последовательносто. Новые подходы (обычно, производные RoPE) направлены именно на это.
👨‍💻1297🔥3
Вспоминаем основы работы с временными рядами

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

Прежде всего вспоминаем, что временной ряд состоит из:

📌 Тренда — долгосрочного роста или спада.
📌 Cезонности — повторяющихся паттернов.
📌 Всего остального (по классике «шум»).

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

Разберёмся по порядку!

Тренд

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

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

Зачем это нужно?

📌 Для интерпретации — тренд помогает понять, как ряд меняется в долгосрочной перспективе.
📌 Для ML-моделей — бустинги над деревьями и случайный лес плохо работают с трендовыми данными, потому что не умеют экстраполировать. Перед их обучениемполезно выполнить детрендинг: например, вычесть трендовую компоненту.

Сезонность

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

Сезонность в данных — это регулярные повторения, например:

🗓 Недельная: люди больше слушают музыку по пятницам в день выхода новых релизов на стримингах.
📆 Месячная: рост переводов и покупок в дни выдачи зарплаты.
📆 Годовая: рост покупок фитнес-абонементов в начале нового года.

Тот же STL, помимо тренда, автоматически выдаёт и сезонную компоненту.

Для выделения отдельных сезонностей подходит:

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

Зачем это нужно?

📌 Для интерпретации — выделение сезонности помогает увидеть закономерности в данных: когда происходят всплески или спады, какие циклы повторяются.
📌 Для ML-моделей — источник важных признаков, без которых модель скорее всего будет совершать систематические ошибки. По аналогии с детрендингом можно cделать десезонализацию, вычитая сезонную компоненту, и попробовать моделировать только остаток.

Кстати, для анализа и прогнозирования временных рядов есть удобный Python-фреймворк etna. Он позволяет легко применять трансформации к ряду, строить прогнозы и тестировать модели — мы в Точке активно его используем. Для тех, кто работает с time-series и любит sklearn-api, но ещё не пробовал etna – рекомендуем.

Линк на туториалы 🌋
🔥26👍148🍾1
Как упростить оптимизацию гиперпараметров?

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

- Параметр λ в L2 или L1 регуляризации.
- Число соседей в kNN.
- Количество слоёв в нейронных сетях.


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

Что мы хотим в идеале? Чтобы человек вообще не принимал участие в подборе гиперпараметров. Для этого нужно:

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


Один из гиперпараметров — это learning rate, который используют в градиентной оптимизации, в частности — в градиентном спуске. Но есть ситуации, когда можно обойтись без него и при этом получить оптимальное качество. Например, в линейной регрессии:

||Xw-Y||^2 + λ||w||^2

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

xₜ₊₁ = xₜ - η ∇ f(xₜ),
где η — это размер шага (stepsize)

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

Не забывайте про поведение градиента. Если функция меняется медленно, то шаг должен быть больше, и наоборот. За это отвечает специальная константа, которая называется константой Липшица. Функция f называется G-Липшицевой, если для любых двух точек Х и Y выполнено неравенство G ≥ ||f(x) - f(y)|| / ||x-y||


Таким образом, величина оптимального шага в градиентном спуске зависит от:

- Расстояния до решения — если возьмем точку подальше, можем не сойтись.
- Константы Липшица — если не учтём, будем сходиться очень медленно.

Правильная настройка параметров поможет оптимизировать работу алгоритмов и увеличит скорость обучения модели.
👍25108👎1
Как оценить оптимальный шаг при градиентном спуске?

В прошлом посте мы расписали математически, как минимизировать функцию в евклидовом пространстве. Но на практике мы обычно не знаем расстояние до решения и константу Липшица. Это неизвестные параметры, которые трудно измерить.

Вот один из способов, как можно их оценить:

📌 Приближаем константу Липшица

Константа Липшица очень напоминает норму градиента. Возьмём её как среднее квадратичное этой нормы за T итераций.

📌 Оцениваем расстояние до оптимума

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

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

📌 Используем итеративный подход:

1. Выполняем несколько итераций градиентного спуска с произвольным шагом и собираем статистику для оценки G и расстояния до оптимума: k=2,4,8,16…

2. Задаём общее число подсчётов градиента: T_k ← [B / (2k)]

3. Допустим, у нас есть функция, которая по собранным статистикам возвращает некоторый шаг. Назовём её Root Finding Bisection. Если собранные статистики оказались достаточно хорошими, она вернёт нам близкий к оптимальному шаг, и по нему мы уже окончательно спустимся.

Формулу прикрепим в следующем посте картинкой ⬇️

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

Подробнее про создание parameter-free SGD можно почитать тут.
🔥16👍106🖕2
Функция Root Finding Bisection
👍14🔥8🖕41
Что такое Root Finding Bisection?

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


Мы определяем минимальный и максимальный шаг и постепенно сужаем диапазон, а именно:

📌 Определяем количество итераций T, которые мы будем выполнять.

📌 Задаём нижнюю и верхнюю границы шагов (η_lo и η_hi).

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

Процесс можно представить как модификацию бинарного поиска:

📝 У нас есть отрезок [A, B], в котором предположительно находится корень функции. При этом A — это нижняя граница, B — верхняя.

📝 На каждом шаге вместо среднего арифметического берём среднее геометрическое:
√(A × B).

📝 Продолжаем этот процесс, пока не достигнем идеального шага, который зависит от константы Липшица и расстояния до оптимума.

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

Такой метод позволяет эффективно находить оптимальные шаги для градиентного спуска и улучшает общую производительность алгоритмов. Это значительно быстрее, чем перебор всех значений по сетке.
🔥16👍9🤝51
Геометрическое среднее между границами η_lo и η_hi
👍20
Обычно в этом канале мы постим обзоры инструментов и объясняем что-то прикладное. Но сегодня решили показать, в чём главный приницип Точки и нашей ML-команды — для этого есть отличный повод.

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

Хотим показать вам новый ролик, который хорошо отражает наше отношение к работе. Приходите к нам, если хотите так же ⬇️

В следующих постах будем больше говорить о наших ежедевных задачах и проектах 💜
17❤‍🔥9🔥9
This media is not supported in your browser
VIEW IN TELEGRAM
Меняй

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

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

Сразу признаемся — вдохновились сериалом «Разделение». Но сделали всё наоборот: показали, как выглядит свобода влиять на свою жизнь и работу.

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

Ну а если работу не изменить — меняй работу.

И приходи к нам 🤟🏻

Вакансии ➡️
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥3311❤‍🔥10👍2
Что такое Bias и Variance?

Bias (смещение) — ошибка, которая возникает из-за недостаточной сложности модели.

Variance (дисперсия) — ошибка, которая возникает из-за чрезмерной чувствительности модели к конкретным примерам в обучающей выборке.


Таким образом, у нас может быть три типа моделей:

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

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

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

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


Почему же такого нет у больших моделей типа GPT?

Потому что у этого графика есть продолжение. Когда количество параметров модели увеличивается тестовая loss делает спуск. Это называется double descent:

📝 Complexity double descent — когда мы наращиваем сложность модели;
📝 Data double descent — когда мы увеличиваем объём обучающей выборки при фиксированной сложности модели.

Благодаря этому феномену более сложные большие модели могут находить более простые решения.
24👨‍💻10🤩6🤯4
Почему большие модели устойчивы?

Предыдущий пост закончили на том, что у более сложных моделей типа GPT есть double descent. Продолжаем тему — начнём с того, как оценить сложность модели с помощью константы Липшица:

f(x_1) - f(x_2)| ≤ L × |x_1 - x_2|

Это мера «резкости» функции: чем больше производная на определенном интервале, тем больше флуктуации — константа Липшица указывает на их силу.

Посчитать её можно по производной на отрезке: формулу прикрепим к следующему посту.


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

📎 Возьмём фиксированную модель с K параметров и train loss=0

f_1(x) = f1 (x_0, x_1,..., x_k), x, x’ ∈ R_k

Её константа Липшица будет равна L_1.

📎 Добавим новый параметр и получим новую нейронную сеть:

f_2(x, x_k+1) = f2 (x_0, x_1,..., x_k, x_k+1), x, x’ ∈ R_k

Её константа Липшица будет равна L_2.

📎 Оптимизация: обучим новую нейронную сеть так, чтобы L_2 ≤ L_1

Добавляя новые параметры, мы можем уменьшить константу Липшица и сделать модель более гладкой в определенной проекции, а значит, более устойчивой и способной к обобщению.
17🔥9🤓9
Как посчитать константу Липшица по производной на отрезке
16👍5🔥1
Что такое grokking?

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

📌 На 100 итерациях качество не растёт.
📌 На 1000 итерациях модель переобучается и имеет низкую валидацию.
📌 После миллиона итераций (в 1000 раз больше, чем модели понадобилось, чтобы запомнить датасет) точность на валидации достигает 100%.

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

Этот эффект называется grokking. Термин заимствовали из книги Роберта Хайнлайна «Странный новый мир», где автор описывал концепцию полного понимания чего-либо. Модель продолжает учиться на данных даже после того, как достигла нулевой ошибки на тренировочном наборе.


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

📝 Full batch — практически никогда не достигает стопроцентного качества.
📝 Mini batch — показывает более качественный результат.
📝 Mini batch с включённым Weight decay — лучше всего демонстрирует генерализацию на данных.

Подробнее про Weight decay расскажем в следующем посте.
👍35🔥109