Канал для поиска исполнителей для разных задач и организации мини конкурсов
Last updated 2 months, 1 week ago
Пока с командой пишем новый пост, принесли тут анонс от коллег.
У нас регулярно проходят открытые ридинг-группы по RecSys для всех желаюших.
И уже завтра, 22 августа, в 16:00 пройдет очередная встреча в онлайн формате: ребята обсудят статью о том, как с помощью нейронных сетей аппроксимировать главные собственные функции интегральных операторов заданных ядер на некоторых вероятностных распределениях без дорогой операции ортогонализации (согласны, это сильно!).
Ведущий группы — Александр Тараканов, ML-исследователь AI VK.
⬇️
Дата: 22 августа
Zoom: ссылка
Meeting ID: 856 0989 2167
Passcode: 433059
Подключайтесь завтра в 16:00!
PMLR
NeuralEF: Deconstructing Kernels by Deep Neural Networks
Learning the principal eigenfunctions of an integral operator defined by a kernel and a data distribution is at the core of many machine learning problems. T...
Подход мы подглядели у разработчиков navec библиотеки. Если кратко, то он заключается в том, чтобы использовать грязную многомиллионную разметку от большой модели для обучения легковесной. Для своей задачи мы собрали сэмпл из 30 млн уникальных комментариев за 2 года. В качестве предобработки помимо очистки текста от html тэгов, обращений к другим пользователям и прочим неинформативным символам, дополнительно по словарику все встречающиеся смайлы заменялись на их семантику. Уже подготовленные тексты затем скармливались в blanchefort и логиты предсказаний сохранялись.
Процесс инференса занял порядка 40 часов. Затем подготовленные комментарии до замены смайлов мы скормили в sentencepiece и обучили свой BPE токенизатор размерностью 100 тысяч. Свежеиспечённый токенизатор мы раскатили на все тексты и получили их индексы. Датасет был подготовлен и сериализован в удобном для обучения формате tf.data.Dataset.
В качестве модели мы используем обычную полносвязную нейронную сеть с одним скрытым слоем размерностью 64 и функцией активации ReLU. На вход в сеть подаётся 100к мерный вектор фактов встречаемости токенов, благо у tensorflow есть поддержка разряженных тензоров из коробки. Обучаем кроссэнтропией на аппроксимацию логитов большой языковой модели 10 эпох. В результате качество аппроксимации насыщается на уровне 85% на валидационных данных.
Пробовали разные вариации с несколькими скрытыми слоями, без них, с соединением с пробросом и прочее. Логрег имел качество аппроксимации порядка 74%, остальные конфигурации обладают качеством не сильно лучше однослойной сети. Как можно понять из описания, у такой модели теряется информация о позиции токенов и их количестве, но эксперименты показали, что это не сильно влияет на результат, так как большинство комментариев имеют мало токенов.
Стоит отметить, что метрика согласия с моделью учителем в 85% не совсем адекватно отображает качество, т.к. сама большая модель может ошибаться. Поэтому из валидации взяли стратифицированный по логитам берта сэмпл 2к комментариев и отдали ассесорам на разметку. Получили так называемый золотой бенчмарк, поскольку один комментарий размечался несколькими людьми независимо. В результате доля совпавших ответов новоиспеченной модели с разметкой разметчиков составила 83%.
F1-мера порядка 80%, а One-vs-Rest ROC-AUC 92%.
При этом по всем приведёнынм метрикам качества разработанная модель нестатзначимо лучше опенсорс берта на 1%. Сравнивали так же с другими внутренними решениями от других отделов и по качеству были конкурентоспособными.
Касаемо инференса: такую модель можно легко развернуть и без специализированных фреймворков для глубокого обучения.
Однослойная нейронная сеть — это два матричных произведения с преобразованием ReLU, прямым аналогом которого в numpy является функция maximum с 0. Весь инференс модели можно записать в одну строчку np.maximum(W1[ind].sum(axis=0) + B1, ).T.dot(W2) + B2.
Сумму вместо скалярного произведения мы можем использовать, т.к. гарантируется, что каждый токен встречается не больше одного раза. Вся модель занимает порядка 25 МБ оперативной памяти при хранении во float32, где больше всего памяти приходится на матрицу W1 с размерностью 100к на 64. Хранить модель можно в квантизованном формате uint8, а во время запуска уже распаковывать. Квантизацию делали вручную через KMeans кластеризацию каждого столбца: получилось 255 кластеров. Размер модели уменьшился до 4 МБ при gzip сжатии. А храним мы её в npz формате и используем в связке с токенизатором от sentencepiece, размер которого не превышает 3 МБ ?
Сегодня мы расскажем подробнее про одну из задач от команды дескриптивной аналитики и CRM моделирования, а именно — про оценку тональности комментариев в пабликах.
Во всём VK за день публикуются десятки миллионов комментариев, сколько их выходит за неделю или месяц предлагаем прикинуть самостоятельно в качестве упражнения ?
Оценка тональности комментариев или сентимент-анализ — одна из распространённых NLP задач. По сути это многоклассовая классификация текста на позитив, негатив и нейтральность.
На текущий момент SotA подход — это использование больших языковых моделей, например опенсорсный предобученный rubert-base-cased-sentiment от blanchefort. Модель весит 700 МБ, и на видеокарте P100 скорость обработки составляет более 200 комментариев в секунду. Получается, что для использования этой модели потребовалось бы порядка 13 часов нонстоп вычислений видеокарты. С целью экономии ГПУ ресурсов можно попробовать решить эту задачу альтернативным способом.
Наша команда проделала большую работу, в результате которой была получена модель размером 4 МБ с сопоставимым качеством и скоростью обработки 12 тысяч комментариев в секунду на ЦПУ. Относительно модели на ГПУ это 60-кратный прирост производительности. Помимо этого из коробки поддерживаются эмодзи. Как получилось достичь такого результата?
Продолжение в следующем посте ⤵️****
Привет! На связи команда VK Predict: Вадим Журавлёв и Артём Агафонов, боссы ML-команды.
Сегодня расскажем про нашу команду и направления работы, а в следующих постах подробнее поговорим про задачи и кейсы.
Мы B2B проект и разрабатываем продукты для бизнеса. У нас высоконагруженные сервисы с 2,5 млн+ запросов в сутки и 100 моделей в продакшне.
Что мы делаем:
Разработка моделей ранжирования. Здесь мы предсказываем, к каким событиям склонны пользователи, и оцениваем вероятности их действий. Чаще всего решаем задачи бинарной классификации и регрессии.
Дескриптивная аналитика и CRM модели. Ищем паттерны у групп пользователей, профилируем аудиторию, помогаем телеком-операторам улучшать связь в городах, строим Look-alike модели для маркетинга, занимаемся моделями откликов и CRM-моделями.
Геоаналитика. Работаем с геоданными, обрабатываем большие объемы данных, исследуем новые признаки, строим ETL пайплайны, создаем и автоматизируем ML-модели для прогнозирования выручки, трафика, цен и покупок.
Новые инициативы. Создаем кастомные ML-решения, разрабатываем low-code инструменты для автоматизации ML и применяем федеративное обучение для распределенного обучения моделей без обмена данными.
В следующих постах про каждую из задач расскажем подробнее.
Если у вас есть вопросы или идеи, о чем ещё написать, оставляйте комментарии!
Завершаем месяц ведения канала (и рабочую неделю) с пользой ?
Собрали любимые ресурсы с нашим коротким овервью.
Для удобства сгруппировали их в:
Актуальное и тренды:
– Daily доза на хаггинфейсе
– Рассылка с актуальными новостями по пейперам, либам, бенчмаркам и т.д.
– Монитор с новыми статьями на arXiv
– Доза новостей LLM и инструментов в максимально легкой подаче
– Llama Index Linkedin, постят use-кейсы о создании сервисов с LLM
– YouTube-канал Langchain
– Рассылки по LLM и инструментам (и не только)
– Ориентир для on-device подходов от Apple
Классика:
– Классные визуализации (жаль, что уже не актуализируются)
– The Annotated Transformer v2022
– Эталонный курс по базовому ML от ВШЭ
– Эталонный курс по СV
– ML rulebook от Google, в основном system design
– Эталонный курс по NLP
– YouTube-канал Андрея Карпатого
– Блог, в котором просто, понятно и красиво объясняют основные концепции современного DL
– Классный курс по NLP с отличными визуализациями основных концепций, читался в ШАДе
NonML
– Список от Альпины из 52 бизнес-книг, по одной на каждую неделю ?
– Рассылка по system design
– YouTube-канал Лекса Фридмана
– Блог автора легендарного «кабанчика»
– Наш любимый раннер курсов по алгоритмам и его цикл книг по этой тематике
Наше, не теряющее актуальности
– ANN на пальцах
– Ошибки новичка
– Наш курс по классическому ML
– Как мы подходим к выбору лоссов
– Вечно актуальное противостояние спамеров и антиспама
– Чем заняться до найма LLM-команды
Делитесь своими полезными ресурсами в комментариях!
А увидеться и подискутировать можно на профильных ивентах, где мы часто бываем. Стараюсь анонсировать их в своем Linkedin, да и в целом рад пообщаться, на связи!
Пока мы готовим новый пост — делимся полезным анонсом.
Наши коллеги проводят регулярную ридинг-группу онлайн: следующая встреча уже завтра.
Там ребята обсудят модификацию фильтра Блума, которая умеет забывать старые данные.
Ведущий — Роман Болозовский, ML-инженер AI VK.
Детали:
- 7 августа в 17:00
- ссылка на зум
Meeting ID: 777 282 2791
Passcode: 1
- ссылка на календарь
Как вы поняли из прошлого поста, мы всегда за обмен опытом и шаринг знаний, поэтому такое уважаем. Приходите! ?
Привет! На связи снова Дима Меркушов.
Что для меня даже более ценно, чем кластер А100 или компьют в Спарке?
Ребята, которые могут превратить все эти мощности в эстетичные ML-сервисы и production-фичи. Ребята, которые приходили к нам разными путями: кого-то мы вели ещё со времён университета, кто-то становился ценным кадром с рынка, некоторые даже поворачивали на 180 и меняли бекграунд backend/аналитики в пользу нас.
Именно они драйвят наше (и моё) экспертное развитие и совершенствуют наши сервисы.
Поэтому ниже пост про то, что делает нас командой.
Исторически ML в Mail.ru родился в задачах почтового Антиспама. В нашем фольклоре всё ещё жива сложнейшая система кластеризации новых регистраций, которая успешно самообучается с 2012 (!) года (~~работает не трожь~~). Это наследие до сих пор определяет наш профиль как очень MLE-ориентированной команды, нацеленной на sli в 99.999 и realtime хайлоад-сценарии без приставки near.
Сейчас же в нашем профиле есть и прикладной ресерч, и скилл быстрой проверки продуктовых гипотез, и бейзлайны на трансформерах.
Возможность выбирать свою нишу (и ротировать её при желании) – суперсила, которую отмечают все без исключения.
Важная составляющая синергии команды – офис. Офис VK (их, кстати, несколько в одной только МСК, и мы иногда меняем локации для разнообразия) предполагает рассадку «ромашкой», что даёт возможность коллабить прямо сидя в своем кресле. Это, конечно, не означает офисный фуллтайм, но мы стараемся регулярно собираться юнитами на груминги и внутренние ивенты.
Кстати, существенная часть команды работает из офисов (и домов) в других городах — и это тоже ок.
Есть у нас еще знаменитый столб (фото в шапке), который в силу меньшей поверхности, чем у регулярного вайтборда, дистиллирует только наши самые ценные мысли.
Мы очень любим митапы и конференции. Помимо того, что сами организовываем (ML митап, конференция VKJT), всегда рады сходить в гости в качестве спикеров или слушателей к коллегам.
Например, мы регулярно отправляем ребят на А* конференции с задачей вытащить интересные инсайты помимо традиционного шортлиста best papers. Потом — устраиваем ламповые обзоры и отбираем самые перспективные штуки для прода (и деплоим).
А ещё мы практикуем регулярные ридинг-встречи в формате 10-minute-papers. Правда в 10 минут укладываемся редко ;)
А что для вас быть частью ML-команды? Расскажите про свои best-practices.
Same-User: NSP для нетекстовых задач
Для анализа действий пользователя в Почте мы применяем поведенческие эмбэддинги. О том, как устроено их обучение, мы рассказывали на прошлогоднем HighLoad++, а в этом посте хочется углубиться в одну частную деталь и рассказать как мы оценивали эмбэддинг пользователя на extrinsic-задаче Next Sentence Prediction (NSP) или, как мы называем ее в команде, Same-User.
Выборка для Same-User состоит из пар (L, R), где L и R — это поведенческие эмбэддинги, полученные моделью (например, трансформер). Same-User – это задача бинарной классификации. Позитивный класс состоит из пар эмбэддингов одного и того же пользователя, а негативный класс — из пар эмбэддингов разных пользователей. Идея проста: обычно пользователь имеет устойчивые паттерны поведения, поэтому эмбэддинги одного пользователя должны быть более похожи, чем эмбэддинги от разных.
Алгоритм для выборки выглядит так:
1. Берем цепочку действий пользователя X за дату T.
2. Разделяем цепочку на две части.
3. Из двух подцепочек получаем пару эмбэддингов (L, R) — это позитивная пара.
4. Чтобы получить негативные пары, перемешиваем случайным образом L и R.
В самом простом варианте код на PySpark будет повторять шаги 1-4. В пункте 4, случайное формирование пар реализовано за счет предварительного перемешивания всех строк в SparkDataFrame, а затем объединения (join) по специальному столбцу, который получили через функцию MONOTONICALLY_INCREASING_ID().
Отметим, что мы решили «резать» цепочку не ровно посередине, а в случайном месте, иначе классификатор легко переобучается: в позитивном классе обе подцепочки имеют равную длину, а в негативном — разную. Если длина исходной цепочки D, то разрез проходил в интервале [0.35 × D, 0.65 × D]; значения 0.35 и 0.65 необходимо подбирать под ваши данные. Теперь в позитивном и негативных классах подцепочки были разных длин, и можно было смело считать ROCAUC. Получилось 97%. Переобучение уменьшилось, но пристальное изучение данных выявило еще одну проблему. Наш негативный класс оказался «слишком простым» для классификатора: из-за склеивания в пары абсолютно случайных подцепочек почти всегда эти подцепочки были настолько разные, что классификатору ничего не стоило их различить.
Первая идея усложнения такая: после формирования случайных пар оставлять только те, в которых есть хотя бы N общих действий (N=1). Этот подход очень легко реализовать в PySpark, но хочется его как-то обобщить. В итоге мы стали оставлять случайные пары подцепочек, которые «близки» (но не сильно) по расстоянию Левенштейна (LevDist). Смысл такой: ранее в пары складывались очень разные цепочки, и LevDist между ними было близко к 1 (мы нормализовали расстояние максимумом из длин входных цепочек), поэтому мы решили, что необходимо оставлять только те пары, в которых LevDist < MAX_LEV_DIST < 1. В нашем случае мы выбрали MAX_LEV_DIST равным 0.85, но здесь многое зависит от ваших данных.
Для пользователей PySpark есть находка, которую мы сделали, когда задумались как считать расстояние Левенштейна. В PySpark есть встроенная функция LEVENSHTEIN(s1, s2), которая работает в разы быстрее чем самописные UDF на Python. Но есть одна проблема: эта функция умеет считать расстояние только между строками, а у нас цепочки действий. Решено было обойти это ограничение следующим образом: мы назначили каждому уникальному действию в нашем словаре (размер ~1K) уникальный символ из Unicode. Теперь цепочки действий можно было представить в виде строк. После описанного выше отбора пар цепочек мы получили ROCAUC ∈ [0.7, 0.9], в зависимости от модели эмбэддинга.
Выводы, которые полезно учесть:
Ограничивать минимальный размер исходной цепочки, которую вы будете разрезать. На слишком коротких цепочках задача будет решаться плохо, так как классификатор не может извлечь ничего полезного из последовательности, в которой всего 2 или 3 действия.
Вместо расстояния Левенштейна мы рассматривали другие меры сходства текстов. В том числе были варианты BLEU и ROUGE, но по итогу для простоты остановились на расстоянии Левенштейна.
Канал для поиска исполнителей для разных задач и организации мини конкурсов
Last updated 2 months, 1 week ago