/* ============================================================
   aiquests/aiquests-data.jsx — независимая подсистема «Игровые курсы».
   Курс «300 задач по ИИ»: 20 актов, 300 квестов, свои уровни/звания.
   Свой store (localStorage "aiquests-state"). Полностью независим
   от остальной части планера и от подсистемы «Академия».
   Exposes: AIQ_ACTS, AIQ_RANKS, AIQ_DAILY, AIQ_TROPHIES,
   AIQStore, useAIQ, AIQActions, AIQLookup.
   ============================================================ */
const React = window.React;

/* ---- 20 актов × 300 квестов (из «Хроник Повелителя Нейросетей») --- */
const AIQ_ACTS = [{"roman":"I","title":"Деревня Тензоров","from":1,"to":10,"xp":10,"quests":[{"num":1,"title":"Монеты в кошельке","desc":"Создай скаляр, вектор из 5 цен на зелья и матрицу 3×4 «инвентарь трёх героев». Выведи `shape`, `dtype`, `ndim` каждого."},{"num":2,"title":"Перепись деревни","desc":"Сгенерируй тензор из 20 случайных возрастов жителей (`torch.randint`). Найди самого старого, самого юного и средний возраст."},{"num":3,"title":"Карта подземелья","desc":"Построй матрицу 5×5 из нулей и расставь «сокровища» (единицы) в углах и центре — только индексацией."},{"num":4,"title":"Слайсер-мечник","desc":"Из тензора `torch.arange(1, 101)` вырежь: каждое 7-е число, последние 10, все числа с 30 по 60 в обратном порядке."},{"num":5,"title":"Алхимический сплав","desc":"Возьми два вектора «сила зелий» и «цена зелий». Найди зелье с лучшим соотношением сила/цена одной строкой."},{"num":6,"title":"Проклятие типов","desc":"Создай тензор float32, конвертируй в int64 и обратно. Объясни (в комментарии), что потерялось и почему это опасно в бою."},{"num":7,"title":"Зеркальный лабиринт","desc":"Разверни матрицу 4×4 по горизонтали, вертикали и транспонируй. Проверь: какая операция вернёт её в исходный вид, если применить дважды?"},{"num":8,"title":"Фальшивомонетчик","desc":"Среди 50 случайных «монет» (веса 9.5–10.5 г) найди все фальшивые (вес < 9.8) через булеву маску и посчитай убытки."},{"num":9,"title":"Трёхмерный сундук","desc":"Создай тензор 2×3×4 («2 сундука, 3 полки, 4 ячейки»). Достань вторую полку первого сундука и последнюю ячейку каждой полки второго."},{"num":10,"title":"Испытание старейшины","desc":"Реши без подсказок: тензор 6×6 случайных чисел нормализуй каждый столбец в [0, 1] замени всё ниже 0.5 нулями посчитай долю выживших значений."}]},{"roman":"II","title":"Кузница Операций","from":11,"to":20,"xp":15,"quests":[{"num":11,"title":"Броски костей","desc":"Смоделируй 10 000 бросков двух шестигранных кубиков. Посчитай, как часто выпадает сумма 7. Сравни с теорией (16.7%)."},{"num":12,"title":"Броадкастинг-заклинание","desc":"К матрице урона 4×3 прибавь вектор бонусов длины 3 без единого цикла. Потом — вектор-столбец штрафов 4×1. Нарисуй в комментарии, как расширялись размерности."},{"num":13,"title":"Турнир гильдий","desc":"Матрица 5×8: 5 гильдий, 8 турниров, очки. Найди: лучшую гильдию по сумме, самый «жаркий» турнир по разбросу очков (`std`), гильдию-стабильность (минимальный std)."},{"num":14,"title":"Матричный портал","desc":"Перемножь матрицы «герои×навыки» (4×3) и «навыки×монстры» (3×5). Объясни, что означает результат 4×5 и почему `*` здесь не сработает."},{"num":15,"title":"Взвешенная мудрость","desc":"Оценки героя [80, 92, 71] с весами важности [0.5, 0.3, 0.2]. Итоговый балл — одной операцией `torch.dot` или `@`."},{"num":16,"title":"Softmax-оракул","desc":"Логиты предсказаний [2.0, 1.0, 0.1] преврати вручную в вероятности (exp / sum(exp)). Сравни с `torch.softmax`. Проверь, что сумма = 1."},{"num":17,"title":"argmax и argmin — гончие следопыта","desc":"В матрице 6×4 «урон героев по раундам» найди, В КАКОМ раунде каждый герой был лучшим, и кто был лучшим в каждом раунде."},{"num":18,"title":"Стакающиеся свитки","desc":"Три вектора длины 4 объедини через `torch.stack` и через `torch.cat`. Объясни разницу форм результата."},{"num":19,"title":"Клятва einsum (опционально-геройская)","desc":"Повтори квест 14 через `torch.einsum('ij,jk->ik', ...)`. Расшифруй заклинание буква за буквой."},{"num":20,"title":"Испытание кузнеца","desc":"Дан тензор 100×5 (сто героев, пять характеристик). Стандартизуй по столбцам (mean=0, std=1), найди героев, у которых ВСЕ характеристики выше среднего, и выведи их индексы."}]},{"roman":"III","title":"Библиотека Форм и Данных","from":21,"to":30,"xp":20,"quests":[{"num":21,"title":"Свиток-трансформер","desc":"`torch.arange(24)` преврати в формы: 4×6, 2×3×4, 24×1, и обратно в 1D — через `reshape`, `view`, `flatten`. Найди форму, в которую он НЕ влезет, и поймай ошибку через try/except."},{"num":22,"title":"Призрачная размерность","desc":"Освой `unsqueeze`/`squeeze`: вектор длины 10 преврати в 1×10, 10×1, 1×10×1 и обратно. Зачем это нужно перед подачей в модель? (напиши гипотезу)"},{"num":23,"title":"Пиксельное зелье","desc":"Скачай/создай картинку, открой через PIL, преврати в тензор. Изучи форму (C×H×W? H×W×C?), выведи min/max значений и переставь каналы через `permute`."},{"num":24,"title":"Серый ритуал","desc":"Ту же картинку переведи в оттенки серого вручную: взвешенная сумма каналов (0.299R + 0.587G + 0.114B). Сохрани результат и посмотри глазами."},{"num":25,"title":"Ковёр из заплаток","desc":"Разрежь картинку-тензор на 16 квадратных патчей (4×4 сетка) через reshape/slicing и собери обратно в перемешанном порядке. Получился пазл!"},{"num":26,"title":"CSV-гримуар","desc":"Найди любой CSV-датасет (например, про вина или ирисы), загрузи через pandas, преврати числовые колонки в тензор. Выведи форму и статистики."},{"num":27,"title":"Пропавшие души","desc":"В датасете из квеста 26 (или искусственном) найди NaN-значения, посчитай их и замени медианой столбца. Всё — тензорными операциями или pandas."},{"num":28,"title":"Раскол королевства","desc":"Раздели данные на train/valid/test (70/15/15) со случайным перемешиванием через `torch.randperm`. Проверь, что ни один пример не потерялся и не задублировался."},{"num":29,"title":"One-hot заклинание","desc":"Вектор классов [0, 2, 1, 3, 2] преврати в one-hot матрицу вручную (через индексацию нулевой матрицы), потом сравни с `torch.nn.functional.one_hot`."},{"num":30,"title":"Испытание библиотекаря","desc":"Собери мини-пайплайн: CSV очистка NaN стандартизация train/valid split тензоры X и y правильных форм (строки = примеры!). Оформи как функцию `prepare_data(path)`."}]},{"roman":"IV","title":"Пещера Градиентов","from":31,"to":40,"xp":25,"quests":[{"num":31,"title":"Первая искра autograd","desc":"Создай `x = torch.tensor(3.0, requires_grad=True)`, вычисли `y = x**2 + 2*x`, вызови `y.backward()`. Проверь `x.grad` вручную по формуле производной."},{"num":32,"title":"Цепное проклятие","desc":"Составь функцию из трёх вложенных операций (например, `z = sin(x²) * 3`). Посчитай градиент autograd'ом и сверь с ручным chain rule на бумаге."},{"num":33,"title":"Спуск с горы вслепую","desc":"Найди минимум функции `f(x) = (x-5)² + 3` градиентным спуском вручную: цикл из 50 шагов, `x -= lr * x.grad`, не забудь обнулять градиент. Выведи траекторию."},{"num":34,"title":"Скорость решает","desc":"Повтори квест 33 с lr = 0.001, 0.1, 1.0, 2.0. Опиши, что случилось в каждом случае (медленно / хорошо / скачет / взорвался)."},{"num":35,"title":"Долина двух минимумов","desc":"Возьми `f(x) = x⁴ - 3x² + x`. Запусти спуск из точек -2 и +2. Покажи, что финиш зависит от старта — вот почему нейросети «застревают»."},{"num":36,"title":"Линейный провидец","desc":"Сгенерируй данные `y = 3x + 7 + шум`. Обучи параметры w и b градиентным спуском с MSE-лоссом, написанным вручную. Должно сойтись к ~3 и ~7."},{"num":37,"title":"Кристалл потерь","desc":"Для квеста 36 построй график loss по эпохам (matplotlib). Найди эпоху, после которой улучшение почти остановилось."},{"num":38,"title":"Многорукий предсказатель","desc":"Расширь квест 36 до 3 признаков: `y = 2x₁ - x₂ + 0.5x₃ + 4`. Теперь w — вектор, и всё через матричное умножение `X @ w + b`."},{"num":39,"title":"Оптимизатор-фамильяр","desc":"Перепиши квест 38, заменив ручной спуск на `torch.optim.SGD`, а ручной MSE — на `nn.MSELoss`. Убедись, что результат тот же, а кода меньше."},{"num":40,"title":"Испытание пещеры","desc":"Полиномиальная регрессия: данные из `y = x³ - 2x² + шум`, признаки [x, x², x³], обучение через optim. Нарисуй облако точек и кривую предсказаний поверх."}]},{"roman":"V","title":"Башня Первых Нейросетей","from":41,"to":50,"xp":30,"quests":[{"num":41,"title":"Голем из одного нейрона","desc":"Реализуй нейрон вручную: `sigmoid(w·x + b)`. Обучи его решать задачу «И» (AND) на 4 примерах."},{"num":42,"title":"Провал голема","desc":"Докажи экспериментом, что один нейрон НЕ может выучить XOR: обучай 5000 эпох и покажи, что loss застрял."},{"num":43,"title":"Двухэтажная башня","desc":"Собери сеть из 2 слоёв вручную (матрицы W1, W2 + ReLU между ними) и победи XOR. Момент истины глубокого обучения!"},{"num":44,"title":"nn.Module — родовой замок","desc":"Перепиши квест 43 как класс, наследующий `nn.Module`, с `__init__` и `forward`. Выведи `model.parameters()` и посчитай общее число параметров."},{"num":45,"title":"MNIST: врата подземелья","desc":"Загрузи MNIST через `torchvision.datasets`. Изучи: сколько примеров, какие формы, нарисуй сетку 3×3 случайных цифр с подписями-метками."},{"num":46,"title":"DataLoader-караван","desc":"Оберни MNIST в `DataLoader` с batch_size=64 и shuffle. Достань один батч, объясни каждое измерение его формы [64, 1, 28, 28]."},{"num":47,"title":"Классификатор цифр","desc":"Полносвязная сеть (784 128 10), CrossEntropyLoss, Adam, 3 эпохи. Цель: точность > 95% на тесте. Напиши цикл обучения полностью сам."},{"num":48,"title":"Матрица заблуждений","desc":"Построй confusion matrix для модели из квеста 47. Какие цифры сеть путает чаще всего? Выведи 9 самых «позорных» ошибок картинками."},{"num":49,"title":"Дуэль активаций","desc":"Обучи ту же сеть с ReLU, Sigmoid, Tanh и вообще без активации. Сравни кривые loss на одном графике. Объясни аутсайдера."},{"num":50,"title":"Босс башни: FashionMNIST","desc":"Полный пайплайн с нуля на FashionMNIST: данные модель обучение оценка confusion matrix сохранение весов через `torch.save`. Точность > 87%."}]},{"roman":"VI","title":"Земли Обучающих Ритуалов","from":51,"to":60,"xp":35,"quests":[{"num":51,"title":"Собственный Dataset-артефакт","desc":"Напиши класс `Dataset` (`__len__`, `__getitem__`) для табличных данных из Акта III. Скорми его DataLoader'у и обучи регрессию."},{"num":52,"title":"Переобучение — тёмная сторона","desc":"Обучи слишком большую сеть на крошечной выборке (100 примеров MNIST). Покажи на графике: train loss падает, valid loss растёт. Это лицо врага."},{"num":53,"title":"Щит Dropout","desc":"Добавь `nn.Dropout` в модель из квеста 52 и покажи, как разрыв между train и valid сокращается."},{"num":54,"title":"Оковы weight decay","desc":"Тот же эксперимент, но с L2-регуляризацией (weight_decay в Adam). Сравни три версии: голая / dropout / weight decay."},{"num":55,"title":"Ранний уход с бала","desc":"Реализуй early stopping вручную: сохраняй лучшие веса по valid loss, останавливайся после 5 эпох без улучшения."},{"num":56,"title":"Кривая обучаемости","desc":"Обучи модель на 1%, 5%, 25%, 100% данных MNIST. Построй график «размер данных точность». Сделай вывод, что дороже: данные или архитектура."},{"num":57,"title":"Планировщик судьбы","desc":"Подключи `lr_scheduler` (StepLR или CosineAnnealing). Нарисуй, как менялся learning rate по эпохам, и сравни финальную точность с постоянным lr."},{"num":58,"title":"BatchNorm-тотем","desc":"Добавь `nn.BatchNorm1d` в глубокую сеть (5+ слоёв) и покажи, что обучение стало быстрее/стабильнее, чем без него."},{"num":59,"title":"Аугментация иллюзий","desc":"Через `torchvision.transforms` добавь к FashionMNIST случайные повороты и сдвиги. Покажи 6 версий одной картинки и прирост точности на тесте."},{"num":60,"title":"Испытание ритуалиста","desc":"Напиши универсальную функцию `train_model(model, train_dl, valid_dl, epochs, lr)`, которая логирует метрики, делает early stopping и возвращает историю. Это твой меч на все следующие акты."}]},{"roman":"VII","title":"Королевство Зрения","from":61,"to":70,"xp":40,"quests":[{"num":61,"title":"Свёртка голыми руками","desc":"Реализуй 2D-свёртку циклами (без conv2d!) для ядра 3×3. Прогони по картинке ядра «размытие» и «поиск границ» (Собель). Посмотри результат глазами."},{"num":62,"title":"Первый Conv-голем","desc":"Собери CNN для FashionMNIST: 2 conv-слоя + pooling + полносвязная голова. Победи свою полносвязную сеть из квеста 50."},{"num":63,"title":"Глаза голема","desc":"Визуализируй фильтры первого conv-слоя обученной сети и feature maps для одной картинки. Что «видит» сеть на первом слое?"},{"num":64,"title":"CIFAR-10: цветное королевство","desc":"Обучи CNN на CIFAR-10 (уже 3 канала!). Цель — точность > 70%. Опиши, что стало сложнее по сравнению с MNIST."},{"num":65,"title":"Пришествие FastAI","desc":"Реши CIFAR-10 через `vision_learner` FastAI с resnet18 за ~10 строк. Сравни точность и количество кода с квестом 64. Прочувствуй мощь."},{"num":66,"title":"fine_tune — магия предков","desc":"Разберись, что делает `fine_tune`: заморозка, обучение головы, разморозка. Повтори эти шаги вручную через `freeze`/`unfreeze` и `fit_one_cycle`."},{"num":67,"title":"lr_find — компас безумца","desc":"Используй `learn.lr_find()`, объясни график и обучи модель с найденным lr. Сравни с наугад выбранным."},{"num":68,"title":"Свой датасет из недр интернета","desc":"Собери 100–150 картинок 3 классов на свой вкус (драконы/грифоны/василиски? коты/собаки/капибары?), оформи через `ImageDataLoaders`, обучи классификатор."},{"num":69,"title":"Суд над моделью","desc":"Для квеста 68 примени `ClassificationInterpretation`: `plot_top_losses`, confusion matrix. Найди мусорные картинки в данных и переобучи после чистки."},{"num":70,"title":"Босс королевства","desc":"Выведи модель из квеста 68 «в мир»: сохрани через `learn.export()`, загрузи в отдельном скрипте и сделай предсказание по любой картинке из интернета с выводом вероятностей."}]},{"roman":"VIII","title":"Земли Слова","from":71,"to":80,"xp":45,"quests":[{"num":71,"title":"Токены — руны языка","desc":"Напиши простейший токенизатор: текст слова словарь индексы. Прогони абзац любимой книги и выведи топ-10 частых токенов."},{"num":72,"title":"Мешок слов-заклинаний","desc":"Реализуй bag-of-words для 20 коротких отзывов (придумай или найди) и обучи логистическую регрессию на PyTorch отличать позитив от негатива."},{"num":73,"title":"Embedding-кристаллы","desc":"Замени one-hot на `nn.Embedding`. Обучи модель из квеста 72 с эмбеддингами и визуализируй полученные векторы слов в 2D (PCA/t-SNE)."},{"num":74,"title":"Геометрия смысла","desc":"Скачай готовые эмбеддинги (или обучи word2vec через gensim). Проверь легендарное: король − мужчина + женщина ≈ ? Найди 5 своих аналогий."},{"num":75,"title":"Хроники следующего символа","desc":"Обучи char-level модель предсказывать следующий символ на маленьком тексте (например, именах драконов). Сгенерируй 10 новых имён."},{"num":76,"title":"LSTM — память старца","desc":"Замени простую сеть из квеста 75 на `nn.LSTM`. Сравни качество генерации. Объясни своими словами, зачем нужна «память»."},{"num":77,"title":"Attention на пальцах","desc":"Реализуй self-attention для одного предложения вручную: Q, K, V, softmax(QKᵀ/√d)·V. Визуализируй матрицу внимания как heatmap."},{"num":78,"title":"Классификатор настроений FastAI","desc":"Через `text_classifier_learner` FastAI обучи анализ тональности на IMDB (или его сэмпле). Проверь на 5 своих придуманных отзывах."},{"num":79,"title":"Трансформер из сундука HuggingFace","desc":"Возьми предобученный `distilbert` через `transformers`, дообучь на классификацию любого маленького текстового датасета. Сравни с квестом 78."},{"num":80,"title":"Босс земель слова","desc":"Построй семантический поиск: возьми 50+ цитат/абзацев, посчитай эмбеддинги (sentence-transformers), реализуй поиск по косинусной близости. Задай 5 запросов и оцени результаты."}]},{"roman":"IX","title":"Запретные Земли","from":81,"to":90,"xp":55,"quests":[{"num":81,"title":"Автоэнкодер — зеркало души","desc":"Обучи автоэнкодер сжимать MNIST до 2 измерений. Нарисуй латентное пространство: точки-цифры раскрась по классам. Увидишь кластеры!"},{"num":82,"title":"Генерация из пустоты","desc":"Пройдись по латентному пространству квеста 81 сеткой точек и декодируй каждую в картинку. Получи карту «всех возможных цифр»."},{"num":83,"title":"Denoising-очищение","desc":"Обучи автоэнкодер убирать шум: на вход — зашумлённые цифры, на выход — чистые. Покажи до/после на 5 примерах."},{"num":84,"title":"GAN: дуэль двух магов","desc":"Обучи простейший GAN на MNIST: генератор против дискриминатора. Сохраняй сгенерированные картинки каждую эпоху и собери «эволюцию» подделок."},{"num":85,"title":"Перенос стиля","desc":"Реализуй neural style transfer (по Гатису): контент одной картинки + стиль другой через фичи VGG. Преврати свою фотографию в картину."},{"num":86,"title":"Сегментация владений","desc":"Через FastAI `unet_learner` обучи сегментацию на CamVid (сэмпл встроен). Визуализируй маски: где дорога, где небо, где пешеходы."},{"num":87,"title":"Табличный оракул","desc":"FastAI `tabular_learner` на датасете Adult (или своём): категориальные + числовые признаки, embedding'и категорий. Сравни с градиентным бустингом (sklearn) — кто победит?"},{"num":88,"title":"Рекомендатель таверны","desc":"Коллаборативная фильтрация через FastAI `collab_learner` на MovieLens: предскажи рейтинги, найди «скрытые жанры» в эмбеддингах фильмов."},{"num":89,"title":"Агент в лабиринте","desc":"Реализуй Q-learning (таблицей, без нейросетей) для FrozenLake из gymnasium. Обучи агента доходить до цели и выведи карту выученной стратегии."},{"num":90,"title":"Босс запретных земель","desc":"Deep Q-Network: замени таблицу из квеста 89 нейросетью и обучи агента на CartPole. Балансируй шест 200+ шагов. Запиши видео триумфа."}]},{"roman":"X","title":"Цитадель Архимага","from":91,"to":100,"xp":70,"quests":[{"num":91,"title":"Мини-GPT своими руками","desc":"Следуя духу nanoGPT: собери маленький трансформер (2–4 блока) и обучи на любимой книге генерировать текст «в стиле автора»."},{"num":92,"title":"Интерпретация — истинное зрение","desc":"Примени Grad-CAM к своей CNN из Акта VII: подсвети, КУДА смотрела сеть, принимая решение. Найди случай, где она смотрела не туда."},{"num":93,"title":"Атака иллюзий","desc":"Создай adversarial-пример (FGSM): добавь к картинке невидимый глазу шум, который заставит модель ошибиться с уверенностью 99%. Задумайся о последствиях."},{"num":94,"title":"Дистилляция знаний","desc":"Обучи маленькую сеть-ученика повторять «мягкие» предсказания большой сети-учителя. Покажи, что ученик с учителем лучше ученика-одиночки."},{"num":95,"title":"Своя архитектура","desc":"Придумай и реализуй собственную модификацию архитектуры (skip-connection по-своему, свой блок, своя активация). Честно сравни с базой на одном датасете. Отрицательный результат — тоже результат!"},{"num":96,"title":"Соревновательный поход","desc":"Зарегистрируйся на Kaggle, возьми любое учебное соревнование (Titanic, Digit Recognizer, Playground) и отправь сабмит. Улучши результат минимум дважды."},{"num":97,"title":"Модель на службе людям","desc":"Оберни любую свою модель в веб-приложение (Gradio/Streamlit): загрузка картинки/текста предсказание. Дай ссылку другу и собери обратную связь."},{"num":98,"title":"Хроники эксперимента","desc":"Возьми любой квест из Актов VII–IX и проведи его как настоящее исследование: 5+ конфигураций, таблица результатов, графики, письменные выводы. Оформи как отчёт в markdown."},{"num":99,"title":"Чтение древних свитков","desc":"Возьми одну классическую статью (ResNet, Attention Is All You Need, U-Net — на выбор), прочти и воспроизведи её ключевую идею в упрощённом виде кодом."},{"num":100,"title":"ФИНАЛЬНЫЙ БОСС: Артефакт Творения","desc":"Полный проект от идеи до продукта: своя задача сбор данных бейзлайн итерации улучшений интерпретация деплой README с историей проекта. Тема — твоя. Это твой посох Архимага."}]},{"roman":"XI","title":"Глубины Оптимизации","from":101,"to":120,"xp":60,"quests":[{"num":101,"title":"Анатомия оптимизаторов","desc":"Реализуй с нуля SGD, SGD+momentum, RMSprop и Adam как классы. Обучи одну сеть каждым и наложи кривые loss на один график. Объясни, почему Adam стартует резвее."},{"num":102,"title":"Ландшафт потерь","desc":"Возьми обученную сеть, зафиксируй два случайных направления в пространстве весов и построй 2D/3D-карту loss вокруг минимума. Найди, «плоский» он или «острый»."},{"num":103,"title":"Проклятие затухающих градиентов","desc":"Собери сеть из 20 слоёв с sigmoid без нормализации. Выведи норму градиента на каждом слое — покажи, как она гаснет к началу. Затем «вылечи» через ReLU + He-инициализацию."},{"num":104,"title":"Взрыв градиентов и щит клиппинга","desc":"Спровоцируй взрыв градиентов в RNN, поймай его по `grad_norm`, укроти через `clip_grad_norm_`. Построй график норм до и после."},{"num":105,"title":"Тайна инициализации","desc":"Обучи одну сеть с инициализацией: нулями, большими случайными, Xavier, He. Покажи, что три из четырёх — катастрофа, и объясни математику каждой."},{"num":106,"title":"Warmup + cosine — ритуал больших моделей","desc":"Реализуй linear warmup + cosine decay lr-расписание вручную (без готового scheduler). Нарисуй кривую lr и сравни сходимость с константным lr."},{"num":107,"title":"Gradient accumulation — иллюзия большого батча","desc":"Обучи с эффективным батчем 512 при физическом батче 32 через накопление градиентов. Докажи численно, что результат близок к настоящему батчу 512."},{"num":108,"title":"Mixed precision — магия половинной точности","desc":"Переведи обучение на `autocast` + `GradScaler` (fp16/bf16). Замерь ускорение и экономию памяти. Объясни, зачем нужен scaler."},{"num":109,"title":"Числовая пропасть","desc":"Реализуй log-sum-exp наивно и стабильно. Подсунь большие логиты и покажи, где наивная версия даёт `inf`/`nan`, а стабильная — нет."},{"num":110,"title":"Отладчик градиентов","desc":"Реализуй gradient checking: сравни аналитический градиент (autograd) с численным (конечные разности) для своей функции потерь. Расхождение должно быть < 1e-5."},{"num":111,"title":"Один цикл, чтоб править всеми","desc":"Разберись в политике `fit_one_cycle` (Smith): нарисуй график lr и momentum по шагам и объясни, почему они движутся в противофазе."},{"num":112,"title":"Лотерейный билет","desc":"Проверь гипотезу lottery ticket: обучи сеть, обрежь 80% наименьших весов (pruning), верни оставшиеся к исходной инициализации, переобучи. Сравни с обучением с нуля."},{"num":113,"title":"Плоские минимумы и обобщение","desc":"Обучи одну сеть маленьким и большим батчем. Оцени «остроту» найденных минимумов (квест 102) и сопоставь с точностью на тесте. Проверь легенду про большие батчи."},{"num":114,"title":"SAM — поиск плоского","desc":"Реализуй Sharpness-Aware Minimization (два прохода на шаг). Сравни обобщение с обычным SGD на CIFAR-10."},{"num":115,"title":"EMA-двойник","desc":"Веди экспоненциальное скользящее среднее весов модели параллельно обучению. Сравни точность EMA-версии и обычной. Почему EMA часто выигрывает?"},{"num":116,"title":"Второй порядок дёшево","desc":"Реализуй одну итерацию Ньютона для маленькой задачи (2–3 параметра), посчитав гессиан через autograd. Сравни скорость сходимости с градиентным спуском."},{"num":117,"title":"Loss landscape взаимодействий","desc":"Обучи одну и ту же архитектуру с 5 разными seed. Через linear mode connectivity проверь, соединены ли минимумы «долиной» без барьеров."},{"num":118,"title":"Кастомная функция autograd","desc":"Напиши свой `torch.autograd.Function` с ручными `forward` и `backward` (например, для нестандартной активации). Проверь через gradcheck."},{"num":119,"title":"Профилировщик узких мест","desc":"Через `torch.profiler` найди, где твоя модель тратит время (forward/backward/data loading). Оптимизируй самое узкое место и замерь выигрыш."},{"num":120,"title":"Босс глубин оптимизации","desc":"Собери «трудный» датасет (несбалансированный, шумные метки) и добейся хорошего результата, комбинируя минимум 4 приёма из этого акта. Отчёт: что дало какой прирост."}]},{"roman":"XII","title":"Архитектурная Кузница","from":121,"to":140,"xp":65,"quests":[{"num":121,"title":"ResNet своими руками","desc":"Реализуй residual-блок и собери ResNet-18 с нуля. Обучи на CIFAR-10. Затем «сломай» skip-connection (убери +x) и покажи деградацию на глубокой сети."},{"num":122,"title":"BatchNorm изнутри","desc":"Реализуй BatchNorm с нуля (train/eval режимы, running stats). Сверь с `nn.BatchNorm`. Объясни, что хранится между батчами."},{"num":123,"title":"Битва нормализаций","desc":"Сравни BatchNorm, LayerNorm, GroupNorm, InstanceNorm на одной сети при batch_size=2. Покажи, кто выживает при крошечном батче и почему."},{"num":124,"title":"DenseNet-паутина","desc":"Реализуй dense-блок (конкатенация всех предыдущих feature maps). Сравни число параметров и точность с ResNet при равной глубине."},{"num":125,"title":"Depthwise separable — экономия мага","desc":"Реализуй depthwise separable свёртку (как в MobileNet). Посчитай, во сколько раз меньше операций против обычной свёртки при той же форме."},{"num":126,"title":"Squeeze-and-Excitation","desc":"Добавь SE-блок (внимание по каналам) в свою CNN. Замерь прирост точности за копеечную цену параметров. Визуализируй, какие каналы усиливаются."},{"num":127,"title":"Dilated-свёртки — расширенный взор","desc":"Собери сеть с dilated convolutions для увеличения рецептивного поля без потери разрешения. Посчитай рецептивное поле вручную."},{"num":128,"title":"U-Net с нуля","desc":"Реализуй U-Net (encoder-decoder + skip) для сегментации. Обучи на игрушечной задаче (сегментация фигур, которые сгенерируешь сам)."},{"num":129,"title":"Vision Transformer с нуля","desc":"Реализуй ViT: патч-эмбеддинги + позиционные + трансформер-блоки. Обучи на CIFAR-10. Сравни с CNN при равном бюджете параметров."},{"num":130,"title":"Рецептивное поле-детектив","desc":"Эмпирически измерь рецептивное поле нейрона глубокого слоя: подавай импульс в один пиксель и смотри, какие входы влияют на выход."},{"num":131,"title":"NAS вручную","desc":"Перебери сеткой 3–4 гиперпараметра архитектуры (глубина, ширина, ядро) — обучи все, построй таблицу точность/параметры/время. Найди Парето-фронт."},{"num":132,"title":"Стохастическая глубина","desc":"Реализуй stochastic depth (случайный пропуск блоков при обучении). Покажи регуляризующий эффект на глубокой сети."},{"num":133,"title":"Anti-aliasing в пулинге","desc":"Замени обычный stride на blur-pool (Zhang). Проверь, стала ли сеть устойчивее к сдвигу входа на 1–2 пикселя."},{"num":134,"title":"Гиперсеть","desc":"Построй маленькую сеть, которая генерирует веса для другой сети. Обучи на простой задаче. Осознай, что веса — это тоже данные."},{"num":135,"title":"Смесь экспертов (MoE)","desc":"Реализуй простой Mixture of Experts с обучаемым роутером. Визуализируй, какой эксперт активируется на каких входах."},{"num":136,"title":"Свёртка = матричное умножение","desc":"Реализуй свёртку через im2col + matmul. Сравни скорость с наивными циклами и с `conv2d`. Пойми, как это работает под капотом."},{"num":137,"title":"Граф вычислений наружу","desc":"Возьми свою модель, экспортируй в ONNX, визуализируй граф (Netron). Найди операции, которых не ожидал."},{"num":138,"title":"Квантизация модели","desc":"Проведи post-training quantization (int8) своей CNN. Замерь падение точности и выигрыш в размере/скорости. Где теряется качество?"},{"num":139,"title":"Fusion слоёв","desc":"Слей Conv+BN+ReLU в один блок для инференса. Докажи численно, что выход не изменился, и замерь ускорение."},{"num":140,"title":"Босс кузницы","desc":"Спроектируй собственную архитектуру под конкретное ограничение (< 1M параметров ИЛИ < 10ms инференс на CPU) и выжми максимум точности на CIFAR-10. Защити свои решения в отчёте."}]},{"roman":"XIII","title":"Наречия Трансформеров","from":141,"to":160,"xp":70,"quests":[{"num":141,"title":"Multi-head attention с нуля","desc":"Реализуй multi-head self-attention полностью (без `nn.MultiheadAttention`). Проверь формы на каждом шаге. Визуализируй головы — разные ли паттерны они учат?"},{"num":142,"title":"Позиционные кодировки","desc":"Реализуй синусоидальные и обучаемые позиционные эмбеддинги. Покажи на игрушке, что без них трансформер «слеп» к порядку."},{"num":143,"title":"RoPE — вращающиеся позиции","desc":"Реализуй Rotary Positional Embeddings. Объясни геометрически, почему поворот кодирует относительную позицию."},{"num":144,"title":"Causal mask","desc":"Реализуй маскирование будущего для авторегрессии. Докажи «утечку», убрав маску: модель начнёт подглядывать в ответ."},{"num":145,"title":"Полный блок трансформера","desc":"Собери энкодер-блок: attention + residual + LayerNorm + FFN. Сравни pre-norm и post-norm по стабильности обучения глубокого стека."},{"num":146,"title":"KV-cache — ускорение генерации","desc":"Реализуй кэширование ключей/значений при авторегрессивной генерации. Замерь ускорение на длинных последовательностях."},{"num":147,"title":"Токенизатор BPE с нуля","desc":"Реализуй обучение Byte-Pair Encoding на корпусе. Сравни размер словаря и длину кодирования с посимвольным подходом."},{"num":148,"title":"Мини-GPT, обученный до толку","desc":"Собери GPT (~10M параметров), обучи на существенном корпусе (например, весь Шекспир или код). Оцени по perplexity и качеству генерации."},{"num":149,"title":"Температура и сэмплирование","desc":"Реализуй greedy, temperature, top-k, top-p (nucleus) сэмплирование. Сравни генерации одной модели. Найди «сладкую точку» разнообразия."},{"num":150,"title":"Scaling laws на кухне","desc":"Обучи 4 модели разного размера на одних данных. Построй log-log график «параметры loss». Увидь степенной закон своими глазами."},{"num":151,"title":"Flash-attention идея","desc":"Реализуй tiled-attention, считающий softmax блоками без материализации всей матрицы N×N. Замерь экономию памяти на длинном контексте."},{"num":152,"title":"Encoder-decoder переводчик","desc":"Собери seq2seq-трансформер и обучи перевод на маленькой параллельной паре языков (или дата/число слова). Оцени по BLEU."},{"num":153,"title":"Instruction fine-tuning","desc":"Возьми маленькую предобученную LLM и дообучи на инструктивных парах (instruction response). Сравни поведение до/после."},{"num":154,"title":"LoRA с нуля","desc":"Реализуй Low-Rank Adaptation: замени дообучение полных матриц на низкоранговые добавки. Посчитай, во сколько раз меньше обучаемых параметров."},{"num":155,"title":"Квантизованное дообучение (QLoRA-идея)","desc":"Загрузи модель в 4-бит, обучи поверх LoRA-адаптеры. Замерь память против полного fine-tuning."},{"num":156,"title":"Внимание под микроскопом","desc":"Для дообученной модели визуализируй attention-паттерны на разных слоях. Найди «индукционные головы» (копирующие паттерн из контекста)."},{"num":157,"title":"Длинный контекст","desc":"Возьми модель, обученную на 256 токенов, и заставь работать на 1024 через интерполяцию позиций. Оцени деградацию."},{"num":158,"title":"Спекулятивное декодирование","desc":"Реализуй идею: маленькая модель предлагает токены, большая проверяет пачкой. Замерь ускорение генерации."},{"num":159,"title":"Оценка честная","desc":"Собери свой бенчмарк из 30 задач, прогони на 2–3 моделях, посчитай метрики. Найди, где автометрика врёт против человеческой оценки."},{"num":160,"title":"Босс наречий","desc":"Обучи end-to-end маленькую языковую модель под конкретную задачу (генерация SQL / стихов / диалогов), доведи до работающего демо и напиши честный разбор её слабых мест."}]},{"roman":"XIV","title":"Генеративные Искусства","from":161,"to":180,"xp":75,"quests":[{"num":161,"title":"VAE — вероятностное зеркало","desc":"Реализуй вариационный автоэнкодер с reparameterization trick и KL-регуляризацией. Обучи на MNIST, покажи гладкую интерполяцию между цифрами."},{"num":162,"title":"β-VAE и распутывание","desc":"Поиграй с коэффициентом β. Найди латентные оси, отвечающие за отдельные факторы (толщина, наклон). Покажи, как меняется одна ось."},{"num":163,"title":"GAN, который не рушится","desc":"Обучи DCGAN до устойчивого результата. Веди лог mode collapse. Примени 2 стабилизирующих приёма (label smoothing, TTUR) и покажи разницу."},{"num":164,"title":"WGAN-GP","desc":"Реализуй Wasserstein GAN с gradient penalty. Объясни, почему критик даёт осмысленную метрику качества, в отличие от классического дискриминатора."},{"num":165,"title":"Conditional GAN","desc":"Сделай генерацию управляемой меткой класса. Сгенерируй «по заказу» конкретную цифру/класс."},{"num":166,"title":"Диффузия с нуля: прямой процесс","desc":"Реализуй forward diffusion (постепенное зашумление). Визуализируй, как картинка превращается в шум за T шагов."},{"num":167,"title":"Диффузия с нуля: обратный процесс","desc":"Обучи модель предсказывать шум (DDPM) и генерируй картинки из чистого шума. Первый собственный «стабильный диффузор» в миниатюре!"},{"num":168,"title":"DDIM — быстрый сэмплинг","desc":"Реализуй детерминированный DDIM-сэмплинг. Сгенерируй за 20 шагов то, на что DDPM тратил 1000. Сравни качество."},{"num":169,"title":"Classifier-free guidance","desc":"Добавь управление генерацией через guidance scale. Покажи компромисс «качество разнообразие» при росте scale."},{"num":170,"title":"Латентная диффузия","desc":"Обучи диффузию в латентном пространстве автоэнкодера (а не в пикселях). Замерь экономию вычислений."},{"num":171,"title":"Метрики генерации","desc":"Реализуй FID и Inception Score. Оцени свои GAN и диффузию численно, а не «на глаз». Где метрика расходится с восприятием?"},{"num":172,"title":"CLIP-компас","desc":"Используй CLIP, чтобы измерить соответствие «текст картинка». Отранжируй свои сгенерированные картинки по близости к промпту."},{"num":173,"title":"Text-to-image в миниатюре","desc":"Обусловь свою латентную диффузию текстовыми эмбеддингами (CLIP/маленький энкодер). Сгенерируй по короткому промпту на игрушечном датасете."},{"num":174,"title":"Inpainting","desc":"Реализуй дорисовку вырезанной области картинки диффузионной моделью. Покажи 3 разных правдоподобных заполнения одной дыры."},{"num":175,"title":"Нормализующие потоки","desc":"Реализуй простой RealNVP. Покажи точное вычисление правдоподобия (то, чего GAN не умеет) на 2D-данных."},{"num":176,"title":"Автогрегрессивные картинки","desc":"Реализуй PixelCNN-идею: генерация картинки пиксель за пикселем. Сравни философию с диффузией."},{"num":177,"title":"Генерация звука","desc":"Обучи маленькую модель генерировать простые аудио-волны или спектрограммы. Послушай результат."},{"num":178,"title":"Score matching интуиция","desc":"Визуализируй выученное score-поле (градиент log-плотности) на 2D-данных как векторное поле. Пойми, куда «течёт» шум к данным."},{"num":179,"title":"Редактирование латентов","desc":"Найди в латентном пространстве GAN/VAE направление, меняющее один атрибут (улыбка, поворот), через арифметику векторов. Продемонстрируй управление."},{"num":180,"title":"Босс генеративных искусств","desc":"Построй управляемый генеративный конвейер (условная диффузия ИЛИ GAN) на своём датасете, с численной оценкой качества и интерактивным демо. Отчёт о том, что работает, а что развалилось."}]},{"roman":"XV","title":"Тропа Обучения с Подкреплением","from":181,"to":200,"xp":80,"quests":[{"num":181,"title":"MDP на бумаге и в коде","desc":"Формализуй простую среду как MDP (состояния, действия, награды, переходы). Реши точно через value iteration и policy iteration. Сравни сходимость."},{"num":182,"title":"Исследование vs эксплуатация","desc":"Реализуй ε-greedy, UCB и Thompson sampling для многорукого бандита. Построй графики суммарного regret. Кто выигрывает и когда?"},{"num":183,"title":"REINFORCE","desc":"Реализуй policy gradient с нуля на CartPole. Покажи проблему высокой дисперсии градиента и снизь её через baseline."},{"num":184,"title":"Actor-Critic","desc":"Собери A2C: актор + критик. Сравни стабильность и скорость с чистым REINFORCE на том же CartPole."},{"num":185,"title":"DQN как надо","desc":"Реализуй DQN со всеми хитростями: replay buffer, target network, ε-decay. Реши LunarLander. Покажи, что убирание target network ломает обучение."},{"num":186,"title":"Double DQN + Dueling","desc":"Добавь Double DQN (борьба с переоценкой) и dueling-архитектуру. Сравни с ванильным DQN на одной среде."},{"num":187,"title":"Prioritized replay","desc":"Реализуй приоритизированный replay buffer. Покажи ускорение обучения за счёт «важных» переходов."},{"num":188,"title":"PPO — рабочая лошадка","desc":"Реализуй Proximal Policy Optimization с clipped objective. Реши непрерывную задачу управления. Это стандарт индустрии — освой его крепко."},{"num":189,"title":"Continuous control","desc":"Реши задачу с непрерывными действиями (например, маятник/hopper) через PPO или SAC. Разберись, почему дискретные методы тут не годятся."},{"num":190,"title":"Reward shaping — обоюдоострый меч","desc":"Придумай reward shaping для сложной задачи. Покажи случай, где неудачное шейпинг привёл к reward hacking (агент читерит)."},{"num":191,"title":"Model-based RL","desc":"Обучи модель динамики среды и планируй в ней. Сравни sample efficiency с model-free подходом."},{"num":192,"title":"Self-play","desc":"Обучи агента в игре двух игроков через self-play (крестики-нолики / Connect-4). Покажи рост силы против фиксированного противника."},{"num":193,"title":"Мини-AlphaZero","desc":"Соедини MCTS с нейросетью для маленькой игры. Обучи через self-play. Это вершина классического RL — почувствуй её."},{"num":194,"title":"Imitation learning","desc":"Собери демонстрации эксперта и обучи агента behavior cloning. Покажи проблему накопления ошибок (distribution shift) и смягчи через DAgger."},{"num":195,"title":"Offline RL","desc":"Обучи политику только на записанном датасете без взаимодействия со средой. Столкнись с проблемой экстраполяции за пределы данных."},{"num":196,"title":"RLHF в миниатюре","desc":"Обучи reward model на парных сравнениях (что лучше из двух), затем оптимизируй маленькую политику под неё через PPO. Это сердце современных LLM."},{"num":197,"title":"Многоагентная среда","desc":"Запусти 2+ обучающихся агентов в общей среде. Понаблюдай эмерджентное поведение: кооперация или конкуренция?"},{"num":198,"title":"Curriculum learning","desc":"Обучи агента решать сложную задачу через постепенно усложняющиеся версии. Сравни с обучением сразу на сложной."},{"num":199,"title":"Своя среда Gym","desc":"Оберни собственную задачу (игру/симуляцию, которую придумаешь) в интерфейс gymnasium и обучи в ней агента."},{"num":200,"title":"Босс тропы RL","desc":"Выбери нетривиальную среду, доведи агента до уверенного решения, запиши видео, проанализируй кривые обучения и провалившиеся попытки. Честный отчёт о боли RL."}]},{"roman":"XVI","title":"Мультимодальные Чертоги","from":201,"to":220,"xp":85,"quests":[{"num":201,"title":"CLIP с нуля","desc":"Обучи контрастивную модель «картинка текст» на маленьком датасете пар. Покажи zero-shot классификацию через текстовые промпты."},{"num":202,"title":"Image captioning","desc":"Собери «CNN/ViT-энкодер + трансформер-декодер» и обучи описывать картинки текстом. Оцени по CIDEr/BLEU."},{"num":203,"title":"Visual Question Answering","desc":"Построй модель, отвечающую на вопросы о картинке. Проверь на своих вопросах — где она «галлюцинирует»?"},{"num":204,"title":"Контрастивное обучение (SimCLR)","desc":"Реализуй self-supervised предобучение на аугментациях без меток. Покажи, что выученные представления полезны для downstream-задачи с малым числом меток."},{"num":205,"title":"Masked autoencoding (MAE)","desc":"Обучи модель восстанавливать замаскированные патчи картинки. Используй энкодер как feature extractor и сравни с обучением с нуля."},{"num":206,"title":"BYOL/DINO идея","desc":"Реализуй self-distillation без негативных пар. Разберись, почему модель не коллапсирует в константу."},{"num":207,"title":"Аудио + текст","desc":"Построй систему распознавания коротких команд (спектрограмма текст) на маленьком датасете. Оцени WER."},{"num":208,"title":"Text-to-speech в миниатюре","desc":"Обучи модель генерировать спектрограмму из текста. Восстанови звук через vocoder. Послушай синтез."},{"num":209,"title":"Видео-понимание","desc":"Обучи модель классифицировать короткие видео (действия). Разберись, как учитывать временное измерение (3D-conv vs frame+RNN)."},{"num":210,"title":"Мультимодальный поиск","desc":"Построй поиск, где запрос-текст находит картинки И наоборот, в общем эмбеддинг-пространстве. Оцени точность на своих запросах."},{"num":211,"title":"Grounding","desc":"Обучи модель локализовать на картинке объект, названный текстом (bounding box по фразе). Визуализируй результаты."},{"num":212,"title":"Знания через модальности","desc":"Проверь, переносится ли знание: обучи на тексте, тестируй понимание картинок (или наоборот) через общий эмбеддинг."},{"num":213,"title":"Диффузия с текстовым управлением","desc":"Соедини свою латентную диффузию (Акт XIV) с текстовым энкодером в полноценный mini text-to-image. Оцени соответствие промптам через CLIP."},{"num":214,"title":"OCR своими руками","desc":"Построй распознавание текста на картинках (CRNN + CTC loss). Обучи на синтетических картинках со словами."},{"num":215,"title":"Позы и ключевые точки","desc":"Обучи модель находить ключевые точки (например, скелет фигуры). Визуализируй предсказания."},{"num":216,"title":"Мультизадачное обучение","desc":"Обучи одну сеть решать 2–3 задачи сразу (классификация + сегментация). Разберись с балансировкой лоссов между задачами."},{"num":217,"title":"Retrieval-augmented генерация","desc":"Построй RAG: эмбеддинг-поиск по базе подача найденного в генератор. Покажи, что он снижает галлюцинации против голой модели."},{"num":218,"title":"Кросс-модальный перенос стиля","desc":"Управляй стилем в одной модальности через другую (текст управляет визуалом). Продемонстрируй управление."},{"num":219,"title":"Слияние сенсоров","desc":"Объедини разнородные входы (например, табличные + текст + картинка) в одной модели для общего предсказания. Сравни с использованием одной модальности."},{"num":220,"title":"Босс мультимодальных чертогов","desc":"Построй работающую мультимодальную систему под реальную задачу (поиск / ассистент / caption), с честной оценкой и демо. Разбор: где модальности помогают, а где мешают друг другу."}]},{"roman":"XVII","title":"Инженерия и Масштаб","from":221,"to":240,"xp":90,"quests":[{"num":221,"title":"Быстрый data pipeline","desc":"Профилируй и ускорь загрузку данных: num_workers, pin_memory, prefetch, кэширование. Докажи замерами, что GPU перестал голодать."},{"num":222,"title":"Распределённое обучение","desc":"Запусти DistributedDataParallel на 2+ процессах (можно эмулировать). Разберись, как синхронизируются градиенты. Замерь масштабируемость."},{"num":223,"title":"Model & pipeline parallelism","desc":"Раздели большую модель по устройствам (по слоям). Пойми, когда это нужно, а когда хватает data parallelism."},{"num":224,"title":"ZeRO-идея","desc":"Реализуй/разбери шардинг состояний оптимизатора между устройствами. Посчитай экономию памяти для большой модели."},{"num":225,"title":"Чекпоинтинг активаций","desc":"Примени gradient checkpointing: обменяй вычисления на память. Обучи модель, которая иначе не влезла бы в память."},{"num":226,"title":"Воспроизводимость-крепость","desc":"Сделай эксперимент полностью воспроизводимым (seed, детерминизм, версии, конфиг). Запусти дважды и получи бит-в-бит одинаковый результат."},{"num":227,"title":"Конфиги и трекинг","desc":"Настрой конфигурацию через Hydra/YAML и логирование экспериментов (W&B/MLflow). Проведи 10 запусков и сравни их в дашборде."},{"num":228,"title":"Гиперпараметрический поиск по-взрослому","desc":"Запусти байесовскую оптимизацию (Optuna) с pruning неудачных запусков. Сравни эффективность с grid и random search."},{"num":229,"title":"CI для ML","desc":"Напиши автотесты: проверка форм, «модель переобучается на одном батче», отсутствие NaN, детерминизм. Собери в pipeline, падающий при регрессии."},{"num":230,"title":"Отладка молчаливых багов","desc":"Специально внеси 3 типичные ошибки (не тот dim в softmax, забытый zero_grad, утечка trainvalid) и напиши, по каким симптомам каждую ловить."},{"num":231,"title":"Оптимизация инференса","desc":"Ускорь инференс через TorchScript/`torch.compile`. Замерь latency и throughput до/после. Найди, что дало основной выигрыш."},{"num":232,"title":"Батчинг запросов","desc":"Реализуй динамический батчинг запросов на сервинге. Покажи рост throughput при контролируемой latency."},{"num":233,"title":"Сервинг в проде","desc":"Заверни модель в API (FastAPI) + контейнер (Docker). Замерь p50/p95/p99 latency под нагрузкой. Найди узкое место."},{"num":234,"title":"Мониторинг дрейфа","desc":"Реализуй детектор data drift: сравнивай распределение входов в проде с обучающим. Подними алерт, когда распределение поехало."},{"num":235,"title":"A/B на моделях","desc":"Спроектируй и просимулируй A/B-тест двух моделей: метрики, размер выборки, значимость. Прими решение по данным, а не «на глаз»."},{"num":236,"title":"Feature store мини","desc":"Построй воспроизводимый пайплайн фич с версионированием, чтобы train и serving считали фичи одинаково (борьба с train-serve skew)."},{"num":237,"title":"Дистилляция для прода","desc":"Сожми большую модель в маленькую (distillation + quantization + pruning вместе). Уложись в жёсткий бюджет latency при минимуме потерь точности."},{"num":238,"title":"Обучение на «грязных» данных","desc":"Построй пайплайн, устойчивый к шумным меткам: детекция подозрительных примеров, confident learning, повторная разметка. Замерь прирост."},{"num":239,"title":"Continual learning","desc":"Дообучай модель на новых классах, борясь с catastrophic forgetting (rehearsal / EWC). Покажи, что старое не забыто."},{"num":240,"title":"Босс инженерии","desc":"Возьми любую свою модель из прошлых актов и доведи до продакшн-качества: тесты, конфиги, трекинг, оптимизированный сервинг, мониторинг. Напиши инженерный отчёт с замерами."}]},{"roman":"XVIII","title":"Совет Мудрецов: интерпретация, надёжность, этика","from":241,"to":260,"xp":95,"quests":[{"num":241,"title":"Saliency-семейство","desc":"Реализуй vanilla gradients, Integrated Gradients, SmoothGrad. Сравни объяснения для одного предсказания. Какой метод менее шумный и почему?"},{"num":242,"title":"SHAP на практике","desc":"Примени SHAP к табличной модели. Найди фичу, которая «важна» глобально, но вредит на конкретном примере. Осознай разницу глобального и локального."},{"num":243,"title":"Пробинг представлений","desc":"Обучи линейные пробы на скрытых слоях: какое знание где закодировано? Построй карту «слой тип информации»."},{"num":244,"title":"Механистическая интерпретация","desc":"Найди в маленькой модели конкретную цепь, реализующую понятную функцию (например, чётность/копирование). Опиши её как алгоритм."},{"num":245,"title":"Активационные патчи","desc":"Через activation patching установи причинную роль компонента: замени активацию и посмотри, что сломается в предсказании."},{"num":246,"title":"Калибровка уверенности","desc":"Проверь, честны ли вероятности модели (reliability diagram, ECE). Откалибруй через temperature scaling. Покажи «до/после»."},{"num":247,"title":"Оценка неопределённости","desc":"Реализуй MC-dropout и ансамбли для оценки эпистемической неопределённости. Покажи, что на OOD-входах неопределённость растёт."},{"num":248,"title":"Детекция OOD","desc":"Построй детектор out-of-distribution входов. Проверь на данных из другого распределения. Где модель «уверенно ошибается»?"},{"num":249,"title":"Adversarial-арсенал","desc":"Реализуй FGSM, PGD, targeted-атаки. Построй кривую «точность vs сила атаки». Найди порог, за которым модель бесполезна."},{"num":250,"title":"Adversarial-защита","desc":"Проведи adversarial training. Замерь честный компромисс: устойчивость выросла, а чистая точность? Развей миф о бесплатной защите."},{"num":251,"title":"Отравление данных","desc":"Внедри backdoor-триггер в обучающие данные. Покажи скрытую атаку: модель нормальна, пока не увидит триггер. Затем задетектируй закладку."},{"num":252,"title":"Аудит справедливости","desc":"Измерь метрики справедливости модели по подгруппам (demographic parity, equalized odds). Найди, где модель систематически хуже к какой-то группе."},{"num":253,"title":"Дебиасинг","desc":"Примени приём снижения предвзятости и покажи компромисс между справедливостью и общей точностью. Обсуди, какой критерий справедливости уместен и почему их нельзя выполнить все сразу."},{"num":254,"title":"Приватность: membership inference","desc":"Проведи атаку определения «был ли пример в обучении». Покажи утечку. Затем защитись через differential privacy (DP-SGD) и замерь цену в точности."},{"num":255,"title":"Извлечение памяти","desc":"Проверь, воспроизводит ли генеративная модель обучающие данные дословно (memorization). Измерь и обсуди риски."},{"num":256,"title":"Стресс-тест на сдвиг","desc":"Собери батарею сдвигов распределения (шум, стиль, подгруппы) и построй карту устойчивости модели. Где она хрупкая?"},{"num":257,"title":"Ошибки как данные","desc":"Проведи систематический error analysis: кластеризуй ошибки, найди паттерны, сформулируй гипотезы улучшения. Проверь одну гипотезу."},{"num":258,"title":"Спецификация против намерения","desc":"Найди/сконструируй случай, где модель оптимизирует метрику, но не решает задачу (specification gaming). Опиши, как это чинить."},{"num":259,"title":"Красная команда","desc":"Проведи red-teaming своей модели: систематически ищи входы, ломающие её. Составь отчёт об уязвимостях с примерами."},{"num":260,"title":"Босс совета мудрецов","desc":"Возьми одну свою модель и составь полный «паспорт доверия»: интерпретация, калибровка, устойчивость, справедливость, приватность, известные ограничения. Как настоящая model card."}]},{"roman":"XIX","title":"Граница Науки","from":261,"to":280,"xp":100,"quests":[{"num":261,"title":"Воспроизведение статьи целиком","desc":"Выбери одну статью средней сложности и воспроизведи её ключевой результат с нуля. Задокументируй все расхождения с оригиналом и их причины."},{"num":262,"title":"Абляции по-научному","desc":"Для воспроизведённого метода проведи полный ablation study: по очереди убирай компоненты, измеряй вклад каждого. Что реально важно, а что украшение?"},{"num":263,"title":"Честный бейзлайн","desc":"Возьми свежий «SOTA»-метод и сравни с сильным, хорошо настроенным простым бейзлайном. Часто простое побеждает — проверь на своей задаче."},{"num":264,"title":"Гипотеза и её проверка","desc":"Сформулируй проверяемую гипотезу о поведении моделей, спроектируй эксперимент, который может её опровергнуть, проведи, сделай вывод. Настоящая наука."},{"num":265,"title":"Статистика результатов","desc":"Прогони эксперимент с 5+ seed, посчитай доверительные интервалы. Покажи «улучшение», которое исчезает внутри дисперсии. Никогда больше не верь одному запуску."},{"num":266,"title":"Отрицательный результат","desc":"Реализуй разумную идею, которая НЕ сработала. Разберись почему, задокументируй честно. Отрицательный результат, хорошо объяснённый, — ценность."},{"num":267,"title":"Синтетический тестовый полигон","desc":"Построй контролируемую синтетическую задачу, где ты знаешь истину, чтобы изолированно изучить одно явление (например, как модель учит композицию)."},{"num":268,"title":"Grokking","desc":"Воспроизведи феномен grokking: модель внезапно обобщает спустя долгое переобучение. Построй кривые. Выдвини гипотезу механизма."},{"num":269,"title":"Double descent","desc":"Воспроизведи двойной спуск ошибки при росте размера модели/данных. Покажи, где классическая теория bias-variance ломается."},{"num":270,"title":"Эмерджентность на масштабе","desc":"Найди способность, появляющуюся скачком при росте модели/данных на твоей игрушечной задаче. Обсуди, артефакт это метрики или реальный переход."},{"num":271,"title":"Обучение динамики обучения","desc":"Отслеживай эволюцию отдельных нейронов/фич в ходе обучения. Когда формируются признаки? Есть ли фазовые переходы?"},{"num":272,"title":"Геометрия представлений","desc":"Измеряй, как меняется размерность/кривизна представлений от слоя к слою (например, через intrinsic dimension). Что происходит с данными внутри сети?"},{"num":273,"title":"Neural scaling — свой закон","desc":"Выведи эмпирический scaling law для СВОЕЙ задачи по данным/параметрам/компьюту. Экстраполируй и проверь предсказание новым запуском."},{"num":274,"title":"Индуктивные смещения","desc":"Спроектируй эксперимент, изолирующий индуктивное смещение архитектуры (CNN vs Transformer vs MLP на задаче с известной структурой). Кто учит что «бесплатно»?"},{"num":275,"title":"Теория информации в сети","desc":"Оцени взаимную информацию между слоями и входом/выходом. Проверь гипотезу information bottleneck на игрушке."},{"num":276,"title":"Обучение без градиентов","desc":"Реши задачу эволюционной стратегией / без backprop. Сравни с градиентным обучением. Когда градиенты не нужны или недоступны?"},{"num":277,"title":"Meta-learning","desc":"Реализуй MAML: обучение учиться. Покажи быструю адаптацию к новой задаче за несколько шагов."},{"num":278,"title":"Причинность, а не корреляция","desc":"Построй задачу, где корреляционная модель проваливается на интервенции, а причинная — нет. Освой разницу observation vs intervention."},{"num":279,"title":"Открытый вопрос","desc":"Найди в литературе нерешённый/спорный вопрос, сформулируй свой мини-эксперимент к нему, проведи, честно опиши, что узнал (даже если «пока непонятно»)."},{"num":280,"title":"Босс границы науки","desc":"Проведи полноценное мини-исследование: вопрос гипотезы эксперименты с контролем дисперсии абляции выводы ограничения. Оформи как препринт-стайл отчёт с воспроизводимым кодом."}]},{"roman":"XX","title":"Трон Мастера: Творения","from":281,"to":300,"xp":120,"quests":[{"num":281,"title":"Библиотека-артефакт","desc":"Собери свой мини-фреймворк для обучения (тренер, коллбэки, логирование, конфиги) — переиспользуемый в будущих проектах. Покрой тестами и документацией."},{"num":282,"title":"Воспроизведение с улучшением","desc":"Воспроизведи серьёзный метод и предложи собственное обоснованное улучшение. Докажи прирост статистически корректно."},{"num":283,"title":"Датасет как вклад","desc":"Собери, очисти, задокументируй и опубликуй собственный датасет с бейзлайнами и картой рисков. Данные — часто больший вклад, чем модель."},{"num":284,"title":"Соревнование всерьёз","desc":"Возьми настоящее Kaggle-соревнование, попади в топ-25% через продуманный пайплайн (валидация, ансамбли, feature engineering). Напиши разбор решения."},{"num":285,"title":"Edge-развёртывание","desc":"Ужми и разверни модель на устройстве с реальными ограничениями (браузер через ONNX / мобильный / Raspberry Pi). Работающее демо на слабом железе."},{"num":286,"title":"Полноценный продукт","desc":"Построй ML-продукт end-to-end: сбор данных обучение сервинг UI мониторинг цикл обратной связи для дообучения. Отдай реальным пользователям."},{"num":287,"title":"Агент с инструментами","desc":"Построй агента поверх LLM, умеющего вызывать инструменты (поиск, калькулятор, код) для решения многошаговых задач. Оцени надёжность и режимы отказа."},{"num":288,"title":"Своя научная заметка","desc":"Оформи один из своих результатов (Акты XVIII–XIX) как аккуратную статью: аннотация, метод, эксперименты, ограничения, воспроизводимый репозиторий."},{"num":289,"title":"Обучи большую-для-себя модель","desc":"Спланируй бюджет компьюта и обучи максимально крупную модель, которую можешь себе позволить, по всем правилам масштабирования. Задокументируй кривые и решения."},{"num":290,"title":"Система, а не модель","desc":"Построй ML-систему из нескольких взаимодействующих моделей (например, retriever + reranker + generator). Оптимизируй систему целиком, а не части по отдельности."},{"num":291,"title":"Робастность как требование","desc":"Возьми свой продукт и сделай его устойчивым к сдвигу, атакам и сбоям. Пройди собственный red-team и почини найденное."},{"num":292,"title":"Оптимизируй под реальную метрику","desc":"Найди задачу, где ML-метрика ≠ бизнес/пользовательская ценность. Перепроектируй систему под настоящую цель и докажи выигрыш."},{"num":293,"title":"Преподавание — высшая проверка","desc":"Возьми одну сложную тему из этих хроник и создай по ней урок/туториал с кодом и визуализациями. Объяснишь другому — значит, понял сам."},{"num":294,"title":"Открытый вклад","desc":"Внеси реальный вклад в open-source ML-проект: исправь баг, добавь фичу или напиши недостающую документацию. Проведи PR через ревью до мержа."},{"num":295,"title":"Воспроизведи то, что «невозможно»","desc":"Возьми результат, который считается сложным для одиночки, и воспроизведи его уменьшенную, но честную версию. Докажи, что понял суть, а не только API."},{"num":296,"title":"Свой бенчмарк","desc":"Создай осмысленный бенчмарк для недооценённой способности, обоснуй метрики, прогони на нескольких моделях, опубликуй лидерборд и разбор."},{"num":297,"title":"Долгий проект","desc":"Веди один проект 4+ недели: гипотезы, дневник, тупики, повороты. Итог — не только результат, но и честная летопись мышления исследователя."},{"num":298,"title":"Мультидисциплинарный мост","desc":"Примени ИИ к области вне ML (биология, музыка, право, физика) в связке с экспертом или литературой. Сделай что-то полезное для той области, а не только «занятное»."},{"num":299,"title":"Ревью как у мастера","desc":"Напиши глубокое ревью на чужую работу/статью: сильные стороны, дыры, что бы ты проверил, как улучшить. Мышление рецензента — признак зрелости."},{"num":300,"title":"ФИНАЛЬНОЕ ТВОРЕНИЕ: Магнум Опус","desc":"Задумай и доведи до конца проект, которым будешь гордиться: оригинальная идея, серьёзная реализация, честная оценка, ясное изложение и работающий артефакт, полезный другим людям. Не задача из списка — а доказательство, что ты стал Мастером. Заверши хроники своим именем в истории."}]}];

/* ---- индекс квестов + сквозная нумерация -------------------------- */
const AIQ_INDEX = {};
let __prev = null;
AIQ_ACTS.forEach((act) => {
  act.quests.forEach((q) => {
    q.id = "q" + q.num;
    q.actRoman = act.roman;
    q.actTitle = act.title;
    q.xp = act.xp;
    q.boss = q.num === act.to;
    q.requires = __prev ? [__prev] : [];
    AIQ_INDEX[q.id] = { act, quest: q };
    __prev = q.id;
  });
});
const AIQ_TOTAL_XP = AIQ_ACTS.reduce((s, a) => s + a.quests.length * a.xp, 0);
const AIQ_TOTAL_QUESTS = 300;

/* ---- звания по XP (как в источнике) -------------------------------- */
const AIQ_RANKS = [
  { at: 0,     name: "Ученик писаря" },
  { at: 500,   name: "Оруженосец данных" },
  { at: 1500,  name: "Рыцарь градиента" },
  { at: 3500,  name: "Маг тензоров" },
  { at: 7000,  name: "Архимаг" },
  { at: 12000, name: "Повелитель Нейросетей" },
  { at: 20000, name: "Хранитель Глубин" },
  { at: 30000, name: "Легенда Градиентов" },
  { at: 45000, name: "Мастер — Творец Разума" },
];
function aiqRankFor(xp) {
  let i = 0;
  for (let k = 0; k < AIQ_RANKS.length; k++) if (xp >= AIQ_RANKS[k].at) i = k;
  const rank = AIQ_RANKS[i], next = AIQ_RANKS[i + 1] || null;
  return { rank, next, idx: i, into: next ? xp - rank.at : 1, span: next ? next.at - rank.at : 1 };
}

/* ---- квесты дня ------------------------------------------------------ */
const AIQ_DAILY = [
  { id: "d1", label: "Закрыть 1 квест",  metric: "count", target: 1, bonus: 15 },
  { id: "d3", label: "Закрыть 3 квеста", metric: "count", target: 3, bonus: 35 },
  { id: "d5", label: "Закрыть 5 квестов", metric: "count", target: 5, bonus: 60 },
];

/* ---- достижения: вехи + звания ---------------------------------------- */
const AIQ_MILESTONES = [
  { id: "first", name: "Первый шаг Ученика", desc: "Завершить первый квест", icon: "spark", test: (s) => Object.keys(s.done).length >= 1 },
  { id: "q25",   name: "Четверть сотни",      desc: "25 квестов позади",      icon: "scroll", test: (s) => Object.keys(s.done).length >= 25 },
  { id: "q50",   name: "Полсотни",            desc: "50 квестов позади",      icon: "scroll", test: (s) => Object.keys(s.done).length >= 50 },
  { id: "q100",  name: "Первая книга закрыта", desc: "100 квестов — Акты I–X пройдены", icon: "book", test: (s) => Object.keys(s.done).length >= 100 },
  { id: "q150",  name: "Половина Хроник",      desc: "150 квестов позади",     icon: "scroll", test: (s) => Object.keys(s.done).length >= 150 },
  { id: "q200",  name: "Граница мастерства",   desc: "200 квестов позади",     icon: "scroll", test: (s) => Object.keys(s.done).length >= 200 },
  { id: "q250",  name: "Совет мудрецов пройден", desc: "250 квестов позади",   icon: "scroll", test: (s) => Object.keys(s.done).length >= 250 },
  { id: "q300",  name: "Магнум Опус",          desc: "Все 300 квестов Хроник завершены", icon: "crown", test: (s) => Object.keys(s.done).length >= 300 },
  { id: "streak3", name: "Три дня в кузнице",  desc: "Серия занятий: 3 дня",   icon: "flame", test: (s) => s.streak.count >= 3 },
  { id: "streak7", name: "Неделя без пауз",    desc: "Серия занятий: 7 дней",  icon: "flame", test: (s) => s.streak.count >= 7 },
  { id: "streak30", name: "Месяц восхождения", desc: "Серия занятий: 30 дней", icon: "flame", test: (s) => s.streak.count >= 30 },
];
const AIQ_RANK_TROPHIES = AIQ_RANKS.slice(1).map((r) => ({
  id: "rank_" + r.name, name: "Новое звание: " + r.name, desc: "Достигнут ранг «" + r.name + "»", icon: "seal",
  test: (s) => s.xp >= r.at,
}));
const AIQ_TROPHIES = [...AIQ_MILESTONES, ...AIQ_RANK_TROPHIES];

/* ---- время ------------------------------------------------------------- */
const aiqDayKey = (t) => new Date(t || Date.now()).toISOString().slice(0, 10);
const aiqYesterKey = () => aiqDayKey(Date.now() - 86400000);

/* ---- seed: немного пройденного пути для демонстрации -------------------- */
function aiqMakeSeed() {
  const done = {};
  let xp = 0;
  for (let n = 1; n <= 7; n++) {
    const id = "q" + n;
    done[id] = { at: aiqYesterKey() };
    xp += AIQ_INDEX[id].quest.xp;
  }
  return {
    xp,
    done,
    streak: { count: 2, last: aiqYesterKey() },
    day: { key: aiqDayKey(), count: 0, claimed: [] },
    trophies: [{ id: "first", at: aiqYesterKey() }],
  };
}

/* ---- store -------------------------------------------------------------- */
const AIQ_VERSION = "aiquests-v1";
/* хранится на сервере, localStorage — кэш (см. makeQuestStore в data.jsx) */
window.AIQStore = window.makeQuestStore("aiquests", AIQ_VERSION, aiqMakeSeed);
window.useAIQ = function () {
  const store = window.AIQStore;
  const [, force] = React.useState(0);
  React.useEffect(() => store.subscribe(() => force((n) => n + 1)), []);
  return store.get();
};

/* ---- derived ------------------------------------------------------------- */
const aiqUnlocked = (s, q) => (q.requires || []).every((r) => s.done[r]);
const aiqActStats = (s, act) => {
  const done = act.quests.filter((q) => s.done[q.id]);
  return { total: act.quests.length, done: done.length, xpTotal: act.quests.length * act.xp, xpGain: done.length * act.xp };
};
const aiqQuestProgress = (s, d) => Math.min(s.day.count, d.target);

window.AIQLookup = {
  quest: (id) => AIQ_INDEX[id], unlocked: aiqUnlocked, actStats: aiqActStats,
  dailyProgress: aiqQuestProgress, rankFor: aiqRankFor, dayKey: aiqDayKey,
  totalXp: AIQ_TOTAL_XP, totalQuests: AIQ_TOTAL_QUESTS,
};

/* ---- toast -------------------------------------------------------------- */
let aiqToastSeq = 19000;
const aiqToast = (text, pts) => { if (window.pushToast) window.pushToast({ id: ++aiqToastSeq, text, pts: pts || 0 }); };

/* ---- actions -------------------------------------------------------------- */
function aiqEnsureDay(s) {
  const k = aiqDayKey();
  if (s.day && s.day.key === k) return s;
  return { ...s, day: { key: k, count: 0, claimed: [] } };
}
function aiqBumpStreak(s) {
  const k = aiqDayKey();
  if (s.streak.last === k) return s;
  const count = s.streak.last === aiqYesterKey() ? s.streak.count + 1 : 1;
  return { ...s, streak: { count, last: k } };
}
function aiqCheckTrophies(s) {
  const have = new Set(s.trophies.map((t) => t.id));
  const won = [];
  AIQ_TROPHIES.forEach((t) => { if (!have.has(t.id) && t.test(s)) won.push({ id: t.id, at: aiqDayKey() }); });
  if (!won.length) return s;
  won.forEach((w) => { const def = AIQ_TROPHIES.find((t) => t.id === w.id); aiqToast("Достижение: " + def.name); });
  return { ...s, trophies: [...s.trophies, ...won] };
}

window.AIQActions = {
  toggleQuest(id) {
    const e = AIQ_INDEX[id];
    if (!e) return;
    window.AIQStore.set((s0) => {
      let s = aiqEnsureDay(s0);
      if (s.done[id]) {
        const { [id]: _drop, ...rest } = s.done;
        return { ...s, done: rest, xp: Math.max(0, s.xp - e.quest.xp) };
      }
      s = {
        ...s, xp: s.xp + e.quest.xp,
        done: { ...s.done, [id]: { at: aiqDayKey() } },
        day: { ...s.day, count: s.day.count + 1 },
      };
      s = aiqBumpStreak(s);
      s = aiqCheckTrophies(s);
      return s;
    });
    const nowDone = window.AIQStore.get().done[id];
    if (nowDone) aiqToast("Квест закрыт", e.quest.xp);
  },
  claimDaily(did) {
    const d = AIQ_DAILY.find((x) => x.id === did);
    if (!d) return;
    window.AIQStore.set((s0) => {
      let s = aiqEnsureDay(s0);
      if (s.day.claimed.includes(did) || aiqQuestProgress(s, d) < d.target) return s;
      s = { ...s, xp: s.xp + d.bonus, day: { ...s.day, claimed: [...s.day.claimed, did] } };
      return aiqCheckTrophies(s);
    });
    aiqToast("Квест дня выполнен", d.bonus);
  },
  reset() {
    /* set() ниже сам перезапишет кэш и серверную запись */
    window.AIQStore.set(aiqMakeSeed());
    aiqToast("Игровые курсы сброшены");
  },
};

window.AIQActs = AIQ_ACTS;
window.AIQRanks = AIQ_RANKS;
window.AIQDaily = AIQ_DAILY;
window.AIQTrophies = AIQ_TROPHIES;
