實(shí)踐|手寫(xiě)邏輯回歸算法
點(diǎn)擊上方“小白學(xué)視覺(jué)”,選擇加"星標(biāo)"或“置頂”
重磅干貨,第一時(shí)間送達(dá)
盡管對(duì)于機(jī)器學(xué)習(xí)來(lái)說(shuō),理論是非常重要的內(nèi)容,但是持續(xù)的理論學(xué)習(xí)多少會(huì)有些審美疲勞。今天,我們就試著用代碼來(lái)簡(jiǎn)單實(shí)現(xiàn)一下邏輯回歸,也方便大家更好地理解邏輯回歸的原理,以及機(jī)器學(xué)習(xí)模型在實(shí)踐中是怎么運(yùn)作的。
一、邏輯回歸算法步驟簡(jiǎn)述
構(gòu)建一個(gè)邏輯回歸模型有以下幾步:
收集數(shù)據(jù):采用任意方法收集數(shù)據(jù)
準(zhǔn)備數(shù)據(jù):由于需要進(jìn)行距離計(jì)算,因此我們要求數(shù)據(jù)類型為數(shù)值型。若是結(jié)構(gòu)化數(shù)據(jù)格式更佳
分析數(shù)據(jù):采用任意方法對(duì)數(shù)據(jù)進(jìn)行分析
訓(xùn)練算法:大部分時(shí)間將用于訓(xùn)練,訓(xùn)練的目的是為了找到最佳的分類回歸系數(shù)
測(cè)試算法:訓(xùn)練步驟完成后將對(duì)算法進(jìn)行測(cè)試
使用算法:首先我們需要輸入一些數(shù)據(jù),并將其轉(zhuǎn)換成對(duì)應(yīng)的結(jié)構(gòu)化數(shù)值;接著,基于訓(xùn)練好的回歸系數(shù)就可以對(duì)這些數(shù)值進(jìn)行簡(jiǎn)單的回歸運(yùn)算,判定它們屬于哪個(gè)類別;在這之后,我們就可以在輸出的類別上做一些其它的分析工作。
并且,因?yàn)檫壿嫽貧w適用于二元分類,因此,我們這次的這組數(shù)據(jù)的預(yù)測(cè)值僅有0和1(其它類型的數(shù)值也沒(méi)關(guān)系,但都以0,1表示會(huì)比較方便)分別代表二元分類中的negative class 和 possitive class。
二、選擇輸入函數(shù):sigmoid函數(shù)
因?yàn)槲覀円呀?jīng)確定是邏輯回歸模型(若是未知模型的數(shù)據(jù)我們還需要從頭推導(dǎo)模型),所以作為分類器的輸出函數(shù)我們選擇邏輯函數(shù),又稱sigmoid函數(shù):

我們將sigmoid函數(shù)的輸入θTx記為z,z由下面這個(gè)公式導(dǎo)出:

顯然,x便是我們的輸入變量。
三、選擇優(yōu)化算法:梯度上升法
作為第一次訓(xùn)練,我們選擇比較簡(jiǎn)單的參數(shù)更新方法:梯度上升法,它細(xì)分為兩種,一種是精度比較高但消耗比較大的批梯度上升法:

另一種是精度較低但速度較快的隨機(jī)梯度上升法:

四、觀察數(shù)據(jù)集
在數(shù)據(jù)集的樣本特征還處在比較的低維的空間(方便我們觀察的空間,像是二維(兩個(gè)特征)或者三維(三個(gè)特征))的時(shí)候,我們可以為數(shù)據(jù)集繪制坐標(biāo)圖形從而對(duì)坐標(biāo)進(jìn)行簡(jiǎn)單地觀察。盡管在現(xiàn)實(shí)任務(wù)中基本上不可能出現(xiàn)特征空間是二維或者三維的數(shù)據(jù)集,但在用代碼實(shí)現(xiàn)理論模型的時(shí)候,這些簡(jiǎn)單的數(shù)據(jù)集能夠讓我們非常直觀的看到實(shí)現(xiàn)的模型的效果而不需要去借助比較復(fù)雜的模型評(píng)估方法,換句話說(shuō),它們能夠很好的輔助我們實(shí)現(xiàn)模型。
在現(xiàn)實(shí)任務(wù)中我們往往也有在處理數(shù)據(jù)前對(duì)數(shù)據(jù)集進(jìn)行觀察的必要,不論是制定數(shù)據(jù)預(yù)處理的策略還是選擇模型的策略,觀察并且了解自己將要處理的數(shù)據(jù)集都是非常非常重要的一項(xiàng)工作。
這里我用的數(shù)據(jù)集是來(lái)自Peter Harrington《機(jī)器學(xué)習(xí)實(shí)戰(zhàn)》第五章上的數(shù)據(jù)集,github鏈接(https://github.com/pbharrin/machinelearninginaction)
這個(gè)數(shù)據(jù)集的樣本特征空間只有兩維,分別為x1和x2,標(biāo)簽僅有正類(1)和負(fù)類(0),我們用matplotlib模塊來(lái)繪制它在平面直角坐標(biāo)系上的數(shù)據(jù)分布圖像:

數(shù)據(jù)集導(dǎo)入和輸出代碼:


函數(shù)loadDataSet將數(shù)據(jù)集從testSet.txt逐行讀取并存入兩個(gè)矩陣中。testSet中每一行的數(shù)據(jù)有三個(gè)值,分別是X1,X2和數(shù)據(jù)對(duì)應(yīng)的類別標(biāo)簽。并且,注意到我們?cè)?/span>dataMat中的第一個(gè)值設(shè)置為1,那其實(shí)是X0的值,這在這里單純的數(shù)據(jù)集輸出中沒(méi)有太大的作用,但是會(huì)方便之后我們導(dǎo)入模型時(shí)的計(jì)算。shape函數(shù)讀取矩陣的行數(shù)m和列數(shù)n。
figure建立繪圖平面,addsubplot表示我們要在平面上建立繪制幾個(gè)圖表,111說(shuō)明我們希望繪制一個(gè)占整個(gè)平面1?1大小的圖表,然后選取第一個(gè)圖表。
scatter表示散點(diǎn)圖,參數(shù)marker='s'表示點(diǎn)的形狀為方形,它還可以接收一個(gè)參數(shù)s=<NUMBER>來(lái)調(diào)整點(diǎn)的大小。
五、批梯度上升訓(xùn)練
得知數(shù)據(jù)集的輸出型狀后,我們可以著手構(gòu)建模型了,這一次我們先使用梯度上升模型。
我們先來(lái)構(gòu)筑sigmoid函數(shù):

表示接收一個(gè)輸入inX可以認(rèn)為是我們?cè)趕igmoid函數(shù)中所說(shuō)的’z’,用sigmoid函數(shù)輸出。
然后構(gòu)建梯度上升函數(shù):

第一個(gè)參數(shù)是全部輸入樣本組成的二維數(shù)組,每一個(gè)樣本包含3個(gè)特征分別是X0,X1,X2,因此,用mat函數(shù)轉(zhuǎn)換后的dataMat是一個(gè)3 x 100的輸入矩陣。第二個(gè)參數(shù)是每一個(gè)樣本的標(biāo)簽組成的矩陣,為了方便計(jì)算,我們?cè)谵D(zhuǎn)化它為1 x 100的矩陣后還要用transpose()將其轉(zhuǎn)置。
變量alpha表示梯度上升中的步長(zhǎng),maxCycles表示我們將要進(jìn)行的步數(shù),一般來(lái)說(shuō)我們也可以通過(guò)設(shè)定條件讓程序判斷收斂情況來(lái)自行決定合適的步長(zhǎng),但這一步我們暫且先簡(jiǎn)化為這樣。weights便是我們希望求得的參數(shù),可以看作是上面給出的梯度上升的數(shù)學(xué)模型中的θ,這里我們先將其初始化為一個(gè) 3 x 1的矩陣分別對(duì)應(yīng)數(shù)據(jù)的3個(gè)特征。
然后我們循環(huán)更新weights值,以找到最合適的weights。更新方式便是梯度上升更新:

我們可以把它與上面的梯度更新公式對(duì)比一下。然后通過(guò)500步更新得到目標(biāo)參數(shù)weights。
我們可以用print輸出看看我們得到的參數(shù):

然后將其繪制到我們一開(kāi)始做的數(shù)據(jù)集表示圖上。


發(fā)現(xiàn)效果不錯(cuò)。其中,函數(shù)getA()表示將矩陣weights轉(zhuǎn)換成數(shù)組,如果我們不這么做的話,輸出一下x和y就會(huì)發(fā)現(xiàn)這一步的必要性:

我們會(huì)發(fā)現(xiàn)y的值是被包裹在兩個(gè)[]里面的,實(shí)際上可以認(rèn)為y是一個(gè)嵌套了兩層的一維矩陣,這也是為什么,我們要用getA來(lái)將weights從矩陣轉(zhuǎn)換回?cái)?shù)組。
y的計(jì)算方式或許也會(huì)給人帶來(lái)疑問(wèn):實(shí)際上,我們知道,我們希望得到的是一條將兩個(gè)數(shù)據(jù)集分開(kāi)的直線。因此,我們?cè)诮o出一串連續(xù)的橫坐標(biāo)(代碼中就是從-3到3每隔0.1取一個(gè)橫坐標(biāo))組成的向量后,就可以根據(jù)直線的方程y=kx+b(轉(zhuǎn)換成?w2X2=w1X1+w0)
計(jì)算這一連串橫坐標(biāo)對(duì)應(yīng)的y軸坐標(biāo),然后將其繪制到散點(diǎn)圖上。
六、隨機(jī)梯度上升訓(xùn)練
因?yàn)槲覀冞@里的樣本比較小,所以我們的批梯度上升可以很快的就得到我們想要的結(jié)果,但實(shí)際上,很多數(shù)據(jù)集包含的內(nèi)容都非常巨大,因此,為了能夠快速執(zhí)行分類任務(wù),我們有時(shí)候會(huì)犧牲一些精度來(lái)?yè)Q取運(yùn)算的速度。這便是我們的隨機(jī)梯度上升法,它的原理我在機(jī)器學(xué)習(xí)理論中的筆記有講,這里就不再贅述:



可以得到我們隨機(jī)梯度下降的結(jié)果:

發(fā)現(xiàn)結(jié)果沒(méi)有之前的準(zhǔn)確,這是當(dāng)然的,因?yàn)槲覀儬奚司龋S機(jī)梯度上升對(duì)參數(shù)weights的每一次更新都只用了一個(gè)樣本,因此速度上相較批梯度上升會(huì)大幅提升。
下面這張圖表示每一次更新回歸參數(shù)X0,X1,X2的值,根據(jù)樣本次數(shù),我們總共更新了100次:
繪圖代碼:



可以看出來(lái),回歸參數(shù)的上下波動(dòng)非常巨大,并且時(shí)常會(huì)往與梯度不同的方向更新,X2在開(kāi)始的幾次更新之后很快達(dá)到了穩(wěn)定,但是X0和X1則沒(méi)有。
并且,我們可以發(fā)現(xiàn),參數(shù)在趨于穩(wěn)定之后依然會(huì)有局部波動(dòng),這是因?yàn)閿?shù)據(jù)集中并非所有的數(shù)據(jù)都可以確保正確分類(因?yàn)閿?shù)據(jù)集并非線性可分)。
資料來(lái)源參考:
Peter Harrington.《機(jī)器學(xué)習(xí)實(shí)戰(zhàn)》,人民郵電出版社
數(shù)據(jù)集來(lái)源 Github:Peter Harrington(https://github.com/pbharrin/machinelearninginaction)
好消息!
小白學(xué)視覺(jué)知識(shí)星球
開(kāi)始面向外開(kāi)放啦??????
下載1:OpenCV-Contrib擴(kuò)展模塊中文版教程 在「小白學(xué)視覺(jué)」公眾號(hào)后臺(tái)回復(fù):擴(kuò)展模塊中文教程,即可下載全網(wǎng)第一份OpenCV擴(kuò)展模塊教程中文版,涵蓋擴(kuò)展模塊安裝、SFM算法、立體視覺(jué)、目標(biāo)跟蹤、生物視覺(jué)、超分辨率處理等二十多章內(nèi)容。 下載2:Python視覺(jué)實(shí)戰(zhàn)項(xiàng)目52講 在「小白學(xué)視覺(jué)」公眾號(hào)后臺(tái)回復(fù):Python視覺(jué)實(shí)戰(zhàn)項(xiàng)目,即可下載包括圖像分割、口罩檢測(cè)、車道線檢測(cè)、車輛計(jì)數(shù)、添加眼線、車牌識(shí)別、字符識(shí)別、情緒檢測(cè)、文本內(nèi)容提取、面部識(shí)別等31個(gè)視覺(jué)實(shí)戰(zhàn)項(xiàng)目,助力快速學(xué)校計(jì)算機(jī)視覺(jué)。 下載3:OpenCV實(shí)戰(zhàn)項(xiàng)目20講 在「小白學(xué)視覺(jué)」公眾號(hào)后臺(tái)回復(fù):OpenCV實(shí)戰(zhàn)項(xiàng)目20講,即可下載含有20個(gè)基于OpenCV實(shí)現(xiàn)20個(gè)實(shí)戰(zhàn)項(xiàng)目,實(shí)現(xiàn)OpenCV學(xué)習(xí)進(jìn)階。 交流群
歡迎加入公眾號(hào)讀者群一起和同行交流,目前有SLAM、三維視覺(jué)、傳感器、自動(dòng)駕駛、計(jì)算攝影、檢測(cè)、分割、識(shí)別、醫(yī)學(xué)影像、GAN、算法競(jìng)賽等微信群(以后會(huì)逐漸細(xì)分),請(qǐng)掃描下面微信號(hào)加群,備注:”昵稱+學(xué)校/公司+研究方向“,例如:”張三 + 上海交大 + 視覺(jué)SLAM“。請(qǐng)按照格式備注,否則不予通過(guò)。添加成功后會(huì)根據(jù)研究方向邀請(qǐng)進(jìn)入相關(guān)微信群。請(qǐng)勿在群內(nèi)發(fā)送廣告,否則會(huì)請(qǐng)出群,謝謝理解~
