Градієнтний спуск — механічна процедура: порахуй похідну, зроби крок проти неї, повтори. Домашнє завдання про те, щоб ця механіка перестала бути чорною скринькою: побачити на своїх числах, як поводиться спуск, коли крок замалий, завеликий і саме такий.
рівень 1Рівень 1 — База
Повтори спуск на інших даних і подивись, як він реагує на швидкість навчання.
- Візьми
sklearn.datasets.load_diabetes()— він іде разом зіscikit-learnі нічого не тягне з мережі. Обери одну числову ознаку (наприклад,bmi) і цільy. - Напиши функцію втрати
L(w, b)— середній квадрат помилки — і функціюградієнт(w, b), що повертає обидві похідні за формулами з лекції. - Перевір градієнт чисельно: зсунь
wна1e-6, порахуй(L(w+h) − L(w)) / hі порівняй із формулою. - Запусти спуск із
w = 0, b = 0на 500 ітерацій для трьох швидкостей: замалої, робочої та завеликої. Збери історію втрати й намалюй три криві на одному графіку з логарифмічною віссю.
Зроблено, якщо: проходить assert np.allclose(чисельна_похідна, аналітична, atol=1e-3),
а на графіку видно три різні поведінки. Назви для кожної кривої, який це режим
(повзе / збігається / розлітається), і підтверди це числом — кінцевою втратою.
рівень 2Рівень 2 — Плюс
Знайди межу збіжності експериментом і звір її з теорією.
- Для своїх даних порахуй матрицю других похідних функції втрат:
H = 2 * [[mean(x²), mean(x)], [mean(x), 1]]. Візьми її найбільше власне число (np.linalg.eigvalsh) і обчисли теоретичну межу2 / λmax. - Проженеш спуск для 40 значень швидкості на логарифмічній сітці навколо цієї
межі (наприклад, від
0.1 · межадо3 · межа). Для кожного значення запиши, чи втрата після 200 ітерацій скінченна й менша за стартову. - Побудуй графік: по горизонталі швидкість навчання, по вертикалі кінцева втрата в логарифмічній шкалі. Познач вертикальною лінією теоретичну межу.
- Окремо знайди швидкість, за якої спуск доходить до мінімуму за найменшу кількість ітерацій (критерій: втрата відрізняється від мінімальної менш ніж на 0.1 %).
Зроблено, якщо: експериментальна межа збігається з теоретичною 2 / λmax
із точністю до кроку сітки, і ти назвав швидкість-переможницю. Поясни одним
реченням, чому найшвидша швидкість не та, що стоїть впритул до межі.
рівень 3Рівень 3 — Виклик
Порівняй три оптимізатори на одній задачі: звичайний спуск, спуск із моментом і спуск із партіями.
- Візьми датасет із щонайменше трьома ознаками (наприклад, ті самі
load_diabetesабоfetch_california_housing). Обовʼязково стандартизуй ознаки, інакше порівняння буде про масштаби, а не про методи. - Реалізуй три функції з однаковим інтерфейсом, кожна повертає історію втрати:
спуск(швидкість, ітерацій)— повний градієнт;спуск_з_моментом(швидкість, ітерацій, бета)— накопичена швидкістьv ← бета·v + градієнт, крокпараметри ← параметри − швидкість·v;спуск_партіями(швидкість, епох, розмір_партії).- Виміряй усіх трьох за однаковим обчислювальним бюджетом: не за кількістю
кроків, а за кількістю переглядів прикладів (
кроків × розмір_партії). - Намалюй три криві втрати на спільній осі «переглядів прикладів».
- Для моменту побудуй окремий графік: кінцева втрата залежно від
бетана сітці0, 0.5, 0.8, 0.9, 0.95, 0.99.
Зроблено, якщо: усі три знайдені набори коефіцієнтів збігаються з
LinearRegression із точністю 1e-3 (перевір assert-ом, давши кожному
методу достатній бюджет), а на графіку за однакового бюджету видно порядок
переможців. Назви, при якому бета момент починає шкодити замість допомагати,
і поясни, що саме там ламається.
Підказки
- Рівень 1. Якщо всі три швидкості поводяться однаково, вони надто близькі
одна до одної. Бери їх у різних порядках величини:
1e-5,1e-2,1e0— і дивись, у якому діапазоні взагалі щось відбувається. - Рівень 2. Спуск, що розлетівся, дає
infабоnan, іmatplotlibтаких точок не намалює. Заміни їх на щось скінченне (наприклад, максимум серед нормальних значень), інакше половина графіка просто зникне. - Рівень 3. Момент із великим
бетаповодиться як важкий шар: він розганяється й перелітає мінімум. Порівнюй не тільки кінцеву втрату, а й форму траєкторії — для двох параметрів її можна намалювати прямо на площині(w, b). - Скрізь, де є
inf, зупиняй цикл достроково:if not np.isfinite(втрата): break. Так у виводі не зʼявиться купа попереджень про переповнення.