深度學(xué)習(xí)——Keras實(shí)現(xiàn)線性和非線性回歸

在上篇深度學(xué)習(xí)框架Keras的教程中,我們?cè)敿?xì)的介紹了Keras中的Sequential和Functional API。也使用Keras的Sequential實(shí)現(xiàn)了手寫字體的識(shí)別。這次的推文中我們繼續(xù)來看看Keras的簡單使用。因?yàn)楹唵?,所以這次我們的教程主要是使用Keras來實(shí)現(xiàn)機(jī)器學(xué)習(xí)中重要的算法-線性和非線性回歸算法。

一、線性回歸

線性回歸是機(jī)器學(xué)習(xí)領(lǐng)域中常見的算法,該算法試圖學(xué)習(xí)到一個(gè)線性模型以盡可能精確的預(yù)測(cè)出有關(guān)輸入X的輸入Y,或者說精確的建立自變量和觀測(cè)變量之間的映射關(guān)系。好比我們初中階段學(xué)習(xí)的:y=kx+b。

二、Keras實(shí)現(xiàn)線性回歸算法

簡單的介紹了線性回歸的概念之后我們就來實(shí)現(xiàn)這個(gè)算法了,不懂線性回歸模型的小伙伴自己先補(bǔ)充一些機(jī)器學(xué)習(xí)的知識(shí)哈。

這里先復(fù)習(xí)一下使用Keras中Sequential模型來實(shí)現(xiàn)一個(gè)構(gòu)建神經(jīng)網(wǎng)絡(luò)模型的步驟:

  1. 導(dǎo)入模塊并生成數(shù)據(jù)
  2. 建立深度學(xué)習(xí)模型
  3. 激活模型
  4. 進(jìn)行模型的訓(xùn)練
  5. 進(jìn)行模型驗(yàn)證

2.1 先導(dǎo)入相應(yīng)的模塊

import numpy as np

import matplotlib.pyplot as plt
from keras.models import Sequential

from keras.layers import Dense

代碼解釋:

(1)第一行代碼導(dǎo)入numpy,此模塊用來產(chǎn)生訓(xùn)練數(shù)據(jù)集和測(cè)試數(shù)據(jù)集

(2)第二行代碼導(dǎo)入畫圖的模塊

(3)第三行代碼導(dǎo)入keras中的Sequential API。

(4)第四行代碼導(dǎo)入keras中的全連接層(密集層)

2.2 構(gòu)建數(shù)據(jù)集

X_data = np.random.rand(200)
noise = np.random.normal(loc=0,scale=0.09,size=X_data.shape)

Y_data = 2*X_data + noise

X_train, Y_train = X_data[:160], Y_data[:160]     # 前160組數(shù)據(jù)為訓(xùn)練數(shù)據(jù)集
X_test, Y_test = X_data[160:], Y_data[160:]       # 后40組數(shù)據(jù)為測(cè)試數(shù)據(jù)集

plt.scatter(X_data,Y_data, c='r', marker='x')
plt.xlabel('X_data')
plt.ylabel('Y_data')
plt.show()

代碼解釋:

(1)第一行代碼創(chuàng)建X_data數(shù)據(jù),使用函數(shù)np.random.randn()來創(chuàng)建200個(gè)服從標(biāo)準(zhǔn)正態(tài)分布取值范圍為[0,1)的值。

(2)第二行代碼創(chuàng)建200個(gè)隨機(jī)干擾值,這些數(shù)據(jù)滿足均值為0,標(biāo)注差為0.09

(3)第三行代碼構(gòu)建了一個(gè)表達(dá)式然后使scatter()函數(shù)畫出了我們?cè)O(shè)置的x_data和y_data數(shù)據(jù)點(diǎn)的分布情況,并給坐標(biāo)值寫上備注,接下來我們將進(jìn)行構(gòu)建模型。表達(dá)式刻畫了我們X_data、Y_data和noise三者之間的關(guān)系。我們的目標(biāo)是使用Keras學(xué)習(xí)到一個(gè)表達(dá)式,這個(gè)表達(dá)式要與其接近或者一樣。

(4)第四行到第五行代碼使用列表的切片來進(jìn)行數(shù)據(jù)的劃分。

(5)剩下的代碼用來展示我們產(chǎn)生的數(shù)據(jù)集,如下圖所示。

2.3 構(gòu)建Sequential模型并編譯模型

model = Sequential()
model.add(Dense(units=1, input_dim=1))
model.compile(optimizer='sgd', loss='mse')

代碼解釋:

上述第一行表示使用Sequential模型;

上述第二行代碼表示增加一個(gè)Dense全連接層,這個(gè)全連接層的神經(jīng)元的個(gè)數(shù)或者說輸出空間的維度;

上述第三行代碼表示進(jìn)行模型的編譯,這里的優(yōu)化器為sgd即隨機(jī)梯度下降,損失函數(shù)選擇mse即均方誤差。

2.4 進(jìn)行模型的訓(xùn)練

接下來就是進(jìn)行模型的訓(xùn)練了:

for step in range(2000):
   train_cost = model.train_on_batch(X_train, Y_train)
   if step % 100 == 0:
       print('train_cost:', train_cost)
w, b = model.layers[0].get_weights()
print('w:', w, 'b:', b)

代碼解釋:

  1. 第一行代碼的for循環(huán)表示我們將進(jìn)行2000批次的訓(xùn)練。
  2. 第二行的代碼表示我們?cè)跀?shù)據(jù)集train_x, train_y的一批數(shù)據(jù)集上訓(xùn)練
  3. 第三行到第四行表示每訓(xùn)練100次的時(shí)候就打印一次訓(xùn)練的損失。
  4. 第五行到第六行表示打印訓(xùn)練好的這個(gè)模型第一層的w,和b參數(shù)的值。layers[0]表示取第一層,因?yàn)槲覀冎辉黾恿艘粋€(gè)Dense,因此我們建立的模型也只有一層。

上述代碼運(yùn)行之后,最后打印的的train_cost為 0.008163492,我們得到的參數(shù)值為:w: [[1.8364288]] b: [0.06628263]為了更加直觀的顯示實(shí)際的擬合效果,我們顯示在訓(xùn)練集合上訓(xùn)練出的模型

y_pred = model.predict(X_train)
plt.scatter(X_train, Y_train)
plt.plot(X_train, y_pred, 'r-', lw=3)
plt.show()

顯示結(jié)果如下:

代碼解釋:

(1)第一行代碼是將數(shù)據(jù)X_train輸入到網(wǎng)絡(luò)中,并預(yù)測(cè)出y_pred

(2)第二行代碼顯示訓(xùn)練集的數(shù)據(jù),進(jìn)行相應(yīng)的可視化。

(3)第三行代碼顯示訓(xùn)練集X_train和預(yù)測(cè)值y_pred之間的函數(shù)關(guān)系。

由上圖可以看出,我們求得(訓(xùn)練得到)的參數(shù)能較好的擬合那些數(shù)據(jù)點(diǎn)。

2.5 進(jìn)行模型的驗(yàn)證

在生成數(shù)據(jù)集的時(shí)候,我們預(yù)留了測(cè)試集。接下來我們就要在測(cè)試集上進(jìn)行模型的評(píng)價(jià)了,來看看在測(cè)試集上的cost為多少:

test_cost = model.evaluate(X_test, Y_test, batch_size=40)
print('test_cost:', test_cost)

輸出結(jié)果為:test_cost: 0.00930690299719572

可以看出,在進(jìn)行2000次的迭代以后,我們的train_cost > test_cost的,這說明我們的模型還可以繼續(xù)進(jìn)行優(yōu)化,可以繼續(xù)增加訓(xùn)練的迭代次數(shù),比如增加到3000次,4000次,當(dāng)然了也不能過擬合。

感興趣的小伙伴把這個(gè)迭代次數(shù)改為300,看看可視化的情況是怎樣的。

以上我們就使用Keras的Sequential構(gòu)建了一個(gè)線性回歸模型:Y = 1.8364288*X + 0.06628263,它能較好的刻畫我們所產(chǎn)生的數(shù)據(jù)集X_data和Y_data之間的聯(lián)系。

三、Keras實(shí)現(xiàn)非線性回歸算法

線性回歸的函數(shù)是線性的,那么非線性回歸的函數(shù)也就是非線性的啦。那么我們?cè)撛趺从?xùn)練一個(gè)非線性回歸模型去擬合X_data和Y_data呢?不著急我們接著往下學(xué):

跟線性回歸模型一下,我們先導(dǎo)入相應(yīng)的模塊,并構(gòu)建一個(gè)映射函數(shù):

import numpy as np
import matplotlib.pyplot as plt
from keras.layers import Dense
from keras.models import Sequential
from keras.optimizers import SGD
from keras.layers import Activation

X_train = np.linspace(-1,1,200)
noise = np.random.normal(loc=0,scale=0.09,size=X_train.shape)
Y_train = X_train **3 + + noise

plt.scatter(X_train,Y_train, c='r', marker='x')
plt.xlabel('X_train')
plt.ylabel('Y_train')
plt.show()

同樣我們也使用序貫?zāi)P?

model = Sequential()
model.add(Dense(units=10, input_dim=1))
model.add(Activation('tanh'))
model.add(Dense(units=1))
model.add(Activation('tanh'))
model.summary()
sgd = SGD(lr=0.3)
model.compile(optimizer=sgd, loss='mse')
for step in range(4000):
   train_cost = model.train_on_batch(X_train, Y_train)
   if step % 500 == 0:
       print('train_cost:', train_cost)

我們來解釋一下其中的幾行代碼:

  1. 第二行到第五行代碼是用來構(gòu)建模型的相應(yīng)的層的,分別是全連接層、激活層、全連接層和激活層。其中第一層全連接層有10個(gè)神經(jīng)元(節(jié)點(diǎn)),input_dim為1。第二個(gè)全連接層有1個(gè)神經(jīng)元(節(jié)點(diǎn)),其實(shí)第四行代碼我們可以這樣寫:
    model.add(Dense(units=1,input_dim=10)),即第二層的全連接層的input_dim為10。

(2)第六行代碼是打印模型的一個(gè)整體情況,結(jié)果如下所示,我們可以清楚的看到模型的層級(jí)和參數(shù)情況:

Total params: 31

Trainable params: 31

Non-trainable params: 0

(3)第七行代碼模型的學(xué)習(xí)率,里面的lr是梯度下降法的更新步長,在使用keras的fit()函數(shù)時(shí),我們可以在callback中設(shè)置在運(yùn)行過程中調(diào)整學(xué)習(xí)率的方法。大家可以在文檔https://keras-cn.readthedocs.io/en/latest/other/callbacks/中找到答案,后期深入研究的時(shí)候我們可以詳細(xì)的說說這個(gè)callback。

接下來,我們看看我們訓(xùn)練的模型對(duì)訓(xùn)練集的擬合情況:

y_pred = model.predict(X_train)
plt.scatter(X_train, Y_train)
plt.plot(X_train, y_pred, 'r-', lw=3)
plt.show()

可以看到實(shí)際的擬合還是不錯(cuò)的。當(dāng)然了我們訓(xùn)練的模型的參數(shù)是可以保存的,以避免每一次都進(jìn)行訓(xùn)練,保存模型的參數(shù)只需要使model.save_weights就可以搞定,如

model.save_weights('my_model_weights.h5')。

四、總結(jié)

又到了總結(jié)的時(shí)候了,看了上面的教程是不是覺得很簡單,沒錯(cuò)。大家不能只看不練習(xí)哦,自己也跟著學(xué)習(xí)起來,不會(huì)機(jī)器學(xué)習(xí)的小伙伴在課余或工作之外的時(shí)間還是得補(bǔ)充一點(diǎn)相關(guān)知識(shí)哦。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容