在上篇深度學(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ò)模型的步驟:
- 導(dǎo)入模塊并生成數(shù)據(jù)
- 建立深度學(xué)習(xí)模型
- 激活模型
- 進(jìn)行模型的訓(xùn)練
- 進(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)
代碼解釋:
- 第一行代碼的for循環(huán)表示我們將進(jìn)行2000批次的訓(xùn)練。
- 第二行的代碼表示我們?cè)跀?shù)據(jù)集train_x, train_y的一批數(shù)據(jù)集上訓(xùn)練
- 第三行到第四行表示每訓(xùn)練100次的時(shí)候就打印一次訓(xùn)練的損失。
- 第五行到第六行表示打印訓(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)
我們來解釋一下其中的幾行代碼:
- 第二行到第五行代碼是用來構(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í)哦。