Перейти к содержанию
С нуля
Программа курса
EN Открыть

Программа курса

Неделя 1. Нейросети и градиенты

Фаза 1. Фундамент · неделя 1 из 24

Учиться в приложении: тьютор, задачи с кодом →

Ядро: MLP и формы тензоров, якобианы и цепное правило, функции активации, MLP на numpy с backward · Глубина: распределения и ожидание (трек D) · ≈ 10 ч ядро / 20 ч всё

Всё, что дальше делает модель, сводится к матричным умножениям, нелинейностям и градиентам по ним. Если здесь формы и Якобианы не станут автоматическими, каждая следующая неделя (backprop, внимание, LoRA) превратится в угадывание, где транспонировать. Неделя ставит один навык: вывести градиент слоя на батче и проверить его по форме.

Теория

  • MLP (многослойный перцептрон: слои «линейное преобразование → нелинейность» подряд): нейрон = f(wᵀx + b), слой = H = f(XW + b)
  • Батч-измерение: почему PyTorch хранит W как (n_out, n_in) и транспонирует. Транспонирование бесплатно: меняется только stride (шаг в памяти между соседними элементами по оси), данные не копируются. А градиент ∂L/∂W сразу выходит нужной формы
  • Функции активации: sigmoid, tanh, softmax (+ температура), ReLU, LeakyReLU, Swish (x·σ(x)), GLU (выход одной проекции, умноженный на гейт от другой), SwiGLU

На пальцах. Слой «умножь на 2», за ним слой «умножь на 3»: вместе это один слой «умножь на 6». Сколько линейных слоёв ни ставь подряд, в сумме выйдет одна матрица. Нелинейность это ломает. ReLU(x) − ReLU(x − 1) равна 0 при x = −1, 0.5 при x = 0.5 и 1 при x = 2. Это ступенька, а ни одна прямая ступеньку не нарисует.

  • Почему без нелинейностей глубина бесполезна: W₁W₂x = Wx

На пальцах. Производная сигмоиды нигде не больше 0.25. В backward через каждый слой с сигмоидой градиент умножается на σ', то есть в лучшем случае на 0.25. Через 10 таких слоёв остаётся 0.25¹⁰ ≈ 10⁻⁶ от исходного сигнала. Первые слои почти не учатся.

  • Проблемы: vanishing gradients (затухание градиента) у sigmoid (σ' ≤ 0.25), не-zero-centered выход (выход сигмоиды всегда положителен, и градиенты всех входных весов нейрона получаются одного знака), dying ReLU (нейрон ушёл туда, где на всех входах выдаёт 0, и градиент к нему больше не приходит)

На пальцах. Функция из двух чисел в два: f(x, y) = (x·y, x + y²). В точке (2, 3) она выдаёт (6, 11). Сдвинем x на 0.01: выход станет (6.03, 11.01), прирост (0.03, 0.01). Сдвинем y на 0.01: выход (6.02, 11.0601), прирост (0.02, 0.0601). Поделим приросты на шаг: столбец по x равен (3, 1), столбец по y равен (2, 6.01). Лишние 0.01 появились из-за квадрата: это вклад 0.01²; при меньшем шаге они исчезают. Получилась таблица [[3, 2], [1, 6]]. Это и есть Якобиан: каждая строка отвечает одному выходу, каждый столбец одному входу. Формулой: J = [[y, x], [1, 2y]].

  • Градиент (вектор производных скалярной функции по всем входам), Якобиан (m×n: производная каждого из m выходов по каждому из n входов), Гессиан (n×n, вторые производные, то есть кривизна ландшафта потерь)
  • Цепное правило: для многомерных функций это перемножение Якобианов
  • Якобиан поэлементной функции = diag(f'(z)): выход i зависит только от входа i, поэтому вне диагонали нули

Вывести на бумаге (обязательно)

  • ∂/∂x (Wx+b) = W, ∂/∂b (Wx+b) = I, ∂/∂u (uᵀh) = hᵀ
  • Производную сигмоиды через частное: σ' = σ(1−σ)
  • Производную Swish через произведение: σ(x) + Swish(x)(1−σ(x))

На пальцах. Один вес w = 3, батч из двух чисел x = (1, 2), выходы zᵢ = w·xᵢ, лосс L = z₁ + z₂ = 9. Сдвинем w на 0.01: сдвинутся оба выхода, и L вырастет на 0.01·(1 + 2). Значит, ∂L/∂w = 1 + 2 = 3: вклады примеров сложились в одно число, ведь и сам w один на батч. Сдвинем только x₁: изменится только z₁, поэтому ∂L/∂x₁ = 3. Так же ∂L/∂x₂ = 3. Итог (3, 3): по числу на пример, той же формы, что x.

Как не путаться в формах при батче. Выводи Якобиан для одного примера: там всё двумерно и очевидно. Дальше вопрос только в том, куда девается батчевая ось, и ответ следует прямо из того, сколько раз тензор участвует в вычислении:

  • W один на весь батч, каждый пример даёт свой вклад в ∂L/∂W → вклады складываются, батчевая ось исчезает (свёртка по ней внутри матмула).
  • X у каждого примера свой, строки Z не смешиваются между примерами → градиенты просто укладываются стопкой, батчевая ось сохраняется.

Проверка на здравый смысл: ∂L/∂W обязана иметь форму W, а ∂L/∂X обязана иметь форму X. Если получилось иначе, ось потеряна или лишняя.

Линейный слой на батче: куда девается батчевая осьЛинейный слой на батче: куда девается батчевая ось
Схема 6. Forward Z = XW + b и два градиента: в ∂L/∂W = Xᵀ·∂L/∂Z батчевая ось m свёрнута, вклады примеров складываются; в ∂L/∂X = ∂L/∂Z·Wᵀ она сохранена, градиенты лежат стопкой.

Код (трек B): MLP на голом numpy: forward и backward вручную, без autograd. Проверить численным градиентом (разностью (f(w+h) − f(w−h)) / 2h по каждому весу).

Математика (трек D): Bernoulli, Binomial, Poisson, Geometric. Вывести E[X] и Var[X] для каждого. Приём: X² = X для индикаторов. Приём: разложить на Бернулли и использовать линейность.

LeetCode: массивы, хеш-таблицы, два указателя (3 задачи по списку трека C).

Интервью-вопрос недели: «Выведи градиенты линейного слоя Z = XW + b на батче. Какой формы ∂L/∂W и ∂L/∂X?» Структура на 3 минуты: (1) первым назови формы: X это (m, n), W это (n, k), Z это (m, k); (2) вывод на одном примере, где всё двумерно, потом один вопрос: куда девается батчевая ось; (3) главный вывод: W один на батч → вклады складываются, ∂L/∂W = Xᵀ·∂L/∂Z; X у каждого примера свой → стопка, ∂L/∂X = ∂L/∂Z·Wᵀ; ∂L/∂b это сумма по батчу; (4) проверка: градиент обязан иметь форму своего тензора, плюс численный градиент центральной разностью, относительная ошибка < 1e-6 в float64; (5) жди уточнения «почему PyTorch хранит W как (n_out, n_in)». Ответ: транспонирование бесплатно, меняется только stride.

Глубже: 05-ГЛУБИНА, раздел «Недели 1–4, трек D. Математика: большой недобор».

Результаты недели

  • Могу вывести на бумаге ∂(Wx+b)/∂x, ∂/∂W, ∂/∂b, производные сигмоиды и Swish за 10 минут без подсказок.
  • Могу по формам сказать, где батчевая ось суммируется (∂L/∂W), а где сохраняется (∂L/∂X), и проверить результат по форме.
  • Могу реализовать MLP на numpy с ручным backward и подтвердить его численным градиентом (относительная ошибка < 1e-6 в float64).
  • Могу за 2 минуты объяснить, почему без нелинейности глубина бесполезна и почему сигмоида ведёт к затуханию градиента.

Самопроверка

  1. Почему для батча ∂L/∂W это сумма вкладов примеров, а ∂L/∂X стопка? Назови формы обоих.
  2. Чему равен Якобиан поэлементной функции и почему он диагональный?
  3. Три проблемы сигмоиды в скрытом слое, что из них решает ReLU и какая проблема появляется у ReLU?

В приложении у недели есть навыки для самооценки, вопросы с проверкой ответа, задачи с кодом на Python и тьютор по материалам курса.

Учиться в приложении: тьютор, задачи с кодом
← НазадМодуль 0. Фундамент до старта Дальше →Неделя 2. Backpropagation

С нуля
С нуля: курс по LLM

  • Главная
  • Программа курса
  • Приложение
  • Конфиденциальность
  • Условия

Текст курса распространяется по лицензии CC BY-NC-SA 4.0, код nanolm по лицензии Apache-2.0.