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

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

Вакансии в команду 👇🏻
https://tchk.me/Vl306E
Download Telegram
Популярные SOTA-модели для суперразрешения

📍 Upscale-A-Video — модель для восстановления видео с низким разрешением, основанная на диффузии.

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


Что интересно:

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

📚 Rotary Position Embedding использует вращательные матрицы для кодирования относительных позиций элементов в последовательности, что позволяет лучше учитывать временные зависимости.

📍 VideoGigaGan — SOTA-модель для видео суперразрешения, в которой ключевую роль играет функция потерь.

Архитектура: традиционный трансформер с UNet-подобным декодером. Важным аспектом является использование temporal attention, который позволяет передавать карты внимания между соседними кадрами. Это уменьшает размер модели и повышает её эффективность.


Что интересно:

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

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

Где взять данные для обучения моделей?


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

Процесс включает:

📌 Размытие из-за микродвижений.
📌 Уменьшение разрешения изображения.
📌 Добавление шума, характерного для камер при нормальном освещении.
📌 JPEG-сжатие, которое широко используется в современных устройствах.

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

💜 Этот пост написал Никита Алутис, ML-разработчик в Точке
19🔥9👍7👨‍💻3👏2
Встретимся на PyCon Russia 25-26 июля?

Коллеги из ML-команд Точки выступят на PyCon, чтобы рассказать об инструментах, с которыми работают каждый день:

📚 Airflow в коммунальном ML: от боли к эффективному использованиюВладимир Пузаков, MLOps

Как сделать так, чтобы было можно использовать инстанс Аirflow, развёрнутый в Kubernetes, в качестве оркестратора ML-пайплайнов, причём сразу несколькими командами, которые не мешают и даже помогают друг другу?

Владимир поделится теми болями, с которыми пришлось столкнуться, и их решением. А ещё покажет несколько лайфхаков, которые заметно упрощают жизнь пользователям Аirflow.

Доклад будет полезен не только MLOps, которые отвечают за ML-инфраструктуру, но и тем, кто использует Аirflow для написания пайплайнов.

📚 Как обучение со слабым контролем помогло тегировать клиентские обращенияАртур Сосновиков, тимлид ML-команд

Ручная разметка данных остаётся узким местом в ML-проектах — она дорогая, медленная и плохо масштабируется. Вместо использования GPT напрямую для классификации, мы используем его для генерации и итеративного улучшения правил разметки на основе ошибок модели.

Сформированные таким образом слабые метки агрегируются с помощью классических методов weak supervision и позволяют обучать точные модели даже в условиях острого дефицита размеченных данных. В отличие от статичных эвристик или одноразовых LLM-промптов, наш подход построен как замкнутый цикл обратной связи: модель → ошибки → обновлённые правила → новые метки.

В кейсе с классификацией клиентских обращений в поддержку Точки этот подход обошёл и zero-shot GPT-4, и классическое обучение на размеченных данных — при меньших затратах и лучшей масштабируемости.

Приходите в Конгресс-центр ЦМТ, если вы в Москве. Будет здорово встретиться и пообщаться с подписчиками этого канала вживую 💜
🔥1910🥰7👍2🤡1💯1
В предыдущих постах мы рассказывали о Restoration в CV, и популярных SOTA-моделях. Пришло время сделать выводы:

📝 Loss под задачу, не задача под loss

В последние годы набирает популярность подход degradation modeling — для решения проблемы он предлагает смоделировать искажения, которые её вызвали. Например, если мы точно смоделируем шум, то сможем использовать его физические свойства как дополнительные данные для модели.

Совет: Loss-функция позволяет тонко настроить результат работы сети. Добавление небольших компонентов к loss может существенно повлиять на выходные данные модели. Для этого не обязательно начинать обучение с нуля — можно использовать новый loss на этапе fine-tuning для улучшения результата.


📝 Аккуратный переход к реальным данным

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

📝 Метрики — не истина в последней инстанции

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

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


💜 Этот пост написал Никита Алутис, ML-разработчик в Точке
19💯9👍6🥰5👎1
Часть 1: Как обучить модель, когда много данных и мало разметки?

В трёх постах покажем, как в Точке мы искали рабочий способ классифицировать обращения клиентов: от экспериментов с «шумной» разметкой и GPT до подхода с Weak Supervision и Snorkel, который дал высокую точность и снизил затраты.

Каждый месяц мы в Точка Банк получаем больше 500 000 обращений от клиентов. При этом важно понимать, с чем именно они приходят в поддержку. Поэтому мы тэгируем каждое обращение, например, #Тариф, #Счёт, #ОнлайнБухгалтерия — всего больше 50 тэгов.

Это помогает:

📌 Правильно разносить затраты поддержки на продукты.
📌 Оперативно решать проблемы.
📌 Держать руку на пульсе и понимать, что беспокоит клиентов.

Раньше оператор ставил теги в конце диалога вручную. Ещё операторы часто переключаются между задачами и им трудно удержать в голове весь контекст, поэтому точность такого тега в среднем составляет около 80%.

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


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

📝 Супер эксперты (бизнес-юнионы): связывают клиента и продукт. Хорошо разбираются в своей теме, но могут разметить не более 200 сессий в месяц. А ещё их мало — по одному на каждую тематику.
📝 AI-тренеры: операторы службы поддержки. Хорошо знают все темы, умеют разделять теги, но их точность около 80%.
📝 Внешние асессоры на ГПХ: не обладают экспертизой в клиентской поддержке, но зато их можно нанять много.


В такой ситуации получить качественную разметку в большом объёме невозможно.

👾 Наш эксперимент

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


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

О том, как мы составляли золотую выборку, расскажем в следующем посте.
25🔥15👍11👨‍💻4😁1🤡1🤓1
Часть 2: Как обучить модель, когда много данных и мало разметки?

Это история о том, как мы Точке классифицируем клиентские обращения

Модель для онлайн-разметки показала невысокую точность — всего 80%. Поэтому мы решили добыть золотую разметку и попросили супер экспертов разметить 2000 объектов. Задачу поставили в бинарном сетапе, то есть, использовали только два тега #Тариф и #ВсёОстальное.

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


На dev-выборке в 1000 объектов получили такие метрики few-shot:

📌 Precision — 68%
📌 Recall — 89%
📌 F1 — 0,77

Получается, что тэг #Тариф мы определяли правильно лишь в 68% случаев. А 11% вообще не попали под нашу классификацию.

Тогда мы решили взять ризонинг-модель и использовать её рассуждения. Это дало незначительный прирост качества +2% к F1.

Какие выводы мы в итоге сделали:

📝 Не получается подобрать инструкцию, чтобы определять метку с высокой точностью.
📝 Сложно масштабироваться на новые теги.
📝 Есть трудности с маскирацией персональных данных.
📝 Высокая стоимость — для GPT-4о от 2000$ в месяц даже без сложных цепочек ризонинга.

Как мы решили эти проблемы, расскажем уже в следующем посте.
23🔥11👍7😁4
Часть 3: Как обучить модель, когда много данных и мало разметки?

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

Тестовая dev-выборка показала низкую точность и высокую полноту. Тогда мы решили использовать комбинированный подход: LLM + Weak Supervision.

Что такое Weak Supervision?

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


Самый простой способ — голосование большинством. Но у этого метода есть минусы:

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

Поэтому в качестве итогового классификатора мы использовали Snorkel.

Применили размёточные функции на большой выборке и научили модель разбираться в корреляционной структуре, где метки вступают в противоречие. Затем взяли языковую модель, которая сама придумывает размёточные функции. Использовали для этого тяжёлую умную модель GPT, а применили их на лёгкой T1-Lite.

В результате эксперимента мы получили:

📍Высокую точность.
📍Прежний уровень recall.

Таким образом, благодаря этому подходу мы:

📝 Получили модель с более высокой точностью, чем у few-shot.
📝 Сэкономили деньги. Потратились на обучение один раз, а инференс получили условно бесплатно.
📝 Сэкономили время. На разметку данных ушло всего две недели, а готовый метод можно применить почти молниеносно, имея на руках золотую выборку.

💜 Серию постов написал Артур Сосновиков, тимлид нескольких ML-команд в Точка Банк.
26🔥10👏8👍2😁2
Почему LLM без Alignment — это риск?

Обучение на миллиардах токенов даёт языковой модели грамотность, но не гарантирует адекватность. Без Alignment она может:

📌 выдавать логически неверные ответы,
📌 генерировать небезопасный контент,
📌 игнорировать бизнес-ограничения.

Что такое Alignment? Это дообучение с учётом предпочтений и ограничений, которое делает модель предсказуемой и управляемой.
Написали статью на Хабр, в которой разбираем:

📝 Методы Alignment: от PPO (Proximal Policy Optimization) до новых подходов DPO и KTO.
📝 Наш опыт: как мы в Точка Банк настроили LLM под конкретные сценарии, обучили модель наград и сократили затраты по сравнению с классическим RLHF.
📝 Грабли и лайфхаки: как работать с несбалансированным датасетом и не дать модели обмануть функцию награды.
📝 Где применять Alignment за пределами LLM: от cost-sensitive классификации до vision-language моделей.

Точно будет полезно, если строите собственную LLM — читайте и задавайте вопросы в комментариях!
👍2815🔥11👎1😁1
Многие, кто обучал большие модели искусственного интеллекта, сталкивались с ситуацией, когда необходимы данные из множества источников. Но если источники совсем не из одной корпорации, то из-за GDPR или законах о защите персональных данных нет возможности обмениваться данными напрямую.

Как быть, если нужно обучать большие модели, но нельзя собирать всю информацию в одном месте?

Решение — федеративное обучение. Это система, в которой центральное устройство (сервер) объединяет усилия множества участников (устройства): каждый совершает операции на своих данных, а сервер собирает только результаты, не забирая саму информацию.

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

📌 Горизонтальное федеративное обучение (HFL)

Суть: у разных участников данные имеют одинаковые фичи (одинаковые столбцы), но разные строки (разные пользователи/наблюдения).

Пример: несколько банков обучают модель для предсказания мошеннических транзакций. У всех есть одинаковые признаки по транзакциям (сумма, время, место, категория операции и т.п.), но набор клиентов у каждого банка свой. Объединяя данные через HFL, они получают более устойчивую модель, не раскрывая данные клиентов напрямую.


📌 Вертикальное федеративное обучение (VFL)

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

Пример: банк и страховая компания имеют одних и тех же клиентов. У банка есть финансовые характеристики (история транзакций, кредитный рейтинг), у страховой — медицинская история и страховые выплаты. Объединив признаки в VFL, они могут построить более точную модель для оценки рисков по клиенту.

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

💜 Этот пост написал Сергей Станко, ML-инженер в Точка Банк.
24👍11👏6😁1
А вы знаете ещё реальные примеры использования федеративного обучения?
Anonymous Poll
8%
Да, из своей практики
17%
Да, из практики других компаний
75%
Нет, впервые слышу о федеративном обучении
4🔥4🍾1
Большинство советов по ускорению Pandas звучат одинаково: «уберите циклы», «используйте apply», «снижайте размер типов». Но правда в том, что в реальном проекте эти правила работают не всегда — иногда даже замедляют пайплайн и увеличивают потребление памяти.

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

👾 Iterrows vs itertuples: почему официальная рекомендация из документации pandas может привести к Out of Memory и замедлению пайплайна.
👾 apply с raw=True: малоизвестный аргумент, который даёт почти тот же прирост, что NumPy-векторизация — без полного переписывания кода.
👾 merge → loc или reindex: правда ли merge — швейцарский нож в мире датафреймов?
👾 Типы данных: int8 vs int64, float32 vs float64, categorical и sparse — что реально экономит ресурсы, а что даёт мизерный эффект.
👾 Параллелизация: pandarallel и multiprocessing — какой инструмент выбрать и почему (или не выбирать ни один).

Если вы работаете с большими объёмами данных на Pandas, наша статья поможет избавиться от «оптимизаций ради оптимизаций».
22🔥14👍9👏2😁1
Почему Polars blazingly-fast: дело не только в Rust

Когда данных много, pandas часто упирается в память и «однопоточность» Python, а множественные агрегации могут выполняться в течение часов или даже дней. Какие же существуют альтернативы? Давайте разберёмся, как устроен Polars и какие архитектурные решения делают его blazingly-fast.

Как оно работает

📌 Колоночный движок на Rust + Arrow-модель памяти
Polars использует модель памяти Apache Arrow для хранения данных в колоночных буферах — плотных, типизированных массивах без Python-объектов. Что важно: формат адаптирован под высокие кэш-хит-рейты и быстрое выполнение SIMD-инструкций. Ядро на Rust исполняется вне интерпретатора Python и не упирается в GIL, что позволяет эффективнее утилизировать CPU и распараллеливать вычисления.

📌 Lazy-режим и оптимизатор
Вы описываете всю трансформацию целиком, а движок сам решает порядок шагов: «проталкивает» фильтры к источнику, отбрасывает лишние столбцы ещё на чтении. По сути Python — это интерфейс, который помогает собрать программу на внутреннем оптимизированном DSL Polars. В итоге это сокращает I/O и использование памяти.

📌 Логический → физический план: как Polars оптимизирует запрос
Когда вы описываете запрос с использованием lazy frame и lazy computations, Polars строит логическое дерево и заранее проверяет типы/схему. Затем оптимизатор уплотняет работу: проталкивает select/filter к источнику, выкидывает лишнее, объединяет выражения. После этого выбираются конкретные алгоритмы и распараллеливание (какой join, как считать group_by), формируется физический план. На исполнении читаются только нужные столбцы и куски данных, при необходимости — потоково; в конце всё собирается одним collect(). Для диагностики полезно смотреть план через lf.explain() (при необходимости — с учётом движка) и включать POLARS_VERBOSE=1, чтобы видеть, как выглядит итоговое оптимизированное дерево.
26🔥106👍2😁1
Ключевые внутренние паттерны

📝 Predicate / projection / slice pushdown
Фильтры, выбор столбцов и срезы применяются максимально близко к моменту чтения (scan_parquet/scan_csv). Проще говоря, читаем ровно то, что нужно, а не «всё подряд». Это резко ускоряет последующие join и group_by и снижает нагрузку на память.

📝 Параллельные join и group_by
Polars разбивает данные на части и обрабатывает их на нескольких ядрах, используя быстрые хэш-джоины и продуманные стратегии агрегации. Ускорение особенно заметно на широких таблицах и конвейерах с множественными агрегациями. Конкретный тип join и форма пайплайна могут влиять на распараллеливание и потребление памяти — это видно в плане.

📝 Streaming / out-of-core
Длинные пайплайны можно исполнять «потоково»: данные обрабатываются батчами, не накапливаясь целиком в памяти — это уменьшает пики памяти и стабилизирует задержки. Включается это явно: lf.collect(engine="streaming"). Важно: не все операции поддержаны в стриминге; где это невозможно, движок прозрачно перейдёт к in-memory выполнению (это нормально, но стоит контролировать план).

📝 SQL поверх выражений
Нужен знакомый синтаксис — регистрируете фреймы и используйте SQL; внутри всё равно сработает оптимизатор выражений. Это возможно благодаря SQLContext/pl.sql, что удобно для смешанных команд (аналитики + инженеры).

Анти-паттерны «под капотом»

📎 Построчные apply/map_rows на Python
Любая функция, которая ходит по строкам в Python, возвращает вас к GIL и убирает параллелизм. Если нужна UDF — старайтесь выразить логику через выражения Polars или переносить вычисления ближе к движку.

📎 Постоянное использование read_* вместо scan_*
read_* сразу загружает всё в память и ограничивает оптимизатор в pushdown-приёмах. Для конвейеров и больших наборов данных предпочитайте scan_* с lazy-планом — это откроет путь для predicate/projection/slice pushdown и стриминга. Для быстрых «снимков» и интерактивной разведки read_* допустим, но указывайте columns=[...] и другие параметры чтения, чтобы не тянуть лишнее.

📎 dtype=object/pl.Object
Polars умеет хранить Python-объекты в специальных столбцах, но это вырывает данные из arrow колоночной модели и выключает многие векторные оптимизации. Используйте только при крайней необходимости и как можно раньше приводите к нативным типам Polars.

Скорость Polars — не «магия», а архитектура
Arrow-модель памяти, lazy-планирование с агрессивными оптимизациями, потоковое исполнение там, где это возможно, и ядро на Rust, обходящее GIL. Практический эффект зависит от формулировки запроса и формата данных — корректный выбор scan_*, выражений и режима исполнения часто даёт многократный выигрыш.

В следующем посте мы расскажем, как использовать Polars в проде: от чтения паркетов до передачи фичей в модели.

💜 Этот пост написал Всеволод Богодист, Data Scientist в Точка Банк.
👍3420🔥112😁1🏆1🫡1
Polars в продакшене: best practices

Когда нужно готовить фичи и витрины «здесь-и-сейчас», pandas-пайплайн часто даёт лишние задержки. Разберёмся, как построить на Polars быстрый и устойчивый конвейер для ETL и ML.

Чтобы что?

📌 Меньше TCO на ETL. За счёт pushdown и параллельности вы читаете меньше данных, тратите меньше CPU и памяти. На том же кластере — больше задач и стабильнее SLA.
📌 Быстрые фичи для моделей. Окна, джоины и агрегации считаются в Polars, а в модель уходят уже компактные матрицы/тензоры — время обучения и инференса сокращается.
📌 Порог входа ниже. С SQLContext команда может начать с SQL и постепенно переходить к выражениям, не теряя производительности.

Базовый набор шагов

📝 Начинайте со scan_* и Lazy. Схема простая: scan_parquet/csv → select/filter/with_columns → финальный collect(). Ранний select() экономит I/O.

📝 Для отладки используйте fetch(), он подходит для быстрых «прогонов» на маленьком сэмпле.

📝 Настройте джоины. Для джойнов по времени — join_asof, сортировка фреймов по ключам, для строковых ключей используйте тип Categorical и включённый StringCache, чтобы джоины были и быстрее, и стабильнее по памяти.

📝 Создавайте новые фичи выражениями. Конструируйте логику через when/then/otherwise, pl.struct, селекторы pl.selectors — это заменяет циклы и apply, оставляя работу на стороне внутреннего оптимизированного движка polars.

📝 Подружите свой пайплайн с ML-стеком. NumPy/torch/sklearn: df.to_numpy()/s.to_numpy() → torch.from_numpy() — минимум копий между слоями. Pandas-мир: to_pandas(use_pyarrow_extension_array=True) включает Arrow-бэкенд и помогает экономить память за счет zero-copy операций.

📝 Включайте streaming там, где длинные пайплайны. collect(engine="streaming") и sink_* уменьшают пиковую память и сглаживают латентность. sink_* позволяет обрабатывать и записывать данные на диск батчами, чтобы не перегружать RAM.

📝 Где уместно — SQL. Регистрируйте фреймы в SQLContext, пишите запросы на SQL, а узкие места постепенно переносите на выражения. Данная практика хороша для быстрого переезда на polars в командах, которые плохо знакомы с синтаксисом polars, но разбираются в SQL-выражениях.

Анти-паттерны в продакшене

📎 collect() после каждого шага. Так вы рвёте план и теряете оптимизации. Копите цепочку и собирайте один раз в конце.
📎 Маятник между pandas и Polars. Постоянные конвертации туда-сюда съедают выигрыш. Держите данные в Polars до последнего шага; если нужна совместимость, используйте Arrow-бэкенд.
📎 Игнорирование специфики типов. Оставлять ключи строками = призывать медленные джоины. Перекладывайте ключи в Categorical и включайте общий словарь.


Кейс Точка Банк

📝 Контекст
Задача реал-тайм рекомендаций. Узкое место — джоины, фильтры и сортировки на горячем потоке данных.

📝 Что сделали
Перенесли препроцессинг с pandas на Polars, переписали джоины в lazy-план, навели порядок в типах (категориальные ключи + общий словарь) и добавили join_asof для временных связок.

📝 Результат
Пайплайн стал выполняться примерно в 5 раз быстрее end-to-end на том же железе — основной прирост дали «проталкивание» фильтров и параллельные джоины.

Получается, что если собирать пайплайн с учетом всех лучших практик работы с polars — lazy, pushdown, выражения, аккуратные джоины и понятные мосты в ML — вы получаете устойчивый прирост скорости и контроля над ресурсами.

💜 Этот пост написал Всеволод Богодист, DS в Точка Банк
👍3220🔥12
Вероятно, прочитав наши предыдущие посты про Polars, вы подумали: «Вау, классный инструмент, жаль мы на него не переедем, у нас слишком много инфраструктуры завязано на pandas». Это довольно частая ситуация: разработчики библиотек не могут переехать на более современный табличный бэкенд, потому что большинство их пользователей использует pandas.

Так как же всё-таки слезть с иглы pandas?

Для этого существует Narwhals — библиотека, которая предоставляет Polars-подобный API и служит слоем совместимости между разными DataFrame-библиотеками. Она позволяет писать один набор логики, который выполняется нативно на бэкенде входных данных и возвращает тот же тип DataFrame, что был на входе.

📎 Narwhals не конвертирует постоянно таблицы в один центральный формат — он оборачивает/переводит вызовы в нативный API бэкенда, чтобы сохранить вычисления «нативными» (т.е. избегать дорогих конвертаций). Это снижает накладные расходы и сохраняет производительность.
📎 Поддерживает индекс pandas, несмотря на то, что в других бэкендах его вообще нет.
📎 Есть ленивые вычисления — для тех, кто любит оптимизацию и отложенное выполнение.


В итоге мы получаем возможность писать библиотеки и утилиты, не беспокоясь о том, какой табличный бэкенд использует команда. Этим преимуществом уже пользуются такие популярные проекты, как Plotly, Bokeh и Darts.

💜 Этот пост написал Виталий Прахов, DS в Точка Банк
👍24🔥13❤‍🔥81
Model-Centric vs Data-Centric подходы в ML

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

Что можно сделать:

📌 Поменять подход к обучению — поиграть с архитектурой, претрейнами, оптимизаторами.
📌 Поработать с данными — проверить датасет, пересмотреть разметку, найти шум и ошибки.
📌 Или в совсем отказаться от классической ML-модели и попробовать скормить всё LLM, надеясь на zero/few-shot способности модели.

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


Andrew Ng из DeepLearning.AI в одном из своих выступлений на примере задачи с детекцией дефектов на поверхности показывал, что:

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

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

В следующем посте — подробнее про асессорскую разметку и оценку её качества.
36🔥17👍15👏2🥴1
Асессорская разметка: как оценивать согласованность?

Обычно разметка проходит строго по этапам: сбор данных → создание гайда → запуск разметки обычно с перекрытием → агрегация меток → обучение модели → оценка качества.

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


В такой ситуации можно посчитать коэффициент согласованности — agreement. Он показывает долю совпадающих меток между асессорами.

В нашем случае средний попарный agreement — 83,9%, что достаточно неплохо. Но есть подвох: этот коэффициент, так же как и accuracy в случае бинарной классификации, может вводить в заблуждение при дисбалансе классов. В нашем датасете больше 70% меток приходятся на два класса — «Нейтральный» и «Замешательство». Давайте воспользуемся другими статистическими коэффициентами, чтобы удостовериться в высокой согласованности:

📌 Cohen‘s Kappa (Каппа Коэна) — попарный коэффициент. Оценивает нормализованное согласие между двумя асессорами.

Как интерпретировать результаты:

<0,6 — плохая согласованность.
0,6…0,8 — хорошая согласованность, можно использовать в прикладных задачах.
>0,8 — очень высокая согласованность.


📌 Fleiss’s Kappa (Каппа Фляйна) — подходит для оценки согласованности между несколькими (более двух) асессорами.

В нашем случае Каппа Коэна варьируется от 0,7 до 0,84, что указывает на высокую согласованность. Для дополнительной проверки мы взяли несколько сотен случайных примеров из датасета и вручную расставили метки. Оказалось, что в 44% наши и асессорские метки расходились — то есть, асессоры в среднем согласованно ставят неправильные метки. Вот поэтому даже высокие показатели согласованности не гарантируют качественной разметки данных.

Что делать в такой ситуации — расскажем в следующем посте.
🔥2414👍11🤩1
Что делать, если асессорская разметка не совпала с экспертной?

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

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

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

📝 Разбить работу на чанки и добавить в каждый golden set для валидации. Это позволит оценивать качество разметки итеративно и следить, насколько асессоры попадают в золотой набор.

После внедрения этих шагов в нашей модели эмоций взвешенный F1 вырос с 0,61 до 0,7, а расхождение экспертной и асессорской разметки упало с 44% до 18%. Также хорошо подтянулись небольшие проблемные классы:

Благодарность — 0,8 → 0,76
Нейтральный — 0,7 → 0,75
Удовлетворительно — 0,68 → 0,74
Нетерпение — 0,57 → 0,53
Разочарование — 0,57 → 0,55
Замешательство — 0,46 → 0,7


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

📎 Неоднозначность задачи: она может подразумевать некоторую неопределенность. Например, такое часто встречается при подготовке диалоговых данных для LLM.

📎 Разный бэкграунд асессоров: внутренние AI-тренеры и внешние подрядчики могут понимать задачу по-разному. Это приводит к значительным различиям в оценках.

Поэтому ML-инженерам и датасаентистам важно самим вчитываться в данные и понимать, как они размечены.

Что делать с ошибочными разметками — расскажем в следующем посте.
🔥19136👍3🌚1
Что делать с ошибочными разметками?

Это продолжение поста об асессорской разметке данных. Если мы нашли ошибки в разметке, то можем:

📌 Передать несогласованные примеры на доразметку эксперту. Это самый простой вариант, но не всегда есть возможность привлечь доменного эксперта.

📌 Использовать библиотеку CleanLab для работы с шумными данными. В её основе лежит алгоритм confident learning, который автоматизирует поиск ошибок. Как это работает:

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

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

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

🔍 Confidence — средняя вероятность предсказания истинного класса.
🔍 Variability — дисперсия вероятностей по эпохам. Показывает, насколько часто модель меняет своё предсказание с течением эпох.
🔍 Correctness — доля эпох, когда пример классифицировался верно.

На выходе мы получаем график, который делит примеры на три зоны (график смотрите ниже):

📝 Easy-to-learn: простые примеры, которые модель легко распознаёт.
📝 Ambiguous: неоднозначные примеры, которые нужны для обучения модели, чтобы она обобщалась.
📝 Hard-to-learn: вероятные ошибки в разметке.

Таким образом, для первичной фильтрации ошибок можно использовать CleanLab. А затем использовать Dataset Cartography, чтобы глубже понять структуру данных.

В следующем посте — про синтетическую разметку данных с помощью GPT.
🔥259👍6
Так выглядит Dataset Cartography
🔥3112😍7❤‍🔥4
Можно ли заменить асессоров на LLM? Да, но с умом.

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

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

Затем мы обучили два классификатора на разных датасетах:

📌 Исключительно с LLM-метками.
📌 С асессорскими метками после проведенной работы по улучшению согласованности и уменьшению ошибок.

Разметка LLM — Weighted F1 0,66
Разметка асессоров — Weighted F1 0,7


В результате качество на LLM-метках лишь немного не дотягивает до эталонной разметки. При этом мы сэкономили большое количество времени и человеческих ресурсов.

Таким образом, на текущем этапе LLM можно рассматривать как джуниор-асессора. Модель отвечает примерно как человек, и в отсутствии ресурсов её можно использовать для разметки данных. В некоторых задачах это даст качество, сопоставимое с эталонной разметкой.

💜Серию постов про разметку написал Антон Земеров, ML-тимлид в круге «Общение с клиентом»
🔥29👍138
Всем привет! Как отдохнули?

Мы выходим с каникул с постом, в котором собрали самое интересное из вышедшего на канале. Если вдруг пропустили некоторые темы или хотите освежить знания — переходите по ссылкам и читайте 💜
14🎄1