- Различать обучение с учителем, без учителя и с подкреплением, объяснять понятия признаков и меток
- Вычислять потери MSE и перекрёстной энтропии вручную и в NumPy
- Обучать линейную регрессию градиентным спуском и объяснять влияние скорости обучения
- Распознавать переобучение и недообучение по потерям на обучающей и валидационной выборках
Представь, что нужно написать программу, которая предсказывает цену квартиры в Баку по площади, числу комнат и району. Записать все правила вручную невозможно: условиям вроде «если район Насими и площадь больше 80 м²...» нет конца. Машинное обучение предлагает другой путь: мы даём компьютеру тысячи примеров проданных квартир, а он сам извлекает правило из данных. Этот урок — математический фундамент всего модуля: на нём держатся нейронные сети, CNN и трансформеры.
Говорят, что программа обучается, если её результат в некоторой задаче, измеренный выбранной метрикой, улучшается с опытом, то есть с данными. Модель — это функция с параметрами, а обучение — подбор этих параметров по данным.
Виды обучения, признаки и метки
Каждый пример описывается вектором признаков x: для квартиры это площадь, число комнат, этаж. Величина, которую мы хотим предсказать, — метка y (целевая переменная): цена. При n примерах и d признаках данные хранятся как матрица X размера n × d и вектор y длины n. Если метка — число, задача называется регрессией, если класс (спам / не спам) — классификацией.
| Вид | Данные | Цель | Пример |
|---|---|---|---|
| Обучение с учителем | пары (x, y) | предсказать y для нового x | цена квартиры, спам-фильтр, поиск болезни на рентгеновском снимке |
| Обучение без учителя | только x, меток нет | найти структуру в данных | разбиение клиентов на группы (кластеризация), понижение размерности |
| Обучение с подкреплением | взаимодействие со средой и награды | максимизировать суммарную награду | агент, играющий в игры, робот, который учится ходить |
Разбиение данных: обучающая, валидационная и тестовая выборки
Настоящая проверка модели — данные, которых она не видела. Поэтому данные случайно перемешивают и делят на три части (типичное соотношение 70/15/15 или 80/10/10):
- Обучающая выборка — только на ней подбираются параметры.
- Валидационная выборка — для выбора гиперпараметров (скорость обучения, размер модели) и момента остановки обучения.
- Тестовая выборка — один раз, в самом конце: несмещённая оценка качества модели в реальном мире.
import numpy as np
rng = np.random.default_rng(42)
idx = rng.permutation(10)
train, val, test = idx[:6], idx[6:8], idx[8:]
print('train:', train)
print('val: ', val)
print('test: ', test)▸ Ожидаемый результат
train: [5 6 0 7 3 2] val: [4 9] test: [1 8]
Функции потерь
Нужно одно число, которое показывает, насколько ошибается модель, — его даёт функция потерь L. Обучение — это поиск параметров, минимизирующих потери. В регрессии обычно используют среднеквадратичную ошибку, в классификации — перекрёстную энтропию.
- nчисло примеров
- yᵢистинное значение (метка) i-го примера
- ŷᵢпредсказание модели
Среднеквадратичная ошибка (mean squared error). Возведение в квадрат сильнее наказывает большие ошибки; единица измерения — квадрат единицы метки.
- Kчисло классов
- yₖ1, если класс k правильный, иначе 0 (one-hot)
- pₖвероятность, которую модель даёт классу k
- pₜвероятность правильного класса
Перекрёстная энтропия (cross-entropy). Для двух классов: BCE = −[y · ln p + (1 − y) · ln(1 − p)]. Когда вероятность правильного класса стремится к 1, потери стремятся к 0.
а) Истинные значения y = (3; 5; 2,5), предсказания ŷ = (2,5; 5; 3,5). Найди MSE.
б) Классификатор изображений выдал вероятности p = (0,7; 0,2; 0,1) для классов «кошка, собака, птица». Найди перекрёстную энтропию, если на снимке кошка и если птица.
Показать решениеСкрыть решение
MSE = 1,25 / 3 ≈ 0,4167.
б) Кошка: CE = −ln 0,7 ≈ 0,357 — модель была уверена и права, потери малы.
Птица: CE = −ln 0,1 ≈ 2,303 — правильному классу досталось всего 10 %, потери больше чем в 6 раз.
import numpy as np
y = np.array([3.0, 5.0, 2.5])
y_hat = np.array([2.5, 5.0, 3.5])
mse = np.mean((y - y_hat) ** 2)
print(f'MSE = {mse:.4f}')
p = np.array([0.7, 0.2, 0.1])
print(f'CE (true class 0) = {-np.log(p[0]):.4f}')
print(f'CE (true class 2) = {-np.log(p[2]):.4f}')▸ Ожидаемый результат
MSE = 0.4167 CE (true class 0) = 0.3567 CE (true class 2) = 2.3026
Градиентный спуск и скорость обучения
Представь, что спускаешься с горы в тумане: вдаль ничего не видно, но ногами чувствуешь уклон. Делаешь маленький шаг в направлении самого крутого спуска и повторяешь. Градиент ∇L указывает направление быстрейшего роста потерь, значит, двигаться нужно против него. Длину шага задаёт скорость обучения η.
- θвсе параметры модели (веса и смещения)
- ηскорость обучения, обычно 0,0001–0,1
- ∇L(θ)градиент — вектор частных производных потерь по каждому параметру
Правило обновления градиентного спуска. Каждое повторение — один шаг; один полный проход по обучающей выборке называется эпохой.
В линейной регрессии ŷᵢ = w · xᵢ + b, а L = MSE. По цепному правилу производная (ŷᵢ − yᵢ)² по w равна 2(ŷᵢ − yᵢ) · xᵢ, а по b — 2(ŷᵢ − yᵢ). Усредняя по всем примерам, получаем:
- w, bугловой коэффициент (вес) и свободный член (смещение) прямой
- ŷᵢ − yᵢошибка на i-м примере
Модель ŷ = w · x, единственный пример (x = 2, y = 6), начальное w = 1, L = (ŷ − y)². Сделай один шаг при η = 0,1 и при η = 0,3 и найди новые потери.
Показать решениеСкрыть решение
dL/dw = 2(ŷ − y) · x = 2 · (−4) · 2 = −16.
η = 0,1: w = 1 − 0,1 · (−16) = 2,6; ŷ = 5,2; L = 0,64 — потери уменьшились в 25 раз.
η = 0,3: w = 1 + 4,8 = 5,8; ŷ = 11,6; L = 31,36 — мы перепрыгнули минимум (w = 3), и потери выросли!
Здесь L(w) = 4(w − 3)², вторая производная равна 8; для квадратичных потерь спуск сходится только при η < 2/8 = 0,25.
Теперь применим ту же идею к 50 синтетическим точкам. Данные получены из прямой y = 3x + 4 с добавлением шума; модель должна найти w и b, начиная с нуля и ничего не зная заранее. Запусти код — график потерь появится автоматически.
import numpy as np
import matplotlib.pyplot as plt
rng = np.random.default_rng(42)
x = rng.uniform(0, 5, size=50)
y = 3 * x + 4 + rng.normal(0, 1, size=50)
w, b, lr = 0.0, 0.0, 0.05
losses = []
for epoch in range(500):
error = (w * x + b) - y
losses.append(np.mean(error ** 2))
dw = 2 * np.mean(error * x)
db = 2 * np.mean(error)
w -= lr * dw
b -= lr * db
if epoch % 100 == 0:
print(f'epoch {epoch:3d} loss {losses[-1]:.4f}')
print(f'w = {w:.3f}, b = {b:.3f}')
plt.plot(losses)
plt.yscale('log')
plt.xlabel('epoch')
plt.ylabel('MSE loss')
plt.show()▸ Ожидаемый результат
epoch 0 loss 158.9249 epoch 100 loss 0.6019 epoch 200 loss 0.5740 epoch 300 loss 0.5735 epoch 400 loss 0.5735 w = 3.024, b = 3.769
На практике градиент на каждом шаге считают не по всем данным, а по небольшому мини-батчу (пакету) размера B (например, B = 32). Это стохастический градиентный спуск (SGD): шаги более шумные, но гораздо дешевле, а шум иногда даже помогает выбраться из плохих локальных минимумов.
Переобучение, недообучение и компромисс смещения и дисперсии
Слишком простая модель не может уловить закономерность в данных — это недообучение (underfitting). Слишком сложная модель вместе с закономерностью запоминает и случайный шум: на обучающей выборке ошибка почти нулевая, а на новых данных большая — это переобучение (overfitting). В коде ниже к 15 зашумлённым точкам функции sin(2πx) подгоняются многочлены разных степеней:
import numpy as np
from numpy.polynomial import Polynomial
rng = np.random.default_rng(1)
x_train = np.sort(rng.uniform(0, 1, 15))
x_val = np.sort(rng.uniform(0, 1, 15))
f = lambda x: np.sin(2 * np.pi * x)
y_train = f(x_train) + rng.normal(0, 0.2, 15)
y_val = f(x_val) + rng.normal(0, 0.2, 15)
for deg in [1, 3, 9, 12]:
model = Polynomial.fit(x_train, y_train, deg)
train_mse = np.mean((model(x_train) - y_train) ** 2)
val_mse = np.mean((model(x_val) - y_val) ** 2)
print(f'degree {deg:2d}: train {train_mse:.3f}, validation {val_mse:.3f}')▸ Ожидаемый результат
degree 1: train 0.264, validation 0.235 degree 3: train 0.032, validation 0.037 degree 9: train 0.008, validation 1.894 degree 12: train 0.005, validation 67.532
- f̂(x)предсказание модели, обученной на случайной обучающей выборке
- Biasсмещение: средняя ошибка из-за слишком простых предположений модели
- Varдисперсия: насколько предсказание зависит от конкретной обучающей выборки
- σ²неустранимый шум в данных
Разложение MSE на смещение и дисперсию. С ростом сложности модели смещение падает, а дисперсия растёт; лучшая модель минимизирует сумму.
| Потери на обучении | Потери на валидации | Диагноз | Что делать |
|---|---|---|---|
| высокие | высокие | недообучение (большое смещение) | модель побольше, новые признаки, дольше обучать |
| низкие | намного выше | переобучение (большая дисперсия) | больше данных, регуляризация, ранняя остановка, модель попроще |
| низкие | близки к ним | хорошая модель | один раз проверить на тестовой выборке |
- λсила регуляризации (гиперпараметр, подбирается на валидации)
- ∑ⱼ θⱼ²сумма квадратов весов — штрафует большие веса
L2-регуляризация (weight decay): модель предпочитает более «гладкие» функции и меньше склонна запоминать шум.
Главное
- Обучение с учителем учится на парах (x, y): регрессия, если метка — число, классификация, если класс.
- Обучающая выборка — для параметров, валидационная — для гиперпараметров; на тестовую смотрят только в самом конце.
- В регрессии используют MSE = (1/n)∑(y − ŷ)², в классификации — перекрёстную энтропию CE = −ln pₜ.
- Градиентный спуск: θ ← θ − η · ∇L; при слишком большой η потери растут, при слишком маленькой обучение ползёт.
- Низкие потери на обучении и высокие на валидации — переобучение; обе высокие — недообучение.
Проверь себя
Вопросов: 10. Каждый правильный ответ приносит XP.