Та сама дошка оголошень про вживані телефони, та сама задача: за відносною ціною й віком акаунта відрізнити приманку від чесного продавця. Модель уже є — у темі про k найближчих сусідів вона впізнавала шахрайство з точністю 0.92. Але зверни увагу на слово, яке ми тоді сказали мимохідь: «девʼять сусідів». Звідки взялася девʼятка?
Її ніхто не обчислив. Її написала людина. І поки вона написана навмання, уся акуратна арифметика поверх неї стоїть на піску. Ця тема — про те, як таких чисел не вгадувати, а підбирати, і як не обдурити себе результатом підбору.
РозрізненняДва види чисел у моделі
Візьмемо найзрозумілішу модель курсу — логістичну регресію — і навчимо її на 520 оголошеннях нашого архіву. Після навчання всередині неї лежать три числа:
Ці три числа знайшов сам алгоритм. Ніхто їх не вигадував: він рухався градієнтним спуском, доки помилка на навчальних оголошеннях не перестала спадати, і зупинився саме тут. Це параметри моделі — те, заради чого навчання взагалі існує.
А тепер подивись на рядок, який запустив це навчання. Там було ще одне число —
C = 1.0. Це ручка регуляризації, з якою ми розібрались у
попередній темі, тільки повернута
навпаки: там силу штрафу задавала α, і більша
α означала сильніший штраф, а в логістичній регресії
scikit-learn просить обернену величину, C ≈ 1/α — тож менший C означає сильніший штраф.
Запамʼятай цей переворот: він коштує людям годин здивування.
Число C не знаходив ніхто: воно стояло в коді до першої
ітерації. Постав замість нього 0.01 — тобто затисни штраф у сто разів
міцніше, — запусти те саме навчання на тих самих даних, і алгоритм зупиниться в іншому
місці:
Ваги стиснулись — рівно так, як обіцяла попередня тема: −1.917 стало −0.634. Інші
ваги, інша модель, інша якість: оцінка на крос-валідації падає з 0.892
до 0.767. Число C не є параметром моделі — воно керує тим,
які параметри навчання знайде. Такі числа звуться гіперпараметрами
(hyperparameter).
Що задає людина, а що знаходить алгоритм
Одна модель, один запуск навчання. Ліворуч — те, що написано в коді заздалегідь; праворуч — те, що зʼявилось у моделі після навчання.
C зсередини. Тому
крутити цю ручку може тільки хтось ззовні — і саме цим ми зайняті всю тему.Різниця формулюється одним реченням: параметр модель знаходить із даних під
час навчання, гіперпараметр людина задає до навчання. Перевірка проста — спитай
себе, чи змінилося б це число, якби ти дав алгоритму інші дані, не змінивши жодного рядка
коду. Ваги змінилися б. C — ні.
| модель | параметри — знаходить навчання | гіперпараметри — задаєш ти |
|---|---|---|
| лінійна регресія | коефіцієнт при кожній ознаці та вільний член | чи є штраф на ваги і який (alpha) |
| логістична регресія | ті самі ваги | C, тип штрафу, метод оптимізації |
| поліноміальна регресія | коефіцієнти многочлена | степінь многочлена |
| kNN | нічого — модель це сам архів | k, вид відстані, ваги сусідів |
| наївний Баєс | частоти слів і апріорні ймовірності класів | згладжування α |
| дерево рішень | яка ознака і який поріг у кожному вузлі | максимальна глибина, мінімум обʼєктів у листі |
| нейромережа | усі ваги звʼязків | кількість шарів і нейронів, швидкість навчання |
Два рядки цієї таблиці варті окремої уваги, бо ламають зручну картинку.
kNN не має параметрів узагалі. Його «навчання» — це запамʼятати
таблицю; жодного числа алгоритм не обчислює. Уся модель складається з даних і
гіперпараметрів. Тому підбір k для kNN — це не налаштування деталі, а
вибір самої моделі.
А масштабувальник — навпаки, має параметри. У нашому конвеєрі перед
kNN стоїть StandardScaler, і він рахує з даних чотири числа: середнє й
стандартне відхилення кожної ознаки. На навчальних 520 оголошеннях вийшло 0.883 і 0.332
для відносної ціни, 178.3 і 105.7 для віку акаунта. Ці чотири числа — повноцінні
параметри: вони прийшли з даних. А от рішення взяти саме
StandardScaler, а не MinMaxScaler, — гіперпараметр.
'euclidean' проти 'manhattan'), спосіб масштабування, навіть сам
алгоритм — усе це вибір, зроблений до навчання. Формально вибір між kNN і наївним Баєсом
теж є гіперпараметром, просто дуже великим. Саме тому інструменти підбору вміють
перебирати цілі конвеєри, а не лише числа всередині них.НеможливістьЧому їх не вивчити разом із вагами
Питання, яке виникає негайно: якщо ваги ми знаходимо мінімізацією помилки, чому б не
знайти так само й k? Перебрати всі значення, порахувати помилку на навчальних
даних, узяти найменшу. Спробуймо — і подивимось, що вийде.
Ось точність нашого kNN на тих самих 520 навчальних оголошеннях, на яких він і навчався:
| k | точність на навчанні | оцінка крос-валідації | точність на 280 відкладених |
|---|---|---|---|
| 1 | 1.0000 | 0.8885 | 0.8750 |
| 3 | 0.9538 | 0.9404 | 0.9071 |
| 9 | 0.9404 | 0.9250 | 0.9214 |
| 25 | 0.9173 | 0.9058 | 0.9179 |
| 51 | 0.8942 | 0.8827 | 0.8929 |
Мінімум помилки на навчанні стоїть при k = 1, і точність там рівно
1.0000. Причина дурна: найближчий сусід навчального оголошення — воно
саме, тож помилитись ніде. Але на відкладених даних це найгірший рядок таблиці —
0.8750, гірше за всі інші k.
Це не властивість kNN. Це загальне правило, і воно варте того, щоб сформулювати його
жирним: гіперпараметр майже завжди керує складністю моделі, а помилка на навчанні
монотонно спадає зі складністю. Степінь многочлена, глибина дерева, кількість
нейронів — усе це те саме. У сусідах роль складності грає 1/k, тобто
величина, обернена до k: чим менше сусідів голосує, тим
вибагливіша межа, тож складність росте, коли k спадає. Тому оптимізація гіперпараметра по
навчальній помилці не «іноді помиляється», а завжди впирається в найскладніший
доступний варіант.
Три криві, які розходяться
Той самий kNN на дошці оголошень, k від 1 до 51. Одна крива міряє модель на даних, на яких вона вчилась, дві інші — на тих, яких вона не бачила.
Є й друга причина, суто технічна. Ваги ми підбираємо градієнтним спуском, бо помилка
від них залежить гладко: зсунув вагу на тисячну — помилка змінилась на тисячну. Від
k нічого гладко не залежить: k ціле, і між 8 і 9 немає нічого.
А гіперпараметр «вид відстані» взагалі не число. Похідну по такому не візьмеш, тож
залишається єдиний спосіб: перебрати варіанти й поміряти кожен.
ЧесністьНа чому міряти під час підбору
Отже, перебираємо й міряємо. Питання одне: міряємо на чому?
На навчальній вибірці не можна — щойно показали чому. Спокуса номер два — міряти на
тестовій: вона ж якраз відкладена, модель її не бачила. Подивись на таблицю вище ще раз:
найкраща точність на відкладених 280 оголошеннях дорівнює 0.9286 і досягається при
k = 17. Візьмімо сімнадцять?
Ні. І причина не в тому, що це «трохи негарно». Тестова вибірка існує рівно для одного: дати одне число, яке ніщо не встигло зіпсувати. Щойно ти обрав по ній хоч один гіперпараметр, вона перестала бути незалежною — інформація про неї просочилась у модель через твоє рішення. І тепер у тебе немає жодної вибірки, щоб сказати, скільки модель дає насправді. Ти витратив єдиний одноразовий вимірювач на службову задачу.
Правильний розподіл ролей ми вже розібрали в темі Train / Validation / Test: навчальна частина підбирає параметри, валідаційна — гіперпараметри, тестова один раз наприкінці називає результат. Проблема в тому, що валідаційну частину доводиться відрізати від навчальної, а даних завжди шкода.
Саме цю проблему знімає крос-валідація:
замість одного відрізаного шматка вона по черзі робить валідаційним кожен фолд і усереднює.
Кожне оголошення один раз побуває перевіркою і K−1 разів навчанням, і жоден
рядок не пропадає. Для підбору це рівно те, що треба, тому GridSearchCV у
назві має ці дві літери.
Наш підбір k виглядає так. Беремо 520 навчальних оголошень, ріжемо на
5 стратифікованих фолдів, для кожного k рахуємо середню точність по фолдах.
Перемагає k = 3 з оцінкою 0.9404 ± 0.0128. Тестові
280 оголошень при цьому не чіпались жодного разу — і коли ми нарешті їх відкрили,
обрана модель дала 0.9071.
k = 7 — 0.9385. Різниця 0.002 при розкиді по фолдах 0.013.
Ба більше: точність на 520 оголошеннях не може набувати будь-яких значень — вона
кратна 1/520 = 0.0019. Тобто 0.9404 — це рівно 489 правильних відповідей
із 520, а 0.9385 — 488. Уся «перевага» переможця дорівнює одному оголошенню.
Це не «трійка краща за сімку», це два однакові результати. Реальний висновок такий:
годиться будь-яке невелике непарне k, і вибір конкретного значення — питання
смаку, а не даних.ОптимізмПрокляття переможця
Тепер найважливіше в темі — і те, що найчастіше пропускають.
Перечитай два останні числа. Найкраща оцінка при підборі — 0.9404. Та сама модель на справді відкладених даних — 0.9071. Розрив 0.033, і він у передбачуваний бік: оцінка, за якою обирали, виявилась завищеною.
Механізм чистий і не має нічого спільного з машинним навчанням. Кожна оцінка на валідації складається з двох доданків: справжньої якості моделі й випадкового шуму конкретного розбиття. Коли ти береш максимум із багатьох таких оцінок, ти обираєш не лише найкращу модель — ти заодно обираєш найудачливіший шум. Максимум із багатьох зашумлених чисел систематично більший за максимум їхніх справжніх значень. Це називають прокляттям переможця (winner's curse).
Що означає кожен символ. j — номер кандидата в переборі (перше
значення k, друге, третє…). ŝj —
виміряна оцінка j-го кандидата на валідації; «дашок» над буквою в статистиці
завжди означає «це не справжня величина, а те, що ми зміряли». Без дашка,
sj, була б справжня якість того самого кандидата
— число, якого ми ніколи не бачимо. maxj — «візьми
найбільше по всіх кандидатах». 𝔼[…] — математичне сподівання, тобто середнє
значення того, що в дужках, якби ми повторили весь підбір нескінченно багато разів на
нових розбиттях.
Що означає нерівність словами. Зліва — те, що ти бачиш у звіті: у середньому найкраща з перебраних виміряних оцінок. Справа — найкраща зі справжніх якостей, тобто те, на що модель має право розраховувати завтра. Лівий бік систематично більший за правий, і це не випадковість окремого запуску: операції «взяти максимум» і «усереднити» не переставляються місцями. Нерівність строга завжди, коли в оцінок є хоч якийсь шум, а він є завжди.
Звідки береться завищення
Кожна пара точок — один кандидат: рожева — його оцінка на валідації, бірюзова — його справжня якість. Пошук бачить лише рожеві й бере найвищу.
Тепер — чесна перевірка на наших даних, бо один розбіг у 0.033 ще нічого не доводить.
У ньому змішані дві причини: завищення від вибору й звичайна різниця між двома вибірками.
Розділимо їх експериментом. Візьмемо дванадцять різних розбиттів дошки на навчальну й
відкладену частини, а сітку скоротимо до тринадцяти значень k. Для кожного порахуємо дві речі: наскільки оцінка завищена для
обраного за крос-валідацією k і наскільки — для
заздалегідь зафіксованого k = 9, який ніхто не обирав.
| що міряємо | середній розрив «оцінка мінус правда» |
|---|---|
| фіксоване k = 9 | −0.0071 — оцінка навіть трохи занижена |
| обране за CV | −0.0030 |
| різниця | +0.0041 — це і є ціна вибору |
Чотири тисячних. Менше, ніж лякає теорія, — і ця розбіжність сама по собі корисна.
Причина ось у чому: тринадцять перебраних значень k — це не тринадцять
незалежних кандидатів. Модель із k = 21 і модель із k = 25
майже однакові, їхні помилки на тих самих фолдах збігаються, тож і шум у них спільний.
Максимум із тринадцяти скорельованих чисел зміщений приблизно так само, як
максимум із кількох незалежних.
Ліки називаються вкладеною крос-валідацією (nested cross-validation). Ідея в тому, щоб не мати одну вибірку, яка одночасно й обирає, і оцінює. Циклів стає два.
Вкладена крос-валідація
Зовнішній цикл ділить дані й міряє. Внутрішній цикл живе всередині кожного зовнішнього фолда й тільки обирає гіперпараметри.
Прогнали це на всіх 800 оголошеннях дошки: пʼять зовнішніх фолдів, усередині кожного —
повний підбір k по пʼяти внутрішніх. Результат такий.
- Середня внутрішня оцінка переможця (те, що показав би звичайний
GridSearchCV): 0.9344. - Чесна зовнішня оцінка: 0.9275 ± 0.0085.
- Різниця 0.0069 — рівно те завищення, яке вкладеність прибирає.
І окрема деталь, помітна лише у вкладеній схемі: по пʼяти зовнішніх фолдах підбір обрав
різні k — 7, 5, 9, 19, 9. Тобто «найкраще k» не є властивістю
задачі, воно міняється від однієї вибірки до іншої. Ще один аргумент не сприймати
переможця сітки надто серйозно.
ПеребірСітка проти випадкового пошуку
Ми весь час казали «перебираємо варіанти», не уточнюючи, як саме. Способів три, і між першими двома є контрінтуїтивна різниця, заради якої й написаний цей розділ.
Сітка
Пошук по сітці (grid search) — це повний перебір: задаєш список значень для кожного гіперпараметра й пробуєш усі комбінації. Просто, відтворювано, тривіально паралелиться. Вада одна, зате арифметична: кількість комбінацій — це добуток довжин списків. Чотири гіперпараметри по шість значень дають не 24 варіанти, а 64 = 1296.
Випадковий пошук
Випадковий пошук (random search) не будує сітки взагалі. Ти задаєш діапазон для кожного гіперпараметра й кількість спроб, а кожна спроба бере випадкову точку з цих діапазонів. Звучить як капітуляція: замість акуратного перебору — кидання дротиків. Але при однаковому бюджеті він зазвичай виграє, і причина не у везінні.
Ось вона. У реальних задачах гіперпараметри не рівноцінні: із пʼяти ручок дві щось вирішують, а три майже ні. Сітка про це не знає й ділить бюджет порівну між осями. Візьми сітку 5 × 5 = 25 спроб: важливу вісь вона обмацає рівно в пʼяти точках, а решту 20 запусків витратить на повторення тих самих пʼяти значень при різних неважливих. Випадковий пошук за ті самі 25 спроб дасть 25 різних значень важливої осі — бо жодні дві його точки не збігаються по жодній координаті.
Однаковий бюджет, різне покриття
Два гіперпараметри. Горизонтальна вісь вирішує майже все, вертикальна майже нічого — фон залежить від неї так слабко, що це непомітно оком.
Перевіримо на наших даних, а не на картинці. Візьмемо повну сітку з трьох ручок kNN:
26 значень k, два способи зважувати сусідів, дві відстані — разом 104
комбінації, помножені на 5 фолдів, тобто 520 навчань. Переможець:
k = 17, ваги за відстанню, манхеттенська відстань, оцінка 0.9404, на
відкладених 0.9321.
Тепер той самий простір випадковим пошуком, 26 спроб — 130 навчань, учетверо дешевше. Він знаходить ту саму комбінацію з тим самим числом 0.9404. Уся різниця в тому, що 390 навчань не відбулися.
Байєсівська оптимізація
Третій спосіб коротко, бо повне занурення в нього — окрема тема. Замість того щоб
кидати точки навмання, можна після кожної спроби будувати сурогатну модель
залежності «гіперпараметри → якість» і обирати наступну точку там, де очікуване покращення
найбільше: частково поблизу вже знайденого доброго, частково там, де ще нічого не відомо.
Це байєсівська оптимізація, і реалізації в optuna,
scikit-optimize чи hyperopt. Вона окупається, коли одне навчання
коштує довго — години на великій нейромережі, — і не окупається, коли навчання триває
секунду: сама розумна процедура вибору точки тоді дорожча за спробу.
ЦінаСкільки моделей ти насправді навчаєш
Найчастіша неприємність підбору не інтелектуальна, а арифметична: людина запускає
GridSearchCV, іде пити каву й повертається до процесу, який доведеться
вбити. Порахуймо, щоб такого не було.
Ця формула — уся математика розділу, але множники в ній ростуть по-різному. Кількість згорток входить лінійно: перейшов з 5 на 10 — стало вдвічі довше. А кількість ручок стоїть у показнику: додав пʼяту ручку з шістьма значеннями — і робота збільшилась ушестеро.
Рахунок за перебір
Покрути три повзунки й подивись, як швидко нешкідливі числа перетворюються на дні. Одне навчання прийнято за 0.8 секунди.
Що з цим роблять на практиці:
- Дві хвилі замість однієї. Спершу груба сітка по широкому
логарифмічному діапазону —
0.001, 0.01, 0.1, 1, 10. Потім тонка сітка навколо переможця. Дві хвилі по 5 точок покривають діапазон краще, ніж одна з 25. - Відсів на половині шляху.
HalvingGridSearchCVуscikit-learnдає всім кандидатам маленьку частину даних, викидає половину найгірших, решті дає вдвічі більше даних — і так далі. Безнадійні комбінації відпадають, поки навчання ще дешеве. - Менше згорток на етапі відсіву. Три фолди для грубого пошуку й десять для фінальної перевірки — цілком законно.
n_jobs = −1. Комбінації незалежні, тому перебір масштабується по ядрах майже ідеально. Це найдешевше прискорення з усіх.
Вибір ручокЩо крутити, а що ні
Останнє й найпрактичніше. У більшості моделей десятки аргументів, але вирішують один-два. Порівняй два наші власні виміри.
kNN, гіперпараметр k: оцінка гуляє від 0.8827 при
k = 51 до 0.9404 при k = 3. Розмах 0.058 —
учетверо більший за розкид самої оцінки. Цю ручку крутити треба обовʼязково.
Логістична регресія, гіперпараметр C: 0.7673 при
C = 0.01, далі 0.8808 при C = 0.1, потім 0.8923 при
C = 1 — і при C рівному 10 чи 100 оцінка не змінюється
взагалі. Тобто змістовна частина діапазону —
це два порядки внизу, а все, що вище одиниці, — марно витрачені запуски.
Звідси процедура, яка економить більше часу, ніж будь-яка розумна бібліотека: перш ніж будувати сітку, прогони кожну ручку окремо в широкому діапазоні й подивись на розмах метрики. Ручка, у якої розмах менший за розкид крос-валідації, у сітку не потрапляє. Зазвичай після такої перевірки з десяти аргументів у сітці лишаються два.
Памʼятка: головна ручка кожної моделі
З чого починати підбір і що станеться, коли крутнеш убік.
| модель | головний гіперпараметр | що робить | у який бік крутити |
|---|---|---|---|
| kNN | n_neighbors | скільки сусідів голосує | більше — гладша межа й менше реакції на шум; менше — межа повторює кожну точку |
| поліноміальна регресія | degree | степінь многочлена | більше — гнучкіше й нестійкіше; рідко потрібно понад 3 |
| гребенева, Lasso | alpha | сила штрафу на ваги | більше — простіша модель; шукати по логарифмічній шкалі |
| логістична регресія | C | зворотна сила штрафу | більше C — слабший штраф; діапазон 0.01…10 зазвичай вичерпний |
| SVM з ядром RBF | C і gamma | жорсткість межі й радіус впливу точки | крутити тільки разом, обидва по логарифмічній сітці |
| наївний Баєс | alpha | згладжування Лапласа | більше — обережніші ймовірності; нуль ламає модель |
| дерево рішень | max_depth | скільки питань поспіль | більше — точніше на навчанні й гірше на нових даних |
| випадковий ліс | max_features | скільки ознак бачить кожен розріз | менше — дерева різноманітніші; кількість дерев просто беруть великою |
| градієнтний бустинг | learning_rate | внесок одного дерева | менший крок вимагає більше дерев; крутити пару разом |
| будь-що на градієнтному спуску | learning_rate | довжина кроку | завеликий — розліт, замалий — не встигне дійти |
scikit-learn обрані непогано: вони
рідко бувають найкращими, але майже ніколи не бувають катастрофічними.alpha,
C, gamma і швидкості навчання значуща не різниця, а
відношення: між 0.001 і 0.01 різниця така сама за змістом, як між 1 і 10.
Рівномірна сітка від 0 до 10 з кроком 0.5 повністю пропустить цікаву зону й перевірить
двадцять разів те саме. Тому в RandomizedSearchCV для таких ручок беруть
loguniform, а в сітці пишуть [0.001, 0.01, 0.1, 1, 10].ПідсумокЩо варто винести
Блок про якість моделі закінчується там, де почався. Ми навчилися міряти, навчилися не довіряти одному вимірюванню — і тепер бачимо, що сам процес пошуку найкращої моделі створює нову, тоншу форму самообману. Кожен рівень чесності відкриває наступний рівень нечесності поверхом вище.
| ідея | суть | чому важливо |
|---|---|---|
| параметр | навчання знаходить із даних | ваги, пороги, частоти |
| гіперпараметр | людина задає до навчання | керує тим, які параметри вийдуть |
| не по навчанню | помилка на навчанні спадає зі складністю | такий підбір завжди обере найскладніше |
| не по тесту | вибір робить тест залежним | лишаєшся без жодного чесного числа |
| крос-валідація | підбір на фолдах навчальної частини | дані не витрачаються на валідацію |
| прокляття переможця | максимум зашумлених оцінок завищений | «найкраща CV» — не прогноз якості |
| вкладена CV | вибір і оцінка на різних даних | єдиний спосіб чесно порівняти алгоритми |
| випадковий пошук | той самий бюджет, більше значень важливої осі | сітка марнує спроби на неважливі ручки |
| бюджет | комбінації в показнику, згортки — множником | рахувати до запуску, а не після |
І головна думка теми, якщо лишити одну. Найкраща оцінка, отримана під час підбору, — це не очікувана якість моделі. Це найкраще з того, що показав шум на твоїй валідації. Очікувану якість дає лише вимірювання, у якому підбір не брав участі: окремий тест, відкритий один раз, або зовнішній цикл вкладеної крос-валідації.
Далі починається блок про дерева й ансамблі, і там усе сказане знадобиться одразу. У дерева рішень ручок помітно більше, ніж у kNN: глибина, мінімальний розмір листа, критерій розрізу, обмеження на кількість листків. У випадкового лісу й градієнтного бустингу їх більше десятка, вони взаємодіють між собою, а одне навчання коштує вже не мілісекунди. Саме там сітка з розділу 6 перетворюється на добу очікування, а вміння відрізнити дві важливі ручки від восьми байдужих стає не теорією, а щоденною роботою.