Содержание
На столе три объявления. Квартира 30 квадратных метров стоит 3,0 миллиона, 50 метров — 4,2, 70 метров — 5,4. Нужно прикинуть четвёртую, не вызывая оценщика.
Дальше эти объявления тянутся через всю статью. Площадь и цена — данные. Правило «цена метра умножить на площадь и прибавить надбавку» — функция, которая из площади делает ответ. Цена метра и надбавка — параметры, два числа, которые можно крутить. Промах в миллионах — функция потерь. Фраза «чуть поднять цену метра» или «чуть опустить» — градиент. Объявление из другого района, которого не было при настройке, — новый пример. Математика машинного обучения — не полка формул. Это способ записать квартиру числами, выставить числа правила, измерить промах и проверить, держится ли цена на объявлениях, которых при настройке не было.
Ключевые выводы
Обучить — выставить цену метра и надбавку по объявлениям. Форма правила выбирается заранее. Числа внутри подбираются так, чтобы промах на известных объявлениях стал меньше.
Одна прямая линия не рисует изгиб. Линейный слой умеет взвесить признаки. Изгиб, развилка и «да или нет» появляются, когда слои складываются и между ними стоит нелинейная функция.
Ошибка — не приговор, а направление. Производная говорит, поднимать цену метра или опускать. Обратный проход доносит этот совет от итогового промаха до самых ранних чисел.
Попадание в свои объявления не доказывает цену в чужом районе. Выборка, функция потерь и метрика решают, какую ошибку вы считаете дорогой. Доля верных ответов на перекошенных данных легко выглядит победой.
Одна и та же математика сидит в классификаторе, свёртке, рекурсии и внимании. Меняется форма правила: окно пикселей, память предыдущего шага или взвешенное среднее по смыслу.
Обучить модель — это подобрать цену метра
Три вещи часто называют одним словом «нейросеть», хотя для этих объявлений это разные предметы.
Алгоритм — порядок действий без подстройки под эти три квартиры. «Умножь площадь на пять сотых и прибавь миллион» — уже готовое правило: числа выставлены заранее, ваши объявления их не двигают.
Математическая модель — форма правила с пустыми числами. Для цены по площади форма такая: цена = вес × площадь + смещение. Вес — это цена метра, смещение — надбавка. Их ещё нет, есть только места, куда их поставят.
Обученная модель — та же форма, но числа уже выставлены. Вес 0,06 и смещение 1,2 попадают в три объявления без промаха: 0,06 × 30 + 1,2 = 3,0; для 50 метров выходит 4,2; для 70 — 5,4. «Обучить» здесь значит подобрать эти два числа.
Если выставить вес 0,05 и смещение 1,0, предсказания станут 2,5, 3,5 и 4,5. Промахи: 0,5, 0,7 и 0,9 миллиона. Средний квадрат промаха — 0,52. Квадрат нужен не для красоты: крупный промах весит больше мелкого, и знак «дешевле или дороже» не сокращается при сложении. Нулевая ошибка при весе 0,06 говорит только об этих трёх карточках. Четвёртая квартира с ремонтом, этажом и районом в правило не входила.
Связка одна и та же на любом числе объявлений. Данные — карточки. Параметры — числа правила. Функция считает цену. Функция потерь говорит, насколько цена не та. Обучение двигает числа в сторону меньшего промаха. Проверка на отложенных объявлениях отвечает, не запомнили ли вы только эти три карточки.
areas = [30, 50, 70]
prices = [3.0, 4.2, 5.4]
def predict(area, weight, bias):
return weight * area + bias
def mean_squared_error(weight, bias):
errors = [
predict(area, weight, bias) - price
for area, price in zip(areas, prices)
]
return sum(error * error for error in errors) / len(errors)
print(round(mean_squared_error(0.05, 1.0), 2)) # 0.52
print(mean_squared_error(0.06, 1.2)) # 0.0
Покрутите вес на одну сотую и посмотрите, как вспухает ошибка. Это и есть практика раздела: модель из одного числа уже показывает, что обучение — перебор чисел, а не магическая программа.
Какие числа нужно узнавать по дороге
Не обязательно год учить анализ, чтобы прочитать первую модель. Нужен короткий набор слов, и каждое слово привязано к этим объявлениям.
Переменная — имя числа, которое может смениться: площадь, вес, ошибка. Функция забирает аргументы и отдаёт число. Цена от площади — функция. Аргумент — то, что вы кладёте внутрь, а не то, что функция «думает».
Проценты, степени и логарифмы встречаются раньше, чем кажется. Вероятность 0,01 — один шанс из ста. Степень растит или гасит число при повторном умножении. Логарифм потом накажет уверенную ошибку сильнее, чем робкую: минус логарифм от 0,1 больше, чем от 0,9. Пока достаточно знать, что логарифм большой, когда аргумент близко к нулю.
График — та же функция, положенная на плоскость. По горизонтали цена метра, по вертикали промах. Минимум — ямка, где промах меньше всего. Плато — полка, где промах почти не меняется, хотя цена всё ещё плохая.
Сумма и среднее описывают кучу чисел одним. Для списка 2, 4, 4, 4, 5, 5, 7, 9 среднее — 5. Разброс можно считать двумя способами. Если описываете именно этот список, делите сумму квадратов отклонений на 8 и получаете стандартное отклонение 2. Если список — пачка из более длинного списка и вы хотите прикинуть длинный список, делите на 7 и получаете около 2,14. Расстояние между двумя объектами — длина отрезка между их числами. Две квартиры с площадями 30 и 70 «далеко» на 40 метров; если признаков несколько, расстояние считают сразу по всем осям.
Производная — скорость, с которой промах меняется, когда вы чуть крутите цену метра. Положительная: промах растёт, цену метра стоит опустить. Около нуля: небольшое движение цены метра почти не меняет промах.
Вероятность — не «модель сомневается по-человечески», а число от 0 до 1, которым вы описываете долю исходов. Случайная величина — величина, которая при повторении опыта прыгает по распределению, а не выписывает одно и то же число.
Заранее полезно спокойно читать функцию, среднее, график и фразу «чуть изменить аргумент». Логарифм, частные производные и теорему Байеса можно добирать в том разделе, где они впервые нужны задаче. Откладывать их «на потом после всей книги» не нужно: они короткие, если рядом пример.
values = [2, 4, 4, 4, 5, 5, 7, 9]
mean = sum(values) / len(values)
spread = (sum((value - mean) ** 2 for value in values) / len(values)) ** 0.5
distance = abs(70 - 30)
print(mean, spread, distance) # 5.0 2.0 40
Объект становится строкой чисел, слой — умножением
Нейросеть не видит квартиру, букву и кадр. Она видит строку чисел. Площадь, этаж и «есть ли балкон» — уже вектор признаков: (50, 4, 1). Несколько таких строк складываются в матрицу, пакет строк — в тензор. Имя «тензор» не добавляет магии: это массив, у которого договорились о порядке осей.
Скалярное произведение — взвесить признаки и сложить. Признаки (1, 2) и веса (0,5, −0,1) дают 0,5 × 1 + (−0,1) × 2 = 0,3. Так один выход считает взвешенную сумму входа. Матрица весов делает это сразу для нескольких выходов. Линейное преобразование поворачивает, растягивает и сдвигает облако точек; само по себе оно не загибает прямую в дугу.
Картинка серого цвета — матрица яркостей. Цветная — тензор с осью каналов. Текст после разбиения на куски — последовательность целых номеров, а потом строки вещественных векторов. Пакет из восьми картинок добавляет ещё одну ось. Путаница размеров — самая частая поломка: вы умножаете строку на строку другой длины. В уроке про картинку как тензор это видно на кропе текста: пиксели уже числа, до свёртки ещё далеко.
Линейный слой записывают так: y = Wx + b. Здесь x — входной вектор, W — матрица весов, b — смещение, y — выход. Смещение нужно, чтобы нулевой вход не обязан давать нулевой выход: квартира нулевой площади в нашей формуле всё равно стоила бы 1,2, если бы такая существовала. Это не рыночная истина, это свойство формы.
Возьмите вход (1, 2), матрицу с рядами (0,5, −0,1) и (0,2, 0,3), смещение (0,1, −0,2). Первый выход: 0,5 × 1 + (−0,1) × 2 + 0,1 = 0,4. Второй: 0,2 × 1 + 0,3 × 2 − 0,2 = 0,6. Тот же слой в PyTorch — объект torch.nn.Linear. Веса лежат в матрице формы «выход на вход», и результат совпадает, если скопировать те же числа.
import torch
x = torch.tensor([1.0, 2.0])
layer = torch.nn.Linear(2, 2)
with torch.no_grad():
layer.weight.copy_(torch.tensor([[0.5, -0.1], [0.2, 0.3]]))
layer.bias.copy_(torch.tensor([0.1, -0.2]))
print(layer(x)) # tensor([0.4000, 0.6000])
Каркас, в котором живут такие слои, — отдельный разговор: PyTorch, TensorFlow и JAX отличаются записью слоя в коде, не таблицей умножения.
Прямая линия не рисует изгиб
Сложите два линейных слоя без промежуточной развилки — снова получите линейный слой. Две поправки «умножить и прибавить» подряд остаются одной такой поправкой. Поэтому между слоями ставят функцию, которая умеет срезать, прижимать или плавно гасить.
ReLU оставляет положительное число и обнуляет отрицательное. На входах −2, −0,5, 0, 0,5, 2 она даёт 0, 0, 0, 0,5, 2. Мёртвая зона слева — плата за простоту: пока сумма до активации отрицательна, эта ветка не передаёт градиент.
Сигмоида sigmoid прижимает любое число к интервалу от 0 до 1. Те же входы дают примерно 0,119, 0,378, 0,5, 0,622, 0,881. Удобно, когда выход хочется читать как долю. На краях она почти плоская: менять вес там почти бесполезно.
Гиперболический тангенс tanh похож, но интервал от −1 до 1: примерно −0,964, −0,462, 0, 0,462, 0,964. Ноль остаётся нулём, крупные входы прилипают к краям.
GELU глаже, чем ReLU: отрицательные числа не рубятся в ноль, а сильно уменьшаются. На тех же входах приближение даёт примерно −0,045, −0,154, 0, 0,346, 1,955. Современные языковые блоки часто берут именно её, не потому что она «умнее», а потому что гладкий срез устойчивее на глубокой стопке слоёв.
softmax превращает сырые оценки в доли, которые складываются в единицу. Оценки 2,0, 1,0 и 0,1 становятся примерно 0,659, 0,242 и 0,099. Это ещё не истина о мире. Это способ разложить перевес оценок на конкурентов так, чтобы сумма была 1.
Одной линейной операции мало, когда граница между классами изогнута или когда ответ зависит от сочетания, а не от отдельного признака. «Большая площадь и первый этаж» — не сумма двух независимых надбавок, если первый этаж портит именно большую квартиру. Составная функция — слой, потом срез, потом слой — собирает такие сочетания. Глубина здесь не украшение: каждый срез добавляет излом, который предыдущая прямая нарисовать не могла.
Нарисуйте четыре активации на одной оси от −2 до 2. Глаз сразу видит, где функция молчит, где режет и где ещё слышит маленькое изменение веса.
Производная показывает, в какую сторону крутить
Вернитесь к ямке на графике промаха. Для круглой картинки возьмём одно число w и ошибку L(w) = (w − 3)². Минимум в точке 3, там ошибка ноль. Это не цена метра 0,06 из объявлений: та же идея на ямке, где дно видно сразу. Производная равна 2(w − 3). Слева от тройки она отрицательна: ошибка убывает, когда число растёт. Справа — положительна: ошибка убывает, когда число уменьшается. Градиент — эта производная, собранная по всем числам сразу. Он показывает направление наискорейшего роста ошибки. Чтобы уменьшать промах, идут против него.
Шаг записывают так: θ(t+1) = θ(t) − η · ∇L(θ(t)). θ — все числа правила разом, η — скорость обучения, величина шага. Старт в нуле, скорость 0,1. Ошибка 9, градиент −6, новое число 0,6. Дальше оно идёт 1,08, затем 1,46, 1,77, 2,02, 2,21, 2,37. Ошибка за эти шаги падает с 9 до примерно 0,40. До тройки ещё есть путь: шаг постоянный, ямка сужается, и хвост приближения длинный.
Слишком крупный шаг перепрыгивает ямку и может уйти вверх. Слишком мелкий ползёт, пока не кончится терпение или данные. Локальный минимум — ямка, которая не самая глубокая на всём графике, но из неё маленький шаг не выбирается. Плато — место, где градиент почти ноль, хотя промах ещё большой: небольшое движение числа почти не говорит, куда идти. На практике смотрят не только на конечное число, а на то, падает ли ошибка и не скачет ли она через край.
Картинка этого раздела — точки (w, L) по шагам. Они должны сползать в ямку, а не рисовать пилу.
Промах надо провести назад по слоям
В сети из многих слоёв число первого слоя не видно в итоговой цене. Оно меняет промежуточный расчёт, тот меняет ответ, ответ меняет промах. Чтобы понять, как двигать раннее число, ошибку проводят назад по той же цепочке. Это правило цепочки: производная составной функции равна произведению производных по дороге.
Маленькая сеть, все числа наружу. Вход x = 1, цель — 0. Первый слой: z = 0,5 × x − 0,2 = 0,3. Срез ReLU оставляет 0,3. Второй слой: y = 0,8 × 0,3 + 0,1 = 0,34. Ошибка — квадрат промаха: (0,34 − 0)² = 0,1156.
Производная ошибки по выходу равна 2 × 0,34 = 0,68. По весу второго слоя: 0,68 × 0,3 = 0,204. По его смещению: 0,68. По скрытому числу: 0,68 × 0,8 = 0,544. Срез справа от нуля пропускает градиент как есть, слева обнулил бы. Вход равен 1, поэтому вес и смещение первого слоя получают ту же 0,544.
Автоматическое дифференцирование в PyTorch считает то же самое, если пометить числа как величины, от которых нужен градиент, и вызвать обратный проход. Расхождение в третьем знаке — повод проверить формулу, а не «магию каркаса». Ручной расчёт на двух слоях нужен один раз: дальше сеть глубже, а смысл тот же. Промах в ответе доходит до первого числа произведением множителей. Если множители по дороге меньше единицы и их много, сигнал затухает. Если больше единицы и их много — раздувается. Отсюда осторожность к глубине, инициализации и срезам, которые на краях замолкают.
import torch
w1 = torch.tensor(0.5, requires_grad=True)
b1 = torch.tensor(-0.2, requires_grad=True)
w2 = torch.tensor(0.8, requires_grad=True)
b2 = torch.tensor(0.1, requires_grad=True)
hidden = torch.relu(w1 * 1.0 + b1)
output = w2 * hidden + b2
loss = (output - 0.0) ** 2
loss.backward()
print(round(w2.grad.item(), 3)) # 0.204
print(round(w1.grad.item(), 3)) # 0.544
Выборка — не весь мир, и не всякая ошибка одинакова
Три квартиры — не рынок. Это короткая пачка карточек. Случайная величина описывает, как число прыгает от опыта к опыту. Распределение говорит, какие прыжки частые. Среднее и дисперсия сжимают распределение в центр и ширину. Условная вероятность — доля при уже известном факте: цена при данной площади, а не цена «вообще».
Теорема Байеса переставляет условие. Болезнь встречается у 1 человека из 100. Тест ловит её в 99 случаях из 100 и ошибочно срабатывает у 5 здоровых из 100. Положительный тест всё ещё чаще про здорового: вероятность болезни при положительном тесте около 0,17, а не 0,99. Модель, которая выдаёт долю, легко спутать с частотой в мире. Байес напоминает, что редкий класс и чувствительный тест не дают автоматической уверенности.
Максимальное правдоподобие — другой вход в ту же задачу. Подбирают числа, при которых увиденные цены были бы наиболее ожидаемыми. Для многих задач это совпадает с минимизацией определённой функции потерь. Перекрёстная энтропия как раз из этого семейства: она велика, когда модель отдала маленькую долю верному классу.
Смещение выборки — перекос карточек. Если все объявления из одного района, вес «метр стоит шесть сотых миллиона» не обязан пережить другой район. Репрезентативность — насколько пачка похожа на район, откуда придут новые объявления. Переобучение — правило, которое запомнило сегодняшние карточки, включая случайную странность. Недообучение — слишком грубая форма: одна прямая там, где нужен изгиб. Качество на обучающих карточках не обещает качества на новых. Поэтому примеры делят: на одной части двигают числа, на другой смотрят, не выросла ли ошибка. Способ разреза сам влияет на оценку. Случайный разрез одного района бодр и бесполезен, если новые объявления придут из другого.
Функция потерь решает, какой промах дорог. Средний квадрат, MSE, сильно штрафует выброс: одна квартира за 20 миллионов тянет прямую на себя. Средний модуль, MAE, считает все промахи ровнее и спокойнее переносит редкую безумную цену. Для ответа «да или нет» берут двоичную перекрёстную энтропию: она смотрит на долю, отданную верному ответу. Для нескольких классов — ту же идею по всем классам сразу. Минус логарифм доли верного класса на оценках 2,0, 1,0 и 0,1 равен примерно 0,42, если верен первый класс. Если бы доли были равны, штраф был бы около 1,10. Уверенная ошибка, когда почти вся масса ушла не туда, даёт ещё больший логарифм.
Одна и та же архитектура с разными потерями расходится на данных с выбросом. Квадрат гонится за выбросом, модуль держит основную массу. Минимальная ошибка на учебных карточках по-прежнему не обещает новых объявлений: потеря выбрана под учебные карточки.
Сгенерируйте две выборки из разных центров, нарисуйте гистограммы и обучите прямую на одной, проверив на другой. Расхождение средних важнее красивого графика обучения.
Один проход: цена, промах, поправка
Полный цикл собирает предыдущие части в один проход.
Сначала собирают вход: числа одного масштаба, одинаковая длина, честный разрез на учебную, проверочную и отложенную части. Потом прямой ход считает предсказание: слои, срезы, при необходимости softmax. Потом функция потерь сравнивает названную цену с настоящей. Потом обратный проход пишет градиент по каждому числу. Потом оптимизатор делает шаг. Потом проход повторяется.
Эпоха — полный проход по учебным объявлениям. Батч — пачка, по которой считают один градиент: не весь район сразу, а несколько карточек. Итерация — один такой шаг. Стохастический градиентный спуск берёт маленькую пачку, поэтому направление шумное, зато шаг дешёвый. Импульс (momentum) добавляет инерцию: поправка не дёргается от каждой странной карточки. Adam держит отдельные скорости по числам и подстраивает шаг. AdamW отдельно затухает сами веса, чтобы регуляризация не путалась с этой подстройкой. Для первой прямой хватает обычного шага против градиента. Имена оптимизаторов нужны, когда чисел много и они разного масштаба.
Инициализация задаёт числа до первого прохода. Нули во всех весах делают симметричные нейроны близнецами: градиент их не различает. Слишком крупные стартовые числа на сигмоиде уезжают в плоский край. Нормализация приводит пачку к устойчивому масштабу, чтобы следующий слой не получал то шёпот, то крик. Регуляризация — штраф за слишком большие числа правила: затухание весов, случайное зануление части связей (dropout), ранняя остановка, когда проверочная ошибка пошла вверх, а учебная ещё падает.
Обучение расходится, когда шаг слишком велик или потери посчитаны в неудобном масштабе. Оно замирает, когда градиент умер в плоском срезе, данные не несут сигнала или числа упёрлись в регуляризатор. Высокоуровневая обёртка вроде Trainer прячет этот проход. Полезный минимум — увидеть его без обёртки.
На синтетических ценах со площадью, поделённой на десять, истинный наклон около 0,6 и смещение около 1,2, плюс небольшой шум. Старт из нуля и скорость 0,02. Первая потеря — порядка 18: предсказание нулевое, цены живые. Через несколько сотен шагов потеря падает к сотым, наклон подходит к 0,6, а смещение догоняет медленнее. Признак не вычли из среднего, поэтому цена метра и надбавка живут в разных масштабах. Это не поломка оптимизатора. Это геометрия правила. Фиксируйте зерно генератора, записывайте скорость и число шагов, иначе «у меня сошлось» нельзя повторить.
Каркасы отличаются тем, как этот проход записан в коде. Сравнение двух записей — в PyTorch и TensorFlow.
Метрики, окно пикселей и память шага
Когда ответ — не цена, а метка, прямая становится границей. Логистическая регрессия — линейный счёт плюс сигмоида: по одну сторону порога класс «да». Несколько классов — несколько счетов и softmax. Граница линейного слоя прямая или плоская. Изогнутая граница требует срезов, о которых речь шла выше.
Матрица ошибок раскладывает промахи. Десять снимков: шесть кошек и четыре собаки. Модель верно назвала пять кошек и трёх собак, одну кошку записала собакой, одну собаку — кошкой. Доля верных — 0,8. Точность по кошке — 5 из 6 срабатываний, полнота — 5 из 6 настоящих кошек. F1 сводит точность и полноту в одно число; здесь оно около 0,83. Если называть кошкой всё подряд, доля верных падает до 0,6, полнота по кошке становится 1, а точность — 0,6. Одна цифра «доля верных» этого развода не показывает. На редкой болезни та же ловушка, что и в тесте из предыдущего раздела.
Для рамки вокруг объекта смотрят пересечение над объединением, IoU. Два квадрата 2×2, сдвинутые на единицу, пересекаются по площади 2 при объединении 6: IoU равен одной трети. Средняя точность по порогам и классам, mAP, собирает такие попадания в одну сводку для детекции. Уверенность модели — доля после softmax, и её полезно сверять с частотой правоты, а не верить вывеске.
Свёртка — то же умножение, но окно едет по картинке. Ядро 2×2 с числами (1, 0; 0, 1) на картинке
1 2 3
0 1 2
1 0 1
даёт четыре отклика: 2, 4, 0, 2. Ядро ищет местный узор, а не взвешивает все пиксели одним вектором. Карта признаков — новый «снимок» откликов. Размеры выхода зависят от размера окна, шага и дополнения краёв. Классификатор кадра, детектор и распознавание цифр отличаются головой сети и метрикой, не таблицей умножения. Практический вход в кадр как в числа — серия CNN и CRNN с нуля и обзор зрения на PyTorch и TensorFlow.
Рекуррентный шаг помнит предыдущий шаг. Скрытое состояние — число или вектор, который переносится на следующий токен. Упростим до одного числа: новое состояние = tanh(0,5 × прошлое + 1 × текущий вход), старт с нуля, входы 1, 0, 1. Состояния примерно 0,762, затем 0,363, затем 0,828. Ноль на втором шаге не стирает память полностью: 0,363 — след единицы. LSTM и GRU добавляют ворота, которые решают, что запомнить, что забыть и что выпустить. Без ворот длинная цепочка множителей легко затухает или взрывается — тот же эффект, что на глубокой стопке слоёв.
Соберите свёртку на матрице 3×3 руками, затем три шага рекурсии на бумаге. Оба упражнения короче, чем библиотечный вызов, и оба показывают, где живут параметры.
Внимание — взвешенное среднее по смыслу
Языковая модель кормит последовательность векторов, эмбеддингов: кусок текста стал строкой чисел. Позиционное представление добавляет место в строке, иначе «кот погнался за псом» и обратный порядок выглядели бы одинаково для набора мешков без порядка.
Внимание спрашивает: на какие другие куски опереться, собирая смысл текущего. Запрос, ключ и значение — три матрицы, обычно полученные из одних и тех же входов разными линейными слоями. Запрос — «что я ищу», ключ — «чем я могу отозваться», значение — «что я отдам, если отозвусь».
Формула: Attention(Q, K, V) = softmax(QKᵀ / √dₖ) V. Скалярные произведения запросов и ключей — таблица сходства. Деление на корень из размера ключа не даёт произведениям раздуться: без него softmax прилипает к одному победителю и градиент замолкает. softmax по строке превращает сходства в доли. Умножение на значения собирает взвешенное среднее тех векторов, которые отозвались.
Числа на двух кусках и размере 2. Запросы — строки (1, 0) и (0, 1). Ключи — (1, 0) и (1, 1). Значения — (1, 2) и (3, 4). После деления на √2 и softmax первая строка весов — 0,50 и 0,50, вторая — примерно 0,33 и 0,67. Выходы — (2, 3) и примерно (2,34, 3,34). Первому куску оба значения равно интересны, второму ближе второй ключ. Поменяйте входные векторы — доли поедут. В этом весь опыт раздела.
Несколько голов — несколько таких троек параллельно, потом их склеивают. Одна голова может смотреть на соседнее слово, другая — на подлежащее в начале фразы. Остаточная связь прибавляет вход блока к его выходу, чтобы глубокая стопка не обязана была заново выучить тождество. Нормализация держит масштаб перед следующим блоком.
Обучение языковой модели чаще всего предсказывает следующий кусок. Потеря — перекрёстная энтропия по верному номеру в словаре. Принудительная подача верного предыдущего куска на учебном проходе (teacher forcing) не даёт ранней ошибке увести всю фразу: при обучении модели подсказывают предыдущий кусок. На генерации подсказки нет, модель продолжает уже свой текст. Окно контекста — сколько кусков входит в один проход. Сравнение каждого с каждым стоит квадратично от длины окна: вдвое длиннее текст — примерно вчетверо больше таблицы сходства.
Температура перед выбором следующего куска растягивает или сужает доли. Ниже единица — чаще победитель. Выше — чаще хвост. Это не новое обученное число, а способ читать уже посчитанные оценки.
Разбор той же схемы по шагам кода — в уроке про внимание с нуля. С чего начинается вся серия лаборатории — в первом уроке.
Новые объявления приходят после настройки
Обобщение — держится ли цена на объявлениях, которых не было при настройке. Компромисс смещения и разброса говорит о двух разных порчах. Смещение — слишком жёсткая форма, которая промахивается даже в среднем: одна прямая на изогнутом рынке. Разброс — форма такая гибкая, что новая пачка карточек переставляет числа до неузнаваемости. Простая модель врёт устойчиво. Слишком богатая запоминает случайные странности.
Калибровка спрашивает, совпадает ли заявленная доля с частотой правоты. Девять верных из десяти там, где модель говорила «0,9», — честная вывеска. Шесть из десяти при той же вывеске — костюм уверенности. Дисбаланс классов делает долю верных ответов дешёвой победой: всегда говорить «здоров» при пяти больных на сто человек даёт 0,95 и нулевую пользу. Метрику считают на отложенной тестовой пачке, которую не трогали ни при подборе чисел, ни при выборе скорости.
Квантование хранит числа грубее. На трёх квартирах вес 0,06 и смещение 1,2 попадают в цены. Округлите вес до десятых — получите 0,1 — и предсказания станут 4,2, 6,2 и 8,2. Экономия разрядов здесь ломает правило, потому что важная цена метра жила в сотых. В большой сети многие веса терпят округление, некоторые нет. Поэтому уменьшение файла не пропорционально потере качества: страдают отдельные оси, не «модель вообще». Численная устойчивость — тот же сюжет в обучении. Сложение огромного и крошечного числа в ограниченной точности теряет крошечное. Отсюда масштабирование в внимании, аккуратные потери и форматы вроде половинной точности на ускорителе.
Локальный запуск упирается в память, пропускную способность и то, влезает ли окно контекста. Математика не отменяет корпус и диск. Она объясняет, почему после округления одна задача жива, а другая поплыла. Железо, на котором это считают, разобрано отдельно: процессор, графический ускоритель и соседние чипы. Вывоз уже обученной сети в другой исполнитель — в заметке про ONNX.
Сквозной проект, который закрывает статью, короткий и воспроизводимый.
- Синтетическая выборка цен с известными наклоном, смещением, шумом и фиксированным зерном.
- Линейная модель на NumPy, без библиотеки обучения.
- Средний квадрат своими руками.
- Градиент по весу и смещению своими руками.
- Цикл шагов и график потери.
- Та же задача сетью из двух слоёв со срезом
ReLU. - Сверка градиента с
autograd. - Ошибка на отложенной трети, которую цикл не видел.
- Три скорости шага: мелкая, рабочая, слишком крупная.
- Файл зависимостей, команда запуска и таблица: скорость, конечная потеря, ошибка на отложенных.
Дальше имеет смысл углублять не «всю математику», а ту часть, которую ломает ваша задача.
| Куда идёт работа | Что поднять в первую очередь |
|---|---|
| Регрессия и классификация | Линейная алгебра, выборки, оптимизация |
| Свёртки и детекция | Окна, размеры тензоров, IoU |
| Память последовательности | Производные по времени, ворота |
| Трансформеры и языковые модели | Матрицы, softmax, энтропия, градиенты |
| Долгое обучение | Шаг, статистика пачек, устойчивость счёта |
| Сжатие и локальный запуск | Округление, масштаб осей, память |
Частые вопросы
Нужен ли полный университетский курс до первой модели?
Нет. Для прямой по одному признаку хватает функции, среднего и идеи шага против роста ошибки. Логарифм, Байес и правило цепочки подключайте в тот вечер, когда без них не читается потеря или обратный проход.
Чем алгоритм отличается от обученной сети?
Алгоритм уже содержит числа и не двигает их от ваших примеров. Обученная сеть — выбранная форма плюс числа, выставленные по ошибке на данных. Форма без подобранных чисел — ещё не сеть, которая что-то умеет на ваших объявлениях.
Почему нельзя просто перебрать все значения весов?
На двух числах цены квартиры перебор ещё мыслим. На миллионах весов сетка перебора не влезает ни во время, ни в память. Градиент заменяет перебор местным советом: в какую сторону каждое число уменьшает ошибку на этой пачке.
Зачем квадрат в ошибке, если можно взять модуль?
Квадрат сильнее тянет модель к редким огромным промахам и даёт гладкую производную в нуле. Модуль спокойнее к выбросу и менее гладок в нуле. Выбор — про то, какой промах вы считаете дорогим, а не про «более математическую» формулу.
Почему глубокая сеть иногда хуже короткой?
Глубина добавляет изломы, но и множители в обратном проходе. Лишние слои при маленькой выборке запоминают случайные странности карточек. Короткая прямая честнее, если у рыночной зависимости нет изгиба.
Что ломается в softmax, если убрать деление на корень размера?
Скалярные произведения растут с числом координат. Без деления доли прилипают к одному куску, остальные получают почти ноль, и ранние числа перестают слышать ошибку.
Доля верных ответов 0,95 — это хорошая модель?
Только если классы не перекошены и цена ошибок сопоставима. Пять больных на сто человек и постоянный ответ «здоров» дают 0,95 при нулевой пользе. Смотрите полноту по редкому классу и матрицу ошибок.
Имеет ли смысл считать градиент руками в 2026 году?
Один раз на двух слоях — да. Так появляется право не верить расхождению с autograd и понимать затухание. На полной языковой модели ручной градиент не пишут: там тот же механизм, другие размеры.
Что почитать на сайте
Рядом с этой картой уже лежат практические материалы лаборатории и сравнения каркасов.
- Фреймворки: PyTorch, TensorFlow, JAX — в чём каркас отличается от самой математики слоя.
- PyTorch и TensorFlow — как один и тот же проход обучения записан в двух каркасах.
- Картинка как тензор — пиксели, оси и размеры до свёртки.
- Лаборатория CNN и CRNN — вход в зрение и распознавание строк.
- Внимание с нуля — запрос, ключ и значение маленькими матрицами.
- Лаборатория языковой модели — с чего начинается серия, если формула внимания уже узнаваема.
- ONNX и исполнитель — что происходит с уже обученными числами вне учебного цикла.
Заключение
Математика здесь — оценка квартиры, которую можно проверить. Площадь становится числом, правило — функцией с ценой метра и надбавкой, промах в миллионах — ошибкой, совет «чуть поднять или опустить» — градиентом, а объявление из другого района — единственной честной проверкой. Классификатор, свёртка, рекурсия и внимание меняют форму правила, не этот порядок.
На этой неделе соберите три квартиры в двадцати строках, доведите вес до 0,06 и один раз прогоните обратный проход на сети из двух слоёв, сверив четыре градиента с PyTorch. Пока эти цифры не сошлись, следующая архитектура будет набором имён.



Комментарии