Отчёт и защита
Как превратить журнал экспериментов в технический отчёт по образцу техотчётов DeepSeek-V3 и Qwen3 — структура, графики, абляции с интервалами, честные ограничения и неудачи — и как подготовиться к защите; с чек-листом и промптом для ИИ-ревьюера.
Зачем это нужно
Заголовок раздела «Зачем это нужно»Через полгода никто не запустит ваш make all, зато отчёт прочитают: будущий работодатель, коллега, вы сами.
Модель — это результат, а отчёт — доказательство: что именно сделано, что сработало, что нет и почему вы в этом
уверены. Проект без отчёта — набор файлов, проект с отчётом — инженерная работа.
Отчёт полезен и вам. Пока вы пишете фразу «GRPO повысил точность на 18 п.п.», обнаруживается, что интервал не посчитан, абляции нет, а базовая линия снята на другой версии eval-набора. Письмо — последний и самый строгий этап отладки.
Образцом будут китайские техотчётытехнический отчёт (техотчёт)EN technical reportТак лаборатории описывают свои модели. Это не рецензируемая статья, хотя часть отчётов позже публикуют в журналах (DeepSeek-R1 — в Nature).. DeepSeek, Qwen, Kimi публикуют подробные отчёты о каждой крупной модели, и это стало главным каналом, по которому индустрия узнаёт о новых идеях. Вы уже читали отчёт DeepSeek-V3 и статью R1 вместе с курсом (уроки «Читаем техотчёт DeepSeek-V3 вместе» и «Читаем статью DeepSeek-R1 вместе» трека «Китайская линза»). Теперь посмотрим на них как писатель, а не как читатель.
Анатомия техотчёта
Заголовок раздела «Анатомия техотчёта»У DeepSeek-V3 и Qwen3 почти одинаковый скелет. Сопоставим его с вашим проектом:
| Раздел техотчёта | Что там у DeepSeek-V3 / Qwen3 | Что у вас |
|---|---|---|
| Abstract | масштаб модели, ключевые новшества, главный результат, стоимость | 5 предложений: задача, что сделано, 2–3 главных числа, вывод |
| 1. Introduction | утверждения статьи; у V3 — таблица GPU-часов по этапам | задача, вклад списком, главный рисунок или таблица |
| 2. Architecture | MLA, DeepSeekMoE, MTP (V3); слои, GQA, MoE (Qwen3) | токенизатор, конфигурация модели таблицей |
| 3. Infrastructure | FP8, DualPipe, кластер | железо, DDP, скорость (токенов/с, MFUутилизация FLOPs модели (MFU)EN model FLOPs utilization (MFU)Доля пиковой производительности железа, которая уходит на полезные вычисления модели. Для больших распределённых обучений типичны 30–50 %.) |
| 4. Pre-training | данные, гиперпараметры, расширение контекста, оценка базовой модели, абляции | корпус, очистка, кривые loss, базовые линии |
| 5. Post-training | SFT, RL; у Qwen3 — четыре этапа и таблица результатов после этапов 2–4 | SFT и GRPO, графики награды, оценка после каждого этапа |
| Evaluation | таблицы с протоколом и сравнением (внутри глав о претрейне и пост-трейнинге) | eval-набор, протокол, точность с интервалами |
| Discussion / ablations | у V3 — подразделы Discussion в главах о претрейне и пост-трейнинге: абляции MTP, балансировки без вспомогательного loss, дистилляции из R1 | ваши абляции |
| Conclusion, Limitations, Future Directions | у V3 — честные ограничения развёртывания | ограничения, риски, неудачи, что дальше |
Шесть приёмов, которые стоит скопировать:
- Главный результат на первой странице. Читатель решает за минуту, читать ли дальше.
- Каждое утверждение подкреплено таблицей, графиком или ссылкой на эксперимент. «Модель стала лучше» без числа в отчёте не живёт.
- У каждого важного решения — абляция. У V3 для MTP и для балансировки без вспомогательного loss есть отдельные эксперименты «с этим и без этого». Вы выбрали награду за формат — покажите, что без неё хуже.
- Стоимость в явном виде. V3 первой же таблицей даёт GPU-часы по этапам. У вас — часы и железо по этапам.
- Оценка после каждого этапа. Qwen3 показывает таблицей, что изменилось после Reasoning RL, Thinking Mode Fusion и General RL.
- Ограничения и неудачи — отдельным разделом, а не мелким шрифтом.
Шаблон отчёта
Заголовок раздела «Шаблон отчёта»Скопируйте каркас в report/README.md и заполняйте из журнала экспериментов (журнал экспериментовжурнал экспериментовEN experiment logЗапись каждого запуска — дата, коммит, конфиг, гипотеза, результат, вывод. Из него потом пишется отчёт.) и файлов metrics.json:
# Маленький решатель: своя LLM от токенизатора до агента
## АннотацияЗадача (1 предложение). Что сделано (1–2). Главные числа с интервалами (1–2). Вывод (1).
## 1. Введение- Задача и почему она проверяемая- Вклад: что сделано своими руками (списком)- Рисунок 1: схема конвейера; Таблица 1: главные результаты по этапам
## 2. ДанныеИсточники, объём в токенах, очистка, дедупликация, доля русского и китайского.Eval-набор: как собран, размер, проверка пересечения с обучением.
## 3. Модель и токенизаторТаблица конфигурации (слои, d_model, головы, словарь, параметры). Сжатие токенизатора.
## 4. Обучение4.1 Претрейн — гиперпараметры таблицей, кривые loss, базовые линии.4.2 SFT — данные, шаблон, маска loss, доля ответов в формате.4.3 GRPO — награды, группа, KL, графики награды и длины ответа.Стоимость: GPU-часы по этапам.
## 5. ИнференсКвантование (размер, скорость, потеря точности), сервер, токенов/с.
## 6. АгентИнструмент, формат вызова, доля решённых задач с инструментом и без, pass^k.
## 7. АбляцииТаблица: вариант → метрика ± интервал → Δ к основному варианту.
## 8. Неудачные попыткиЧто пробовали, что ожидали, что получилось, почему (гипотеза).
## 9. Ограничения и дальнейшая работа
## ПриложенияКонфиги, примеры генераций (удачные и неудачные), промпты, команды воспроизведения.Вывод автогрейдера и самопроверки уровней (check.txt), сводный metrics.json.Аннотация — самое трудное. Формула: контекст → что сделано → главные числа → что это значит. Пример:
Мы обучили с нуля русскоязычную модель на 25.8M параметров (0.5 млрд токенов, 1 GPU, 3 часа) и довели её до агента, решающего арифметические текстовые задачи с калькулятором. GRPO с наградой за верный ответ и формат повысил точность на отложенных задачах с 34.0 ± 5.4% до 52.0 ± 5.7%. 4-битное квантование уменьшило модель в 3.6 раза при потере 1.2 п.п. С калькулятором агент решает 64% задач с большими числами против 26% без него. Главное ограничение — модель не обобщается на задачи длиннее трёх действий.
Каждое число этой аннотации должно найтись в таблице отчёта. Числа в примере условные — у вас будут свои.
Графики, которые убеждают
Заголовок раздела «Графики, которые убеждают»Правила, которые отличают график из отчёта от скриншота TensorBoard (программы, которая рисует графики обучения «на лету»):
- Ось X — токены, а не шаги. Шаг зависит от размера батча, токены — нет. Так кривые разных запусков сравнимы.
- Сырые точки полупрозрачные, сглаженная кривая поверх. Сглаживание (EMAэкспоненциальное скользящее среднее (EMA)EN exponential moving average (EMA)m ← βm + (1 − β)x. Помнит примерно последние 1/(1 − β) значений; при β = 0.9 — около 10., как моменты в Adam из урока 1.4.2) показывает тренд, но отстаёт на крутых участках — поэтому сырые данные оставляют видимыми.
- Train и val на одном графике, и val в начале обучения оценивайте чаще: там всё меняется быстрее.
- Подписи с единицами: «cross-entropy, нат/токен», «точность, %».
- Заголовок — это вывод: не «Loss», а «train и val идут вместе — переобучения нет».
- Ориентиры на графике: стартовый loss , базовая линия, порог уровня.
import os
import matplotlibmatplotlib.use("Agg") # рисуем в файл, без окнаimport matplotlib.pyplot as pltimport numpy as np
rng = np.random.default_rng(0)# Синтетический лог вместо runs/pretrain/metrics.json: шаг → токены → losssteps = np.arange(1, 3001)tokens = steps * 32 * 512 # батч 32 × контекст 512train = 2.6 + 6.2 * steps ** -0.45 + rng.normal(0, 0.08, steps.size)# geomspace — 16 точек, равномерных в логарифмическом масштабе (1, 1.7, 2.9, …, 3000): val чаще в началеval_steps = np.unique(np.geomspace(1, 3000, 16).astype(int))val = 2.65 + 6.2 * val_steps ** -0.45
def ema(x, alpha=0.05): """Экспоненциальное сглаживание с поправкой на старт (как в Adam и TensorBoard).""" out, s = [], 0.0 for t, v in enumerate(x, start=1): s = alpha * v + (1 - alpha) * s out.append(s / (1 - (1 - alpha) ** t)) # без поправки кривая «тянется» от нуля return np.array(out)
fig, ax = plt.subplots(figsize=(6, 3.5))ax.plot(tokens / 1e6, train, alpha=0.25, lw=0.8, label="train (сырой)")ax.plot(tokens / 1e6, ema(train), lw=2, label="train (EMA)")ax.plot(val_steps * 32 * 512 / 1e6, val, "o-", label="val")ax.axhline(np.log(6400), ls="--", c="gray", lw=1)ax.text(0.03, np.log(6400) - 0.45, "ln V = 8.76 (старт)", color="gray")ax.set_xscale("log") # логарифм: видно и начало, и хвостax.set_xlabel("токены, млн") # ось X — токены, а не шаги: так графики сравнимыax.set_ylabel("cross-entropy, нат/токен")ax.set_title("Претрейн: train и val идут вместе — переобучения нет") # заголовок = выводax.legend()fig.tight_layout()os.makedirs("report", exist_ok=True)fig.savefig("report/fig_loss.png", dpi=150)print("сохранено: report/fig_loss.png", f"| финальный val loss = {val[-1]:.2f}")сохранено: report/fig_loss.png | финальный val loss = 2.82Откройте картинку и обратите внимание: в начале оранжевая кривая EMA идёт выше сырых точек — сглаживание отстаёт там, где loss падает быстро. Если бы вы смотрели только на сглаженную кривую, вы бы недооценили скорость обучения на старте.
Для GRPO нужны три графика рядом: средняя награда, средняя длина ответа и точность на eval-наборе по шагам. Награда без eval может расти из-за взлома награды (взлом наградывзлом награды (reward hacking)EN reward hackingПолитика находит способ получить высокую награду, не делая того, что задумали люди., урок 6.3.2), а длина ответа показывает, учится ли модель рассуждать — или просто удлиняет ответ.
Таблица результатов и абляции
Заголовок раздела «Таблица результатов и абляции»Абляцияабляционный эксперимент, абляцияEN ablation studyУбрать или заменить один компонент и сравнить с полной моделью, чтобы измерить вклад этого компонента. отвечает на вопрос «нужна ли эта деталь». Правила честной абляции:
- Меняется ровно один фактор относительно основного варианта.
- Всё остальное то же: данные, число шагов, бюджет, eval-набор, протокол оценки.
- У каждого числа интервал, а разницу сравнивают с шумом.
- Разница внутри шума — это тоже результат. Пишите «значимой разницы не обнаружено», а не «чуть хуже».
Таблицу генерируйте скриптом из metrics.json, а не переписывайте руками — так в отчёт не попадут опечатки:
import math
# Результаты на eval_v1 (300 задач): вариант → (верных, всего, доля ответов в формате)# Числа условные — подставьте свои из runs/*/metrics.jsonresults = { "SFT (база)": (102, 300, 0.86), "GRPO, G=8, формат + ответ": (156, 300, 0.97), "— без награды за формат": (141, 300, 0.71), "— группа G=4": (147, 300, 0.95), "— без KL к SFT": (152, 300, 0.93),}
def acc_ci(correct, n): p = correct / n return p, 1.96 * math.sqrt(p * (1 - p) / n)
bc, bn, _ = results["GRPO, G=8, формат + ответ"]base = bc / bn # с чем сравниваем абляцииprint("| Вариант | Точность, % | Δ к полному GRPO, п.п. | В формате, % |")print("|---|---|---|---|")for name, (c, n, fmt) in results.items(): p, h = acc_ci(c, n) delta = "—" if name.startswith("GRPO") else f"{100 * (p - base):+.1f}" print(f"| {name} | {100 * p:.1f} ± {100 * h:.1f} | {delta} | {100 * fmt:.0f} |")| Вариант | Точность, % | Δ к полному GRPO, п.п. | В формате, % |
|---|---|---|---|
| SFT (база) | 34.0 ± 5.4 | -18.0 | 86 |
| GRPO, G=8, формат + ответ | 52.0 ± 5.7 | — | 97 |
| — без награды за формат | 47.0 ± 5.6 | -5.0 | 71 |
| — группа G=4 | 49.0 ± 5.7 | -3.0 | 95 |
| — без KL к SFT | 50.7 ± 5.7 | -1.3 | 93 |
Сначала одна поправка к интуиции. В таблице стоят интервалы каждого варианта (около ±5.6 п.п.). Интервал разницы двух независимых оценок примерно в раза шире: здесь около ±8 п.п. Парный бутстрэп на одних и тех же задачах (уроки 1.3.4 и 7.3.2) обычно даёт интервал уже, поэтому для спорных строк делайте именно его.
Как это написать честно:
- GRPO против SFT (+18 п.п. при интервале разницы около ±8) — уверенный результат. Для уровня Strong всё равно подтвердите его парным бутстрэпом.
- Награда за формат: точность ниже на 5 п.п. — это внутри непарного интервала разницы, пока парный бутстрэп не покажет обратного. А доля ответов в формате упала с 97% до 71% — на 26 п.п. при интервале разницы около ±5.5: это далеко за пределами шума. Вывод: «награда за формат нужна прежде всего для формата; влияние на точность требует парной проверки или большего набора».
- G=4 и KL: разница 3 и 1.3 п.п. — внутри шума. Вывод: «на нашем масштабе значимой разницы не обнаружено». Это нормальный, полезный результат.
Неудачные попытки и ограничения
Заголовок раздела «Неудачные попытки и ограничения»Самый недооценённый раздел. В статье DeepSeek-R1 есть параграф «Unsuccessful Attempts»: авторы объясняют, почему у них не сработали reward model по шагам рассуждения (PRM) и поиск по дереву (MCTS). Этот параграф цитируют и обсуждают наравне с успехами: другим командам не нужно вслепую повторять те же тупики. В отчёте Qwen3 честно показано, что после этапов Thinking Mode Fusion и General RL результаты в режиме мышления на самых трудных задачах (AIME’24, LiveCodeBench) немного снизились — и авторы прямо называют это компромиссом ради универсальности.
Как писать о неудаче — четыре строки:
- Что пробовали: «награда за длину рассуждения, +0.1 за каждые 50 токенов».
- Что ожидали: «модель начнёт рассуждать подробнее и точность вырастет».
- Что получилось: «длина выросла в 3 раза за 200 шагов, точность упала на 6 п.п.; модель повторяла одну фразу».
- Почему (гипотеза) и что вынесли: «взлом награды — длину легко нарастить без смысла; награждать только результат».
Раздел ограничений отвечает на вопрос «где моей модели нельзя доверять»: на каких задачах она ломается, на каких языках не проверялась, какие числа получены на маленьком наборе, какие риски (уверенно неверные ответы, выдуманные факты). У DeepSeek-V3 тоже есть такой раздел: например, что рекомендуемая единица развёртывания велика для небольших команд. Ограничения не ослабляют отчёт — они делают остальные утверждения достойными доверия.
Китайское слово для защиты — «дабянь»защита проектаEN project defenseКороткий доклад о проекте и ответы на вопросы комиссии. В китайских вузах защита («дабянь») — обязательный финал выпускного проекта.: буквально «отвечать и аргументировать». Главное на защите — не доклад, а ответы на вопросы. План на 10 минут:
flowchart LR A["1 мин: задача и почему она проверяемая"] --> B["1 мин: схема из 7 этапов"] B --> C["2 мин: главный результат с интервалами"] C --> D["2 мин: абляция и неудача"] D --> E["3 мин: живая демонстрация"] E --> F["1 мин: ограничения и что дальше"]
Демонстрация. Покажите живой запрос к серверу и работу агента с калькулятором. Запишите видео заранее: если что-то упадёт, вы переключитесь на запись и продолжите спокойно.
Вопросы, к которым стоит подготовиться:
- Почему такой размер модели и столько токенов? (Ответ — бюджет из урока 10.1.1.)
- Откуда вы знаете, что прирост после GRPO — не шум?
- Как вы проверили, что задач из eval нет в обучающих данных?
- Что будет, если убрать награду за формат? А KL?
- Чем ваш агент лучше, чем просто вызвать калькулятор напрямую?
- Почему модель ошибается в задачах из четырёх действий? Что бы вы сделали с бюджетом в 10 раз больше?
- Сколько стоил проект в GPU-часах и где ушло больше всего времени?
- Что вы сделали бы по-другому, если бы начинали сначала?
Результаты автопроверки в отчёте
Заголовок раздела «Результаты автопроверки в отчёте»Если вы собирали проект в стартере homework/s10-capstone/ (урок 10.1.1, «Стартовый репозиторий»), у вас есть
две автоматические проверки. Обе нужно приложить к отчёту:
- автогрейдер
check.pyпоказывает, что код этапов правильный и связан в конвейер. Это уровни Simple–Boss на крошечной конфигурацииtiny; - самопроверка уровней проекта показывает, прошли ли числа вашего настоящего прогона пороги урока 10.1.1.
Сохраните оба вывода в один файл рядом с метриками запуска (здесь — для конфигурации M):
python homework/check.py s10-capstone > homework/s10-capstone/artifacts/m/check.txtpython homework/s10-capstone/code/eval.py --levels homework/s10-capstone/artifacts/m/metrics.json >> homework/s10-capstone/artifacts/m/check.txtВ Windows перед этим включите UTF-8 ($env:PYTHONUTF8=1 в PowerShell): без него запись эмодзи уровней в файл
может упасть с UnicodeEncodeError.
Как это оформить:
- Одна строка в разделе «Оценка»: «Автогрейдер: 🐉 Boss, 37 из 37 тестов; уровень проекта: Medium — для Strong не хватает второй абляции». Читатель сразу видит, что заявлено и что проверено.
- Приложение целиком:
check.txt, сводныйmetrics.json, конфиг запуска, коммит и команда воспроизведения. Числа в таблицах отчёта берите изmetrics.jsonскриптом, а не переписывайте руками. - Не путайте два уровня. Автогрейдер проверяет код на модели размером 0.13M параметров и ничего не говорит о качестве. В аннотацию и вывод идёт уровень проекта. Зелёный автогрейдер при уровне проекта «не пройден» — честный результат для XS, и так его и нужно описать.
Числа, которые не посчитать автоматически (абляции, страницы отчёта, защита), впишите в
artifacts/<запуск>/manual.json до самопроверки, например {"n_ablations": 2, "report_pages": 7}.
Чек-лист перед сдачей
Заголовок раздела «Чек-лист перед сдачей»- Аннотация из 5 предложений, каждое число в ней есть в таблицах
- Главный результат — на первой странице
- Таблица конфигурации модели и таблица гиперпараметров всех этапов
- Стоимость: GPU-часы (или CPU-часы) по этапам, железо
- Графики: ось X — токены, единицы на осях, заголовок-вывод, train и val вместе
- У всех ключевых чисел 95% интервалы; размер eval-набора указан
- Протокол оценки: промпт, temperature, число сэмплов, способ извлечения ответа
- Проверка контаминации train/eval описана
- Минимум 2 абляции с выводом «значимо / не обнаружено»
- Раздел о неудачных попытках
- Раздел ограничений и рисков
- Примеры генераций: удачные и неудачные
- Воспроизводимость: коммит, seed, команды,
requirements.txt,make all - Лицензии данных и базовых моделей указаны
- Самопроверка уровня по
metrics.json(урок 10.1.1) пройдена - Вывод
check.py s10-capstoneиeval.py --levelsприложен (если работали в стартере)
Что записать, чтобы ваш прогон повторил другой человек на другой машине (версии окружения, хэш данных, конфиг, команда запуска), — в уроке 11.1.3.
Промпт для ИИ-ревьюера
Заголовок раздела «Промпт для ИИ-ревьюера»Перед защитой отдайте отчёт строгому ревьюеру — Claude, DeepSeek, Qwen или GLM. Промпт построен так, чтобы модель искала слабые места, а не хвалила и не переписывала текст за вас:
Ты — рецензент выпускных проектов курса ChinaAI и строгий, но доброжелательный инженер.Ниже технический отчёт о проекте «своя LLM от токенизатора до агента» и файл metrics.json.
Проверь отчёт по рубрике (по каждому пункту: «выполнено / частично / нет» и одна фраза почему):1. Каждое утверждение в аннотации подкреплено числом из таблиц; числа совпадают с metrics.json.2. У ключевых чисел есть доверительные интервалы; выводы о разнице учитывают шум.3. Абляции меняют ровно один фактор при прочих равных; выводы не сильнее данных.4. Протокол оценки описан так, что его можно повторить; проверена контаминация.5. Есть честные разделы «Неудачные попытки» и «Ограничения».6. Графики читаемы: ось X — токены, единицы, заголовок-вывод.7. Проект воспроизводим: коммит, seed, команды, конфиги.
Затем:- перечисли 3 самых слабых места отчёта, начиная с самого серьёзного;- задай 5 вопросов, которые задала бы комиссия на защите;- оцени уровень проекта по критериям Simple / Medium / Strong / Boss и объясни, чего не хватает до следующего.
Правила: не переписывай отчёт и не пиши код за автора; не хвали без конкретики;если чего-то не видишь в тексте — так и скажи, не додумывай.
[ОТЧЁТ]...[metrics.json]...Практика
Заголовок раздела «Практика»Отчёт пишется за несколько вечеров. Порядок, который экономит время:
- Каркас. Скопируйте шаблон в
report/README.md. Разделы «Данные», «Модель» и «Обучение» заполните прямо изLOG.mdиruns/*/metrics.json— это механическая работа, с неё легко начать. - Рисунки. Постройте график loss кодом из урока, но на своих данных: ось X — токены, заголовок-вывод, линия . Для GRPO — три графика рядом: награда, длина ответа, точность на eval.
- Таблицы. Сгенерируйте таблицу абляций скриптом. Для каждой спорной строки посчитайте парный бутстрэп (код из урока 7.3.2): для этого сохраните ответы каждого варианта по задачам, а не только итоговую точность.
- Аннотация — последней. Когда таблицы готовы, напишите 5 предложений по формуле и проверьте, что каждое число в них есть в таблицах.
- Проверка. Пройдите чек-лист выше, приложите
check.txt(раздел «Результаты автопроверки в отчёте»), затем отдайте отчёт ИИ-ревьюеру у двух разных моделей. Замечания запишите вLOG.mdи отметьте, какие исправили. - Репетиция. Проговорите защиту вслух с таймером на 10 минут и ответьте вслух на 8 вопросов комиссии.
Проверь себя
Заголовок раздела «Проверь себя»- Техотчёт строится по скелету DeepSeek-V3 и Qwen3: главный результат сразу, каждое утверждение подкреплено, стоимость названа, у важных решений есть абляции, ограничения и неудачи — отдельными разделами.
- Графики: ось X — токены, сырые данные и сглаживание, train и val вместе, заголовок-вывод.
- Абляция меняет один фактор при прочих равных, и разница сравнивается с шумом. «Значимой разницы не обнаружено» — тоже результат.
- Защита — это ответы на вопросы. Готовьтесь по списку, демонстрацию страхуйте записью, отчёт проверяйте чек-листом и ИИ-ревьюером.
Отчёт — главный аргумент вашего портфолио: как сослаться на него в резюме и README и рассказать о проекте на собеседовании — в уроке 11.3.6.
Дальше: своя LLM собрана — теперь превращаем знания в профессию. Ступень 11 начинается с урока «Грязные данные: как выглядят настоящие датасеты»: там работа «как на работе», проектирование ML-систем, собеседования и план роста. Поле движется каждый месяц: ведите «журнал фронтира» (урок 9.2.2) и возвращайтесь к тетради ошибок — на сайте она хранит всё, что стоит повторить.