自我學習與理解:keras框架下的深度學習(三)迴歸問題

眼前有座山發表於2021-12-27

  本文主要是使用keras對其有的波士頓房價資料集做一個迴歸預測,其程式碼架構與之前一樣(都只是使用多層感知機):資料的預處理、搭建網路框架、編譯、迴圈訓練以及測試訓練的網路模型。其中除了資料預處理與之前歸回模型略有不同,其他基本類似。但是在本文的迴歸預測程式碼中會提到一個資料集比較少時常用到的訓練方法——交叉驗證。

       迴歸預測房價,也就是說選定影響房價的因素,將其量化,然後使用該資料和對應的房價價格訓練神經網路,最後使用因素的量化值來預測房價的走勢。

       Keras中的波士頓房價資料集,其中一共只有506個樣本,其中只有404個用來做訓練。其他是用來做測試。每個樣本有13個特徵,也就是有13個房價影響因素(13個因素中有些是具體的數值也有的是給定的權重值)。所以訓練資料集是:[404,13]。

       1.資料的預處理

       首先使用keras匯入所需要使用的包以及資料集

from keras.datasets import boston_housing
(train_data,train_targets),(test_data,test_targets)=boston_housing.load_data()

  然後對資料進行標準化處理,得到特徵平均值為0,標準差為1的資料,這樣更加有利於網路的處理及其收斂。

mean = train_data.mean(axis=0)  
train_data -= mean  
std = train_data.std(axis=0) 
train_data/=std 

test_data-=mean
test_data/=std

 

  第一部分程式碼中的train_data.mean(axis=0)表示是求train_data中每一行的特徵平均值,其std所求的也是每一行的標準差,也就是對每一組資料中的13個影響因素做標註化。(使用print(train_data.shape)可以得到訓練資料的形狀[404,13],上述程式碼中的axis=0就是指的404)

       第二部分程式碼中,我們直接使用訓練集上所得到的特徵平均值和標準差來對測試集進行標準化,其原因是不能使得網路提前知道了測試集的資料。

       2.搭建網路架構

model=models.Sequential()
model.add(layers.Dense(32,activation='relu',input_shape=(trian_data.shape[1],)))
model.add(layers.Dense(32,activation='relu'))
model.add(layers.Dense(1))

  網路架構的搭建與之前文章一樣,但是在最後不需要進行非線性的處理,因為改網路是需要做一個預測,所以直接輸出網路得到的數值即可。

       3.編譯

model.compile(
        optimizer='rmsprop',loss='mse',metrics=['mae'] )

  編譯這裡採用的損失函式是mae,也就是平均絕對誤差,即取預測值和真實值之間誤差的平方作為網路得到的誤差進行返回訓練。

       4.迴圈網路

k=4
num=len(trian_data)//k
num_epochs=60
all_list=[]
for i in range(k):
    print('proccesing #',i)
    val_data=trian_data[i*num:(i+1)*num]
    val_target=trian_target[i*num:(i+1)*num]

    par_data=np.concatenate(
        [trian_data[:i*num],
        trian_data[(i+1)*num:]],
        axis=0
    )
    par_target=np.concatenate(
        [trian_target[:i*num],
        trian_target[(i+1)*num:]],
        axis=0
    )
           his=model.fit(par_data,par_target,epochs=num_epochs,batch_size=1,validation_data=(val_data,val_target))
    history=his.history['mae']
    all_list.append(history)

  因為該資料集十分稀少(404個),所以為了提升網路的效能,這裡使用交叉驗證來加強網路效能。交叉驗證,也就是把所以的訓練資料分成n分,按順序選取從其中一份做驗證集,其餘做測試集,直到n份資料都做過驗證集為止。如下圖所示:

  在程式碼中,用k表示一共分成的份數,然後進行,其中一共需要進行k次驗證,每次進行驗證時都會執行num_epochs次。最後把每一次的的mae值儲存在all_list的列表中,方便後面的畫圖。

  在上述程式碼中,因為一個訓練了k(k=4)輪,每輪60次(epochs=60),所以我們求60次的均值(一共四組資料,求均值,從4*60個數值得到60個數值),然後再使用得到的均值作圖,程式碼如下:

ave_list=[np.mean([x[i] for x in all_list]) for i in range(num_epochs)]
plt.plot(range(1,len(ave_list)+1),ave_list)
plt.xlabel('epochs')
plt.ylabel('validation mae')
plt.show()

  第一行程式碼是分別對4組中的資料求60個epochs的均值;剩下的程式碼是做mae的驗證值曲線,得到的曲線如圖所示:

 

 

 

   mae越小,表示預測越準確;其餘曲線,比如說是驗證集的損失值曲線,只需替換 4.迴圈網路中的history:

#替換前
history=his.history['mae']
#替換後
history=his.history['val_mae']

  之後修改y軸名稱即可,關於能畫什麼曲線,因為在model.fit中,我們使用了訓練集和驗證集,所以最後得到訓練集的loss和mae以及驗證集的loss和mae。

  5.所有程式碼

from keras.datasets import boston_housing
from keras import layers
from keras import models
import numpy as np
import matplotlib.pyplot as plt
(train_data,train_target),(tesr_data,test_target)=boston_housing.load_data()
print(train_data[1])
mean=np.mean(train_data)
train_data-=mean
str=np.std(train_data)
train_data/=str

tesr_data-=mean
tesr_data/=str
print(train_data[1])

model=models.Sequential()
model.add(layers.Dense(32,activation='relu',input_shape=(train_data.shape[1],)))
model.add(layers.Dense(32,activation='relu'))
model.add(layers.Dense(1))
model.compile(
        optimizer='rmsprop',loss='mse',metrics=['mae'] )


k=4
num=len(train_data)//k
num_epochs=60
all_list=[]
for i in range(k):
    print('proccesing #',i)
    val_data=train_data[i*num:(i+1)*num]    #從訓練集中提取出驗證的資料部分
    val_target=train_target[i*num:(i+1)*num]    #從訓練集中提取出驗證的標籤部分(房價)

    par_data=np.concatenate(        #把訓練資料的其他部分粘合在一起
        [train_data[:i*num],
        train_data[(i+1)*num:]],
        axis=0
    )
    par_target=np.concatenate(      #把訓練標籤的其他部分粘合在一起
        [train_target[:i*num],
        train_target[(i+1)*num:]],
        axis=0
    )
    his=model.fit(par_data,par_target,epochs=num_epochs,batch_size=1,validation_data=(val_data,val_target))
    history=his.history['mae']
    all_list.append(history)


ave_list=[np.mean([x[i] for x in all_list]) for i in range(num_epochs)]
plt.plot(range(1,len(ave_list)+1),ave_list)
plt.xlabel('epochs')
plt.ylabel('train mae')
plt.show()

   目前為之所有用到的網路層次都是使用多層感知機,也就是神經網路演算法,在後面的文章中會開始介紹卷積神經網路演算法。

 

相關文章