Интересное что-то
517 subscribers
2.71K photos
253 videos
138 files
4.51K links
Материалы и мысли, понадерганные отовсюду
Блог: https://t.iss.one/asisakov_channel
Чат: https://t.iss.one/youknowds_chat
Download Telegram
Изи стажка в OzonTech💙
#ozon
Недавно кончилась моя стажка в озоне, поэтому напишу кратко про сам отбор и впечатления...

Параллельно с учёбой на 3 курсе искал подработку, наткнулся на сайт с вакансиями, откликнулся на DS поиска и рекомендаций звучало хайпово.

Закинул резюме и оставил tg на сайте. Hr написала спустя месяц:^) я уж и забыл, что вообще подавался. В резюме были общие слова про место учёбы(финашка), ну и 2 курса по машинке, которые брал факультативно

Сначала был созвон с рекрутером(минут 20, тех вопросов не было)
Потом- тех собес; были теорвопросы по sql, простой quizz по видам ключей и joinов, терия ml и pytorch👇
1️⃣написать свёрточную сеть с одним свёрточным слоем и линейным
(параметры задавал тимлид в ходе интервью)
model = torch.nn.Sequential(
torch.nn.Conv2d(3, 16, 3),
torch.nn.ReLU(),
torch.nn.Flatten(),
torch.nn.Linear(16 * 30 * 30, 10)
)

2️⃣дан кусок кода. нужно отдебажить
for epoch in range(10):
y_pred = model(x)
loss = torch.nn.functional.mse_loss(y_pred, y)
loss.backward()
optimizer.step()
# тут надо вставить optimizer.zero_grad() перед backward

3️⃣написать класс логрегрессии
class LogisticRegression(nn.Module):
def __init__(self, input_dim):
super().__init__()
self.linear = nn.Linear(input_dim, 1)

def forward(self, x):
return torch.sigmoid(self.linear(x))

def fit(self, X, y, epochs=100, lr=0.01):
criterion = nn.BCELoss()
optimizer = torch.optim.SGD(self.parameters(), lr=lr)

for epoch in range(epochs):
optimizer.zero_grad()
outputs = self(X)
loss = criterion(outputs, y.unsqueeze(1))
loss.backward()
optimizer.step()

def predict(self, X, threshold=0.5):
with torch.no_grad():
return (self(X) >= threshold).float()

def predict_proba(self, X):
with torch.no_grad():
return self(X)

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

зп: 80к гросс фултайм, считаю, для начала карьерного пути- это хорошо🤓
@zadachi_ds
Please open Telegram to view this post
VIEW IN TELEGRAM
Трансформеры — это база в 2025🤖

без них даже на джун-роль не возьмут, так что пробежимся по must-know

Кратко о сути:

текст сначала разбивается на токены (слова или их фрагменты), которые превращаются в эмбеддинги — плотные числовые векторы, фиксирующие базовое значение слова
главное чудо происходит в self-attention:
тут каждое слово формирует три вектора: Запрос (Q) (что ищу?),
Ключ (K) (как найти?),
Значение (V) (что знаю?)
🔜 Q текущего слова сравнивается (скалярное произведение) с K каждого слова в предложении, вычисляя их релевантность
🔜 Эти оценки превращаются в веса внимания (softmax), показывающие, какое влияние оказывают другие слова на текущее
🔜 Итоговое представление слова — динамическая сумма векторов V всех слов, взвешенная по важности

Так "ключ" (дверной) в контексте "замок" и "дверь" кардинально отличается от "ключ" (музыкальный) рядом с "ноты" и "скрипичный"
multi-head attention использует несколько независимых наборов параметров (голов), чтобы параллельно анализировать разные типы связей (например, грамматические и семантические)
также необходимо позиционное кодирование (специальные сигналы), чтобы передать порядок слов

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


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

@zadachi_ds_chat
Please open Telegram to view this post
VIEW IN TELEGRAM
Изи стажка в VKВидео✅️
#vk
В начало

Делюсь отзывом о стажировке от выпускника наших курсов. Учусь на 4 курсе бизнес-информатики в ВШЭ. Всё началось с моего друга, он уже работал в вк и дал контакт своего эйчара. Я отправил резюме, и через месяц мне пришла обратная связь на почту... кхе-кхе
Ваше резюме заинтересовало

и просьба связаться с hr. Списались в tg. Было сказано, мол будет алгоритмическая задачка и теория по ML, но я бы сузил до алгоритмическая задачка и рекомендашки

По сути вышло 3 этапа: созвон с эйчаром, тех-собес на 1.5 часа, финал с командой

Тех.собес
1.собеседующий рассказал, почему пошёл в вк (кстати, лично я кайфанул от прикольной фичи в офисе, такой как безлимитная кола(стоит автомат как в бургер кинге:), иногда засиживался на кофе-поинтах в ноуте из-за этого)
2.Алгоритмическая таска
Дан массив чисел и число k. Нужно вернуть k самых частых элементов
по решению: считаем частоту чисел через хеш-мапу, сортируем пары (число, частота) по убыванию частоты, берём первые k элементов, O(NlogN) асимптотика
3.Блок с рекомендашками
написать функцию, которая вычисляет Precision@K
def precision_at_k(recommended_items, relevant_items, K):
top_k = recommended_items[:K]
relevant_in_top_k = [item for item in top_k if item in relevant_items]
return len(relevant_in_top_k) / K if K > 0 else 0.0


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

можно ранжировать айтемы по вероятности клика(CTR, например), учитывая контекст: время, устройство и историю просмотров, после чего делать A/B-тесты и добавлять разнообразие(избегаем застревания в одной категории), повышая вовлечённость

написать формулы метрик ранжирования, которые помню(написал MAP, nDCG, MRR), обсудили ранговую корреляцию+ попросил рассказать основные подходы к построению рекомендательных систем

Финал
ребята рассказали о себе, я поделился своими пет-проектами; в целом, словили общий вайб

через 3 дня дали офер

По стажке
понравился опыт, лично я дорабатывал алгоритмы рекомендаций, крутил данные, проверял гипотезы и даже пару раз устроил небольшой баг в A/B-тестах (но быстро поправил!)
+ немного помогал внедрять фичи в бекенд

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

зп: 80к гросс, 3 месяца
@zadachi_ds_chat
Please open Telegram to view this post
VIEW IN TELEGRAM
Авторы вспомнили мутационные алгоритмы, которые я ненавидела в бакалавриате, когда мы их проходили, и утверждают, что это заменит RLHF

Если коротко АМЕРИКАНСКИЕ УЧЕННЫЕ придумали как заставить модель учиться на своих ошибках от артефактов CoT (ну а что он тупо существует, еще и жалуются ходят, что он не показывает настоящих размышлений модели)

Работает все следующих образом:

1) запускаем модель на минибатч задач по определенному классу
2) собираем с запуска всякие CoT, тул коллы (когда работаем с агентами), ошибки с компиляторов, когда это кодовые задачи и тд
3) другая LLM-ка смотрит на артефакты и выдает экспертное мнение чего не хватало в промпте, чтобы модель получше ПОДУМОЛА

За что лайк: вместо жадного выбора лучшего кандидата (который ведет к локальным оптимумам), GEPA строит Парето-фронт:
💛Сохраняет всех кандидатов, которые лучше хотя бы на одной задаче
💛Убирает полностью доминируемых
💛Стохастически выбирает из оставшихся

Это дает exploration без раздувания пула кандидатов. GEPA также может скрещивать кандидатов. Если один хорошо эволюционировал модуль А, а другой — модуль Б, то берет лучшие части от каждого

В общем то что? Понятное дело, авторы делают ставку на интерпретируемость процесса эволюции, меньшее время подбора систем промптов таким способом в сравнении с RL обучением, но как это работает на самом деле не понятно, ни кода, ни модели, которая победила модель с GRPO, нифига на руках не имеется.

🖼💅

📖Папир
Please open Telegram to view this post
VIEW IN TELEGRAM
Forwarded from Refat Talks: Tech & AI
This media is not supported in your browser
VIEW IN TELEGRAM
🤩 Как новенький LangExtract от Google может помочь в AI работе с доками, RAG и не только

Неделю назад Google тихо выпустил библиотеку, которая решает боль production LLM систем: как гарантировать, что извлеченные данные действительно есть в источнике, а не выдуманы моделью. Ты задаешь примеры что хочешь извлечь из текста (например, даты и суммы из контракта), LangExtract находит все такие элементы и показывает где именно каждый находится в документе, гарантируя что ничего не выдумано. Мне как раз надо было что-то подобное, я полез изучать, потом залез в исходники и залип.

Ключевая инновация - Source Grounding
Каждое извлечение привязано к точным координатам в тексте. Парсите контракт на 50 страниц? Система не просто скажет "срок оплаты 30 дней", но и покажет exact char positions где это написано. Под капотом - умный fuzzy matching алгоритм, который находит источник даже если LLM слегка перефразировал. То есть да, это как NER только без обучения, и как structured outputs, но с точным и надежным определением координат цитаты.

А еще на основе моих тестов эта штука поразительно хорошо и быстро работает с длинными документами.

Ботанский кусок (разверните кому интересно):
Покопался в исходниках, рассказываю суть.

По сути LangExtract = Few-shot Information Extraction + Structured Outputs + Automatic Source Grounding.

В отличие от простого использования structured outputs, автоматически находит точное местоположение типа {"startpos": 41, "endpos": 57}.

Общий принцип:

Документ → [Chunking] → [LLM + Schema] → [alignment phase] → Результат с позициями

Трехуровневый alignment (exact → case-insensitive → fuzzy) покрывает все основные кейсы, результаты потом валидируются.

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

На входе использует example-driven подход - вместо написания промптов вы предоставляете несколько примеров того, что хотите извлечь. Из этих примеров автоматически генерируется JSON schema для structured output и создается few-shot промпт. Поддержка разных LLM провайдеров (Gemini, OpenAI, Ollama) с оптимизациями под каждый.

А с длинными доками хорошо работает за счет трех элегантных решений:
- Intelligent chunking с сохранением границ предложений (не тупое разбиение по токенам)
- Multi-pass extraction - несколько независимых проходов, каждый может найти что-то новое, результаты консолидируются
- Массивная параллелизация - десятки чанков обрабатываются одновременно

Есть встроенная HTML-визуализация с подсветкой найденных элементов прямо в исходном тексте (показана на видео).

Некоторые альтернативы: Instructor/Marvin/Outlines.


Use кейсы для вдохновления:
- Контракты на 100+ страниц - находит все суммы и сроки с точной ссылкой на цитату, можно легко интегрировать в UI "подсветку" фактов
- Медкарты с записями - извлекаем дозировки лекарств с гарантией и визуальным указанием источника
- Data Science стал еще доступнее: на вход тысячи не структурированный документов, на выход - CSV с нужными колонками и точными координатами откуда взял
- Извлекаете из корпоративной wiki, email, Slack: люди, проекты, технологии, их связи. Строим графы знаний - Profit!

Главное: LangExtract не просто надежно извлекает, но еще и доказывает откуда взял каждый факт.
Двигаемся еще ближе от "LLM как магический черный ящик" к "LLM как надежный production инструмент".

Блогпост | Репа

🔥🔁
Спустя долгое время отсутствия приношу пост 👀

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

Так вот это довольно легко сделать (по крайней мере на Linux) с помощью дебагера gdb

Делается так:
0. Сохраняем локально файл libpython.py. Это нужно, чтобы в gdb стек и код вокруг отображался "по-питонячему" (иначе это будет малопонятный C++).
- Для этого открываем CPython на гитхабе
- Переключаемся с main ветки на tag с версией питона, которым запущен зависший код
- Скачиваем файл libpython.py (например `wget https://raw.githubusercontent.com/python/cpython/refs/tags/v3.13.5/Tools/gdb/libpython.py`)
1. Подключаемся к зависшему питонячему процессу
sudo gdb -p 68653
2. Подключаем файл
source libpython.py
3. Выбираем нужный поток, если их несколько
info threads - показать все
thread 1 - выбрать первый
4. Смотрим стек
py-bt
5. Смотрим код вокруг
py-list
6. Смотрим переменные
py-locals
7. Двигаемся по стеку выше/ниже
py-up
py-down

Все команды можно посмотреть как раз в файле libpython.py, который мы скачивали на шаге 0

Один-два раз это упражнение делаешь - код болеть не будет! 💪
Можно, кстати, проще (https://wiki.python.org/moin/DebuggingWithGdb)
gdb python -p pid

и можно сразу переходить к пункту 3
Forwarded from Душный NLP
Demons in the Detail: On Implementing Load Balancing Loss for Training Specialized Mixture-of-Expert Models

Сегодня разберём статью от команды Qwen о том, как они придумали новый LBL-лосс для обучения MoE.

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

Обычно LBL считают на уровне отдельного микробатча каждого DP-ранка, а потом усредняют полученные LBL по всем микробатчам. Но заставлять роутер распределять токены равномерно в рамках одного микро-батча — довольно строгое ограничение. Пара длинных семплов может заполнить весь микро-батч, и тогда, если эти семплы пришли из одного домена, роутер всë равно будет вынужден разослать эти токены равномерно по всем экспертам. Так теряется логика специализации экспертов.

Для того чтобы избежать потери специализации, авторы предлагают считать LBL на уровне глобального батча (global-batch), где больше разнообразия данных. Как? Добавляют шаг коммуникации: синхронизируют нужные для подсчёта LBL статистики роутера по выбору экспертов со всей DP-группы, то есть со всех микробатчей. Рассмотрим пример:

1. Вообразим 2 карты и обучение с DP.
2. А к ним — 4 эксперта и 16 токенов (после пермьюта).
На первой карте токены распределятся по экспертам так: [0, 0, 8, 8]. На второй — [8, 8, 0, 0].
3. Для micro-lbl этот лосс будет на каждой карте ругать роутер за неравномерное распределение токенов.
5. Но если мы соберём глобальную статистику (то есть, сложим вектора распределений со всех карт), то получим [8, 8, 8, 8]. Это идеальная равномерность и macro-lbl на такое не обижается.
6. macro-lbl даёт роутеру больше свободы, что конвертируется в прирост качества.

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

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

Разбор подготовил Даниил Сухой

Душный NLP
Please open Telegram to view this post
VIEW IN TELEGRAM
Forwarded from Information Retriever
Sampled Softmax for Large-Scale Retrieval.

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

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

А вот что нам подходит — это softmax-лосс. Можно сформулировать задачу рекомендации в виде экстремальной классификации, в которой каждому айтему соответствует свой класс (экстремальной — потому что много классов). Если пользователь лайкнул трек, то что это был за трек? Считаем для каждого трека некоторый скор (читай «логит»), затем превращаем скоры в вероятностное распределение, применив softmax. Учим модель максимизировать правдоподобие правильного класса — минимизируем кросс-энтропийную функцию потерь. При таком обучении в саму модель заложено, что мы должны уметь делать глобальное ранжирование между всеми айтемами в каталоге.

У такого лосса есть одна «большая» проблема — чем больше каталог, тем сложнее посчитать сам softmax. В знаменателе есть сумма экспонент от логитов по всему каталогу. Нам в целом не нужно считать сам лосс, важен только градиент, но в градиенте эта сумма тоже присутствует. Чтобы это побороть, можно использовать сэмплирование негативов — вместо суммы скоров по всему каталогу считать её по небольшому сэмплированному подмножеству. Популярные стратегии сэмплирования — равномерное (выбираем айтемы из каталога абсолютно случайно) и униграммное (пропорционально популярности айтема). Частный случай униграммного — in-batch сэмплирование: при обучении нейросетей мы набираем «батчи» из положительных пар (пользователь, айтем), и можно для каждого пользователя из батча использовать в качестве негативов чужие позитивы из этого же батча.

Почему же всё-таки недостаточно простого равномерного сэмплирования? Здесь поможет следующая интуиция: «полный» softmax-лосс неявно занимается майнингом негативов — у айтемов из каталога, которым модель даёт высокий скор, большой вклад в градиент. Это отличительное свойство softmax-а — например, у BPR-лосса, если модель сильно ошибается в каком-то айтеме, его вклад в градиент всё равно сильно ограничен. Поэтому, если мы хотим аппроксимировать softmax-лосс, нам важно сэмплировать как можно больше «сложных, информативных» негативов, в которых модель ошибается и у которых был бы большой вклад в градиент. А равномерное сэмплирование, особенно при больших каталогах, будет давать простые негативы. Добиться хорошего качества с равномерными негативами всё равно можно, но понадобится гораздо большее количество негативов, чем при использовании альтернативных, более «сложных» источников негативов.

А вот при униграммном сэмплировании мы получаем популярные айтемы, которые чуть ли не по определению имеют высокий средний скор у пользователей и поэтому представляют из себя более «сложные» негативы. Но и здесь не без проблем :) Что же идёт не так — я расскажу в следующем посте.

P.S.: это я вас так готовлю к посту про статью, которую у нас приняли на RecSys :) А ещё это небольшое переосмысление прошлого поста на ту же тему. Что-то похожее я рассказываю в рамках лекции про нейросетевой кандген в ШАД.
Forwarded from Information Retriever
Correcting the LogQ Correction: Revisiting Sampled Softmax for Large-Scale Retrieval.

А вот и наша статья, принятая на RecSys 2025, добралась до arxiv’а! Что мы сделали: улучшили logQ-коррекцию.

Почему это важно: logQ-коррекция активно используется в индустрии для обучения нейросетевых двухбашенных retrieval моделей. Я за свою жизнь в Яндексе неоднократно участвовал в больших и успешных внедрениях нейросетевых кандидатогенераторов, которые не случились бы без logQ-коррекции.

Улучшение связано с тем, как в формуле logQ-коррекции используется положительный айтем (далее именуемый “позитив”). Он появляется в двух местах — и в числителе, и в знаменателе софтмакса. К числителю вопросов нет. А вот в знаменателе есть странности. Например, в исходной статье от Google к позитиву в знаменателе применяется logQ-поправка; а в следующей статье от тех же авторов — уже нет. То есть для сэмплированных негативов в знаменателе logQ-поправка есть, для позитива — нет. А вывод такой формулы нигде не приводится / не обосновывается.

Более того, само использование позитива в знаменателе выглядит сомнительно. Оригинальный вывод формулы, который Bengio проделал в начале нулевых для доисторических языковых моделей, гласит: для оценки знаменателя софтмакса можно насэмплировать айтемы из произвольного распределения Q (обычного называемого proposal distribution) и добавить к ним ту самую “logQ-поправку”. Распределение Q — это как раз и есть то распределение, из которого мы сэмплируем негативы; которое чаще всего является in-batch распределением.

И когда мы рассматриваем конкретный обучающий пример, то есть конкретную пару (user, positive item), и для нее считаем сэмплированный softmax-лосс с logQ-коррекцией, мы не сэмплируем позитив из распределения Q — он приходит к нам детерминированно, с вероятностью 1. А в формуле он используется для Монте-Карло оценки в предположении, что мы сэмплируем его из Q.

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

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

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

Ещё хочется немного подсветить остальную ценность статьи. До этого я не видел в академической литературе замеры на публичных датасетах для logQ-коррекции. Мы эти замеры сделали и показали, что популярная в индустрии logQ-коррекция хорошо работает и в академическом сетапе. Кроме того, мы, возможно, первыми на этих датасетах показали пользу от mixed negative sampling (таких замеров я тоже раньше не встречал, но здесь уже меньше уверен).

И последнее — мы сделали две валидации. Было понимание, что без leave-one-out схемы, как бы я ее ни недолюбливал, есть большая вероятность не пройти ревью :) Но делать только leave-one-out валидацию тоже не хотелось. Поэтому сделали также temporal split валидацию. Получилось, что ранжирование моделей c точки зрения качества в этих двух сетапах заметно различается.

Остальные подробности — читайте в статье!