Реализовать active learning loop
ТЕХНИЧЕСКОЕ ЗАДАНИЕ: Реализовать active learning loop
1. Цель задачи
Разработать и протестировать цикл активного обучения (active learning loop) для задачи классификации коротких текстов. Основная цель — научиться выбирать наиболее неопределённые для текущей модели примеры из пула неразмеченных данных, запрашивать для них метки (в симуляции — у «оракула») и дообучать модель на пополненном размеченном наборе. Ключевой результат итоговая модель, обученная с использованием active learning, должна достигать точности, сопоставимой с моделью, обученной на всех размеченных данных, но при этом используя не более 30% исходного объёма размеченных примеров (т.е. в ~3 раза меньше).
2. Исходные данные
| Что нужно | Откуда взять |
|---|---|
| Неразмеченный набор текстов (1000–2000 примеров) | Открытый датасет: sklearn.datasets.fetch_20newsgroups (категории: sci.space, rec.autos, comp.graphics, talk.politics.guns — 4 класса, ~500 документов на класс) |
| Базовая модель классификатора | Scikit-learn LogisticRegression + эмбеддинги из sentence-transformers/all-MiniLM-L6-v2 (384-мерные векторы) |
| Стратегия отбора примеров | Реализовать uncertainty sampling: минимальная уверенность (least confidence), margin sampling, entropy — на выбор |
| Оракул (разметчик) | Симулировать — истинные метки из того же датасета, «запрос» возвращает метку из скрытого массива |
| Метрики качества | Accuracy, F1 (macro), кривая обучения (число запросов vs точность) |
Если нет реального инструмента — симулируем:
- Загружаем датасет 20newsgroups с помощью sklearn.datasets.fetch_20newsgroups.
- Разбиваем на train/test (70/30). Train часть используем как пул неразмеченных данных — метки прячем.
- Случайно выбираем 10 примеров из пула как начальный размеченный набор (seed).
- Создаём массив
y_poolс истинными метками пула — это «оракул». - В цикле: модель предсказывает вероятности для всех неразмеченных, вычисляем метрику неопределённости, выбираем top-k (например, 10), «запрашиваем» метку из
y_pool, добавляем в размеченный набор и удаляем из пула.
3. Технологический стек
| Компонент | Инструменты | Назначение |
|---|---|---|
| Язык / среда | Python 3.10+, Jupyter Notebook | Разработка и выполнение |
| Эмбеддинги | sentence-transformers, transformers | Преобразование текстов в векторы |
| Классификация | scikit-learn (LogisticRegression) | Базовая модель |
| Active learning логика | numpy, collections | Реализация цикла и стратегий |
| Визуализация | matplotlib, pandas | Кривые обучения, сравнение |
| Валидация | sklearn.metrics (accuracy, f1_score) | Оценка качества |
4. Этапы выполнения
Этап 1: Подготовка данных и baseline (1 час)
Действия
- Загрузить датасет: from sklearn.datasets import fetch_20newsgroups; подмножество из 4 классов:
categories=['sci.space','rec.autos','comp.graphics','talk.politics.guns']. - Разделить на train (70%) и test (30%). Удалить заголовки, подписи и цитаты (remove=('headers','footers','quotes')).
- Посчитать эмбеддинги для всех текстов с помощью SentenceTransformer('all-MiniLM-L6-v2'). Сохранить как numpy array.
- Обучить baseline на всех train данных (с метками) — записать accuracy / F1 на test.
- Создать класс DataPool: список
pool_indices(все train), списокlabeled_indices(изначально 10 случайных),y_true(истинные метки), embeddings.
Ожидаемый результат этапа
- Загруженный и предобработанный датасет, файл embeddings.npy (опционально).
- Baseline-метрики (accuracy, F1) записаны.
- Класс DataPool готов для использования.
Этап 2: Реализация стратегии отбора (1 час)
Действия
- Реализовать функцию compute_uncertainty(probabilities, strategy='least_confidence'):
- Реализовать функцию select_next_batch(pool, model, strategy, k=10), которая:
- получает вероятности для всех неразмеченных примеров через model.predict_proba
- вычисляет неопределённость по стратегии
- возвращает индексы
kобразцов с наибольшей неопределённостью
- Протестировать на небольшом наборе (первые 50 примеров), убедиться, что отбор корректный.
Ожидаемый результат этапа
- Функции
compute_uncertaintyиselect_next_batch. - Юнит-тест с ручной проверкой (например, пример с известными вероятностями).
Этап 3: Реализация цикла активного обучения (1.5 часа)
Действия
- Написать класс
ActiveLearningLoop:- Инициализация: DataPool, модель (LogisticRegression), стратегия, batch_size, max_queries (например, 100).
- Метод
run():- Цикл до max_queries:
- Обучить модель на
labeled_indices(X = эмбеддинги[labeled_indices], y = y_true[labeled_indices]). - Выбрать batch_size примеров из пула.
- Переместить их из пула в размеченный набор (через oracle).
- Сохранить текущую точность на test (по желанию логировать).
- Обучить модель на
- Цикл до max_queries:
- Логирование: номер итерации, размер размеченного набора, accuracy на test.
- Обучить модель на каждом шаге только на размеченных данных.
- Остановиться, когда исчерпан лимит запросов или пул пуст.
- Запустить цикл с batch_size=10,
max_queries=50(т.е. максимум 10 + 500 = 510 размеченных — около 30% от train).
Ожидаемый результат этапа
- Реализация класса с методом
run(), возвращающим историю (iteration, labeled_size, accuracy). - Вывод лога в консоль или файл.
Этап 4: Сравнение со случайным отбором и baseline (1 час)
Действия
- Реализовать второй цикл с той же инициализацией, но стратегия отбора —
random(случайный выбор из пула). - Запустить его с теми же параметрами (начальный seed, batch_size, max_queries).
- Построить график: ось X — количество размеченных примеров, ось Y — accuracy на test. Три кривые:
- На графике отметить точку, где active learning достигает 95% от baseline accuracy — показать, сколько данных потребовалось.
- Вычислить коэффициент экономии:
(размер baseline набора) / (размер данных, при котором active learning достиг 95% accuracy).
Ожидаемый результат этапа
- График (сохранённый как
learning_curve.png). - Численная оценка экономии: «Active learning достиг 95% baseline accuracy при N примерах (вместо M), что в X раз меньше».
Этап 5: Документация и чистка (0.5 часа)
Действия
- Добавить комментарии и docstrings во все функции.
- Упаковать код в один файл
active_learning_loop.pyи/или Jupyter notebook с ячейками, разделёнными по этапам. - Написать краткий
README.mdс описанием задачи, как запустить, результаты. - Убедиться, что код воспроизводим (зафиксирован
random_state=42).
Ожидаемый результат этапа
- Готовый репозиторий с кодом, графиком, README, requirements.txt (sentence-transformers, scikit-learn, numpy, matplotlib).
5. Критерии приемки (Definition of Done)
- Реализован класс
DataPool, корректно управляющий размеченными/неразмеченными данными. - Реализованы три стратегии неопределённости (least confidence, margin, entropy) — хотя бы одна используется, остальные опциональны.
- Цикл active learning выполняет запросы к оракулу и дообучает модель на каждом шаге.
- Итоговая модель active learning достигает accuracy ≥ 95% от baseline при использовании ≤ 30% размеченных данных.
- Построен график сравнения active learning vs random vs baseline.
- Код воспроизводим:
random_stateфиксирован, зависимости указаны вrequirements.txt. - Присутствует лог процесса (количество итераций, точность на каждом шаге).
- Результат представлен в виде Jupyter notebook или Python-скрипта с комментариями.
6. Ожидаемый результат
Основной артефакт
- Файл
active_learning.ipynb(илиactive_learning.py+README.md) с полным конвейером.
Содержание
- Загрузка и эмбеддинги
- Baseline
- Реализация стратегий
- Цикл active learning
- Сравнение с random
- Визуализация
- Выводы (метрики экономии)
Дополнительные результаты (опционально):
- Сравнение разных стратегий (least confidence vs entropy vs margin) в одной таблице.
- Анализ влияния размера начального seed.
- Эксперимент с другой моделью (например, Random Forest вместо LogisticRegression).
7. Возможные сложности и их решение
| Сложность | Решение |
|---|---|
| Медленное обучение модели на каждой итерации | Использовать быструю линейную модель (LogisticRegression); можно инкрементально обновлять (SGDClassifier с partial_fit) |
| Несбалансированность классов в отобранных batch | Использовать стратифицированный отбор или комбинировать uncertainty с разнообразием (diversity sampling) |
| Выбор начального seed влияет на результат | Повторить эксперимент с несколькими random seeds (3–5) и усреднить кривые |
| «Oracle query» замедляет симуляцию | Просто брать метку из массива (O(1)), не имитировать задержку |
| График не показывает явного преимущества active learning | Уменьшить batch_size (например, до 5), увеличить количество итераций; возможно, эмбеддинги недостаточно информативны — попробовать более качественную модель (e.g., all-mpnet-base-v2) |
8. Бюджет времени (оценка)
| Этап | Время (часов) |
|---|---|
| Этап 1: Подготовка данных и baseline | 1 |
| Этап 2: Реализация стратегии отбора | 1 |
| Этап 3: Реализация цикла активного обучения | 1.5 |
| Этап 4: Сравнение со случайным отбором | 1 |
| Этап 5: Документация и чистка | 0.5 |
| Итого | 5 |
Примечание для первого раза: если вы впервые работаете с sentence-transformers или active learning, заложите дополнительно 1 час на установку библиотек и отладку.
9. Связанные вопросы из базы знаний
| Вопрос | Тема |
|---|---|
| 42 | Оценка неопределённости в классификации (uncertainty estimation) |
| 83 | Методы активного обучения (strategies) |
| 124 | Эмбеддинги текстов с sentence-transformers |
| 201 | Скорость обучения vs количество размеченных данных |
| 289 | Инкрементальное обучение (partial_fit) |
| 314 | Работа с дисбалансом классов в обучении |
| 425 | Сравнение стратегий отбора (empirical evaluation) |
| 518 | Логирование и визуализация экспериментов |
| 637 | Random seed и воспроизводимость |
| 789 | Оценка экономии данных (data efficiency) |
10. Чек-лист самопроверки
- Я загрузил датасет и проверил, что классы сбалансированы.
- Я вычислил baseline на всех размеченных данных и зафиксировал точность.
- Я реализовал хотя бы одну стратегию uncertainty и убедился, что она выбирает разные примеры при разных вероятностях.
- Мой цикл active learning корректно обновляет размеченный набор и пул, не утекая метки.
- Я построил график и вижу, что active learning достигает высокой точности быстрее, чем случайный выбор.
- Я зафиксировал
random_stateи получил воспроизводимые результаты. - Я добавил комментарии и docstrings к ключевым функциям.