У модели времени доставки четыре параметра: три веса при признаках и постоянная часть. Сдвигать надо все четыре — значит, и наклон нужен по каждому отдельно. Такой набор наклонов называют градиентом.
Считается он по одной и той же формуле:
удвоенный промах × значение признака при этом весе
Промах — это ŷ − y, разница между прогнозом и фактом.
Каждый вес стоит при своём признаке: w₁ при x₁, w₂ при x₂ и так далее. У свободного члена b своего признака нет, поэтому за него берут единицу — так одна формула покрывает и веса, и смещение. Отсюда производная по b — это просто 2 × промах.
Формулу легко вывести с ошибкой: забыть двойку, перепутать знак, взять не тот признак. И самое неприятное — ошибка не проявится сразу. Программа запустится, loss даже может падать, но веса будут двигаться не туда, и обучение пойдёт вкось.
Поэтому градиент, посчитанный по формуле, всегда сверяют с численным — тем самым «горячо-холодно» из прошлого задания. Численный считается принципиально иначе: он «щупает» функцию в двух точках и не знает формулы производной. Если два значения расходятся — значит, в формуле ошибка.
Этот приём применяют всякий раз, когда пишут новый слой или новую функцию потерь. Сейчас вы реализуете его целиком.
Подробно это разобрано в учебнике: Все веса сразу.
Задание
База выполненных заказов. Три первых числа в строке — признаки заказа: километры, светофоры, свободные курьеры рядом. Четвёртое — сколько заказ ехал на самом деле, в минутах. Это и есть то, что модель учится предсказывать.
База вписана в тест, объявлять её в решении не нужно.
baza = [(4.0, 2, 6, 20.0), (2.0, 5, 4, 19.5), (6.0, 1, 2, 26.5), (1.5, 3, 8, 13.0),
(5.0, 0, 5, 20.5), (3.0, 4, 1, 22.5), (7.5, 2, 3, 32.0), (2.5, 6, 7, 21.0)]
Модель: время = p[0]·км + p[1]·светофоры + p[2]·курьеры + p[3].
Последний параметр p[3] — постоянная часть времени, одинаковая для всех заказов: сборка и передача курьеру. Признака при нём нет, поэтому в производной на его месте стоит единица.
Напишите две функции.
def loss4(baza, p): # MSE модели, p — список из четырёх чисел
...
def grad4(baza, p): # список из четырёх производных
...
Не забудьте поделить и ошибку, и каждую производную на число заказов.
Как проверить себя
Времена в базе посчитаны по правилу с весами 3, 1.5, −0.5 и 8, поэтому loss4(baza, [3, 1.5, -0.5, 8]) обязана дать ноль.
Дальше сверьте сами: для каждого из четырёх параметров сдвиньте только его на h = 1e-5 в обе стороны и посчитайте центральную разность через loss4. Она должна совпасть с grad4 — расхождение выйдет порядка 1e-9, это машинная погрешность. Потом уберите из формулы множитель 2 и посмотрите, насколько разойдутся числа.
Числа сравниваются с допуском, а не как строки: достаточно совпадения в первых четырёх знаках. Печатать ничего не надо — функция возвращает значение.