С код в Python

Въведение

Като цяло един от първите предмети на курса по Машинно обучение е Линейна регресия, която не е много сложна и лесна за разбиране. Освен това включва много понятия за машинно обучение, които могат да се използват по-късно в по-сложни концепции. Така че е разумно да започнем с линейна регресия към нова поредица от основи на машинното обучение.

В тази публикация в блога ще научим за едномерната линейна регресия, което означава линейна регресия само с една променлива. В края на тази статия ще разберем фундаменталните концепции на машинното обучение като хипотеза, функция на разходите и градиентно спускане. В допълнение, ние ще напишем необходимия код за тези функции и ще обучим/тестваме линеен модел за набор от данни на Kaggle, използвайки Python[1].

Преди да се потопим в едномерната линейна регресия, нека поговорим накратко за някои основни концепции:

Основни понятия

Машинно обучение е подполето на изкуствения интелект, което използва данни за програмиране на компютри за някои задачи. Типично приложение за машинно обучение използва набор от данни и алгоритъм за обучение, за да направи модел, който предвижда изходните данни за нови входове към приложението.

Приложенията за машинно обучение обикновено се разделят на три категории:

  • Контролирано обучение
  • Учене без надзор
  • Обучение с подсилване

При контролирано обучение [2] данните имат идентични характеристики, които могат да бъдат съпоставени с някакъв етикет. Обучението под наблюдение има два вида.

Нарича се класификацияако броят на етикетите е ограничен и може да се трансформира в някои категории. Идентифициране на животни или ръкописни цифри в изображения са примери за класификация.

Ако наборът от етикети не е ограничен до някакъв малък брой елементи, но може да се приеме, че са безкрайно много, тогава това се нарича регресия. Прогнозирането на цената на къщите в даден регион или потреблението на газ на километър коли са примери за регресия.

При обучение без надзор [3] наборът от данни няма етикетирани данни. След процеса на обучение моделът открива моделите в данните. Категоризирането на клиентите на уебсайт за електронна търговия е пример за обучение без надзор.

Обучението с подсилване [4] използва интелигентни агенти, които действат според механизми за възнаграждение и наказание [5]. Използва се главно в компютърните игри.

Линейна регресия

Както казахме по-горе, регресията картографира входовете към безкрайно много изходи. В допълнение, линейната регресия предполага линейна връзка между входовете и резултатите [6]; предизвикателство е да визуализираме това, ако имаме повече от една входна променлива. Ако имаме една входна променлива, трябва да начертаем линия в равнината XY; ако имаме две входни променливи, трябва да конструираме равнина в триизмерната координатна система. Повече от две входни променливи е изключително трудно да си представим. В резултат на това ще демонстрираме линейна регресия, използвайки едномерни данни. По-долу са цените на жилищата от Портланд, Орегон набор от данни [7], които ще използваме като пример.

В графиката по-горе оста y е цената (K$) на някои къщи в Портланд, а оста x е размерът на къщата (футове²). Искаме да начертаем права линия на тази графика (като изображението по-долу), така че когато знаем размера на нов дом, който не е в този набор от данни, да можем да предвидим цената му, като използваме тази линия.

Например, можем да предвидим, че цената на къща от 3000 фута² е приблизително 500 K$, както се вижда на графиката по-долу.

Така че без повече шум, нека се потопим в по-задълбочени концепции, за да разберем как да начертаем тази линия.

Обърнете внимание, че тази статия използва набора от данни за Линейна регресия [1] и тетрадка Едномерна линейна регресия от нулата [8] от Kaggle. Както е описано в частта със съдържанието на набора от данни, той има обучителен набор от 700 и тестов набор от 300 елемента. Данните се състоят от двойки (x,y), където x са числа между 0 и 100, а y са генерирани с помощта на функцията на Excel NORMINV(RAND(), x, 3). Дадено е също, че най-добрата оценка за y трябва да бъде x.

Първо, трябва да напишем три функции, за да намерим решение с едномерна линейна регресия върху набор от данни. Тези функции са за изчисления на хипотеза, цена и градиентно спускане по ред. Преди всичко ще ги обясним един по един.

Хипотезата

Ние се стремим да намерим модел, който можем да използваме, за да предвидим нови входове. „Хипотезата“ е потенциален модел за система за машинно обучение [9].

Както се вижда на фигурата по-долу, можем да намерим хипотезата за набор от данни, като използваме алгоритъм за обучение [10]. По-късно ще говорим за това колко добре тази хипотеза отговаря на нашите данни, но засега нека просто дефинираме формулата на хипотезата.

За задача за едномерна линейна регресия хипотезата е във формата:

Пресечната точка на оста y с хипотетичната линия се нарича отсечка. Това е θ₀ в нашата формула, а наклонът на линията на хипотезата е θ₁.

Ако знаем стойностите на x, θ₀ и θ₁, можем да предвидим целевата стойност за система за машинно обучение. Например в горния пример за цените на жилищата θ₀ = 0,00008 и θ₁ = 0,16538 за червената линия. Така че за къща от 3000 фута² (x=3000), очакваната цена е:

Както може да се види, имаме нужда от три параметъра, за да напишем функцията на хипотезата. Това са x (вход), θ₀ и θ₁. И така, нека напишем функцията на Python за хипотезата:

Процесът е доста лесен. Просто трябва да върнем (θ₀+θ₁* x).

Функцията на разходите

Когато имаме хипотеза (т.е. знаем стойностите на θ₀ и θ₁), трябва да решим колко добре тази хипотеза отговаря на нашите данни. Връщайки се към примера с цените на жилищата, нека приемем θ₀ като 500 и θ₁ като -0,1 и да начертаем чертата върху нашите данни.

Както се вижда от изображението по-горе, хипотеза с θ₀ = 500 и θ₁ = -0,1 не е подходяща за нашия набор от данни. Ние не искаме подобна хипотеза да бъде наш модел, тъй като дава погрешни резултати, с изключение на няколко точки. Нека начертаем още няколко линии, за да разберем по-добре.

Имаме три хипотези в горното изображение с различни θ стойности. По интуиция можем лесно да изберем синята линия (θ₀ = 0, θ₁ = 0,165) като най-добро съответствие за нашите данни. Въпросът е как можем да изберем по-добро съответствие математически? С други думи, как можем да изберем най-добрите стойности на θ₀ и θ₁, които дават оптималното решение за целта ни да намерим модел, който можем да използваме за прогнозиране на нови входове?

За да направим това, можем да изберем θ₀ и θ₁ така, че h(x) да е близо до действителната стойност за всички примери за обучение [10]. Правим грешки за всяка точка от набора от данни за конкретна хипотеза (с известни стойности на θ₀ и θ₁). Ако по някакъв начин добавим всички тези грешки, които направихме за всяка точка от данни в този набор от данни, можем да изберем най-подходящата линия, като изберем минималната сума (което означава, че правим по-малко грешки).

Така че дефинираме функция на разходите, за да измерим общата грешка, която правим. Има няколко решения, които можем да изберем. Едната се нарича функция на квадратна грешка:

j(θ₀, θ₁) се нарича функция на разходите. Това е функция на θ₀ и θ₁, които са пресечната точка и наклонът на хипотезата. h(xᵢ) — y(xᵢ) е грешката, която направихме за i-тия пример за обучение. И като го повдигнем на квадрат, получаваме две значителни ползи; първо, наказваме големите грешки и второ, премахваме отрицателния знак, ако h(x) ‹ y. Като разделим общата сума на грешките на броя на пробите, намираме средната грешка, която сме направили. Както е описано по-горе, по-малките стойности на функцията на разходите предполагат по-добро съвпадение, така че ние се опитваме да минимизираме функцията на разходите за по-добро съответствие.

За да напишем функцията за разходите, трябва да импортираме NumPy, известна библиотека за машинно обучение, използвана за задачи по линейна алгебра. NumPy ще ускори нашите изчисления. Нуждаем се също от четири параметъра и това са θ₀, θ₁, X (вход) и y (действителен изход).

Във функцията първото нещо, което трябва да направите, е да изчислите грешките за всяка точка от данни, като използвате функцията за изваждане на NumPy. След това можем да изчислим квадратните грешки за всяка точка от данни, като използваме квадратната функция на NumPy. И накрая, можем да изчислим общата квадратна грешка с помощта на sum() и да я разделим на броя на примерите, за да получим средната грешка. Имайте предвид, че всички данни за обучение се предават на функцията като масив NumPy. Освен това, тъй като използваме функцията на хипотезата вътре във функцията на разходите, трябва да я напишем преди това. Не забравяйте също, че все още не се опитваме да минимизираме функцията на разходите. Ще видим как да го направим по-късно в темата Gradient Descent.

Градиентно спускане

Сега можем да изчислим функцията на разходите за даден набор от θ₀ и θ₁ върху набор от данни. Знаем също, че стойностите θ₀ и θ₁, които правят функцията на разходите минимална, са най-добрите съвпадения с нашите данни. Следващият въпрос е как да намерим тези стойности θ₀ и θ₁, които правят функцията на разходите минимална.

Алгоритъмът за градиентно спускане може да се използва за тази цел и можем да използваме аналогията с катерача, за да обясним по-добре градиентното спускане. Да предположим, че има алпинист на върха на планината. Той иска да слезе на хълма възможно най-скоро. И така, той наблюдава заобикалящата го среда и намира най-стръмната пътека към земята, като прави една малка крачка в тази посока. След това отново наблюдава заобикалящата го среда, за да види новата, най-вертикална посока за движение. Той продължава да повтаря тази процедура, докато стигне до хълма.

Обяснението е отвъд тази публикация в блога, но знаем, че функцията на стойността на квадратната грешка има един глобален минимум без локални минимуми. Освен това неговият отрицателен градиент в дадена точка е най-стръмната посока към този глобален минимум. И така, както катерач на върха на планина намира пътя си към склона, можем да използваме градиентно спускане, за да намерим θ стойностите, които минимизират нашата функция на разходите.

За да направим това, първо трябва да изберем някои начални θ₀ и θ₁, с които да започнем. След това можем да изчислим спускането на градиента в тази точка и да променим стойностите на θ₀ и θ₁ пропорционално на изчисления отрицателен градиент. След това повторете същите стъпки до сближаване.

За да разберем по-добре концепцията за градиент, ще използваме функция на стойността на произволна квадратна грешка с θ₀ = 0, както е показано по-долу. Избираме θ₀ като нула; в противен случай щяхме да се борим с 3D графика, вместо да се занимаваме с 2D.

Да предположим, че на изображението по-горе сме в точка = 6 (тоест сме избрали първоначалното си θ₁ като 6) и се опитваме да достигнем глобалния минимум. Отрицателният градиент в тази точка е надолу, както е показано със стрелката. Така че, ако отидем още една стъпка в тази посока, ще завършим с точка, по-малка от 6. Тогава, както е показано по-долу, можем да повторим същата процедура до сближаване в точка = 2.

Нека опитаме друга точка, както е показано по-долу. Ако сме избрали друга стойност на θ₁, като точка = -2, отрицателният градиент в тази точка ще бъде надолу, както е показано със стрелката. Така че, ако отидем една крачка напред в тази посока, ще завършим със стойност, по-голяма от -2.

След това, както е показано по-долу, можем да повторим същата процедура до конвергенция в точка = 2.

Един добър въпрос, който трябва да зададете, е как да решим кога сме се сближили. Тоест какво е нашето условие за спиране в кода? Имаме два избора. Можем или да проверим стойността на функцията на разходите и да спрем, ако е по-малка или равна на предварително зададена стойност, или можем да проверим разликата между последователните стойности на функцията на разходите и да спрем, ако е по-малка или равна на прагова стойност. Ще изберем последното, тъй като поради първоначалния избор на стойности на θ никога не можем да достигнем предварително зададената стойност на разходите, която сме избрали.

Вземането на градиентно спускане на функция е концепция за смятане на ниво първокурсник и ние няма да навлизаме в подробности; вместо това ще дадем само резултатите. Градиентът на квадратната функция на цената на грешката за едномерен набор от данни е както следва:

Преди да напишем кода за градиентното спускане, трябва да въведем една последна концепция: скоростта на обучение. Както обсъдихме по-горе, алгоритъмът за градиентно спускане изисква малки стъпки и както е показано по-долу, може да рискуваме да превишим локалния минимум, ако стъпките са твърде големи. Така че, докато изчисляваме новите стойности на θ, ние умножаваме резултата от градиента с коефициента на скоростта на обучение. Скоростта на обучение е хиперпараметър, който трябва да се коригира по време на обучението. Докато по-високата стойност на скоростта на обучение може да доведе до превишаване, по-ниската стойност на скоростта на обучение може да доведе до по-дълго време за обучение [10].

В резултат на това за едномерен набор от данни с хипотеза от формата h(x) = θ₀ +θ₁* x и квадратна функция на стойността на грешката J(θ₀, θ₁),θ стойностите за всяка стъпка могат да бъдат изчислени, както следва:

Както беше обсъдено, α е скоростта на обучение, а m е броят на примерите за обучение.

Трябва да импортираме NumPy, както във функцията за разходи, за да напишем функцията за градиентно спускане.Също така имаме нужда от пет параметъра и това са θ₀, θ₁, α (скорост на обучение), X (вход) и y (действителен изход). Също така трябва да сме сигурни, че не актуализираме θ₀, преди да изчислим θ₁ [10]. В противен случай ще получим грешен резултат. Кодът за градиентната функция е както следва:

Във функцията първото нещо, което трябва да направите, е да изчислите грешките за всяка точка от данни, като използвате функцията за изваждане на NumPy и да я съхраните в променлива. След това можем да умножим предишния резултат с x и да го съхраним в друга променлива. Имайте предвид, че всички данни за обучение се предават на функцията като масив NumPy. Така че тези променливи са от тип масив и функцията sum() може да се използва за получаване на общите стойности, които след това могат да бъдат умножени по скоростта на обучение и разделени на броя на примерите. Като последна стъпка можем да изчислим и върнем новите θ стойности.

Модел обучение

Тъй като сме написали всички функции, от които се нуждаем, е време да обучим модела. Както беше обсъдено преди, трябва да решим кога градиентното спускане се събира. За да направим това, ще извадим последователните стойности на разходите. Ако разликата е по-малка от определен праг, ще заключим, че градиентното спускане се сближава.

Ние също така чертаем хипотезата за всяка итерация, за да видим как се променя. Но това забавя кода. Изборът на начални стойности може значително да промени броя на итерациите, така че може да е подходящо да промените тази част от кода за тези, които го възпроизвеждат. Възможно е също така да копирате бележника Унивариантна линейна регресия от нулата за тази цел, в който раздел чертае модела, обучен само поради големия брой итерации.

Вътре в кодовия блок ние инициализираме α, θ₀, θ₁ и стойностите на прага на конвергенция. Ние също изчисляваме стойността на първоначалните разходи, като извикваме функцията на разходите.

Както беше обсъдено по-рано, нашето условие за спиране за цикъла while е разликата на последователните стойности на функцията на разходите да бъде по-малка от прагова стойност. Първо изчертаваме данните за обучение и хипотезата за демонстрационни цели за всяка итерация на цикъла while. След това изчисляваме стойността на функцията на разходите, като извикваме функцията на разходите. След това изчисляваме новите стойности на θ₀ и θ₁ чрез извикване на градиентната функция. След това използваме нови θ стойности, за да преизчислим стойността на разходите, за да намерим разликата, за да проверим условието за спиране. В края на цикъла отпечатваме необходимата информация за всяка итерация.

Резултатът

Резултатът по-долу е за началните условия в кодовия блок за обучение на модела. Обучението отне 27 повторения. θ₀ се изчислява на приблизително 0,015, а θ₁ е около 0,999. Крайната стойност на разходите се изчислява като около 3,936. Резултатът е много близък до линията y = x, обсъждана в Набора данни за линейна регресия. Можем също да видим промяната в хипотезата за всяка итерация.

Валидиране

Можем също така да потвърдим нашия резултат с набора от тестови данни, който не е бил използван в процеса на обучение. По-долу можете да намерите ефективността на нашия модел по отношение на тестовия набор от данни. Цената на модела е приблизително 4,702, малко по-лоша от 3,936 (стойност на разходите за обучение), която се очаква.

Заключение

В тази публикация в блога научихме основите на линейната регресия, като например хипотезата, функцията на разходите и градиентното спускане, използвайки едномерни данни. Ние също написахме тези функции на Python. В допълнение, използвайки ги, ние обучихме едномерен линеен модел и го тествахме с помощта на набора от данни Линейна регресия.

Заинтересованите читатели могат да намерят кода, използван в тази публикация в блога, в бележника на Kaggle Едномерна линейна регресия от нулата.

Благодаря ви, че прочетохте!

Препратки

[1] V. Andonians, „Линейна регресия“, Kaggle.com, 2017 г. [Онлайн]. Налично: https://www.kaggle.com/datasets/andonians/random-linear-regression. [Достъп: 12 септември 2022 г.].

[2] „Учене под наблюдение — Уикипедия,“ En.wikipedia.org, 2022 г. [Онлайн]. Налично: https://en.wikipedia.org/wiki/Supervised_learning. [Достъп: 13 септември 2022 г.].

[3] „Неконтролирано обучение — Уикипедия,“ En.wikipedia.org, 2022 г. [Онлайн]. Налично: https://en.wikipedia.org/wiki/Unsupervised_learning. [Достъп: 13 септември 2022 г.].

[4]” Обучение за укрепване — Уикипедия,' En.wikipedia.org, 2022 г. [Онлайн]. Налично: https://en.wikipedia.org/wiki/Reinforcement_learning. [Достъп: 13 септември 2022 г.].

[5] J. Carew, „Какво е обучение с подсилване? Изчерпателен преглед“, SearchEnterpriseAI, 2021 г. [Онлайн]. Налично: https://www.techtarget.com/searchenterpriseai/definition/reinforcement-learning. [Достъп: 12 септември 2022 г.].

[6] J. Brownlee, „Линейна регресия за машинно обучение“, https://machinelearningmastery.com/, 2022 г. [Онлайн]. Налично: https://machinelearningmastery.com/linear-regression-for-machine-learning/. [Достъп: 11 септември 2022 г.].

[7] JohnX, „Цени на жилищата, Портланд, Орегон“, Kaggle.com, 2017 г. [Онлайн]. Налично: https://www.kaggle.com/datasets/kennethjohn/housingprice. [Достъп: 11 септември 2022 г.].

[8] Е. Хатипоглу, „Едномерна линейна регресия от нулата“, Kaggle.com, 2022 г. [Онлайн]. Налично: https://www.kaggle.com/code/erkanhatipoglu/univariate-linear-regression-from-scratch. [Достъп: 12 септември 2022 г.].

[9] J. Brownlee, „Какво е хипотеза в машинното обучение?“, machinelearningmastery.com, 2019 г. [Онлайн]. Налично: https://machinelearningmastery.com/what-is-a-hypothesis-in-machine-learning/. [Достъп: 12 септември 2022 г.].

[10] A. Ng, „Станфорд CS229: Машинно обучение — линейна регресия и градиентно спускане | Лекция 2 (есен 2018 г.)“, Youtube.com, 2018 г. [Онлайн]. Налично: https://www.youtube.com/watch?v=4b4MUYve_U8&list=PLoROMvodv4rMiGQp3WXShtMGgzqpfVfbU&index=2. [Достъп: 12 септември 2022 г.].