周末AI課堂:神經網路的正則化 代碼篇
AI課堂開講,就差你了!
很多人說,看了再多的文章,可是沒有人手把手地教授,還是很難真正地入門AI。為了將AI知識體系以最簡單的方式呈現給你,從這個星期開始,芯君邀請AI專業人士開設「周末學習課堂」——每周就AI學習中的一個重點問題進行深度分析,課程會分為理論篇和代碼篇,理論與實操,一個都不能少!
來,退出讓你廢寢忘食的遊戲頁面,取消只有胡吃海塞的周末聚會吧。未來你與同齡人的差異,也許就從每周末的這堂AI課開啟了!
讀芯術讀者交流群,請加小編微信號:zhizhizhuji。等你。後台回復「周末AI課堂」,查閱相關源代碼。
全文共1923字,預計學習時長4分鐘
我們在上一節講解了深度學習中常用的幾種正則化手段,包括提前終止、添加雜訊、參數共享和Dropout。並且說明了與我們常見的L1、L2正則化的等價性。我們在這篇文章里將會使用keras面對具體的任務添加不同的正則化手段。
我們採用boston房價這一經典回歸問題的數據集,因為它包含404個訓練樣例,102個測試樣本,特徵維數為13。對於深度學習而言,這樣的數據量和特徵都少得可憐,用一個簡單的神經網路可能就會發生過擬合,這正是我們需要的。
boston房價數據的特徵具有不同的單位,比如有的特徵使人均犯罪率,而有的特徵是到就業中心的加權距離,特徵之間單位的不一致,不利於後續對特徵的統一處理,同時也是為了加快收斂,我們先對數據做標準化處理。
from keras.datasets import boston_housing
from sklearn.preprocessing import StandardScaler
(x_train, y_train), (x_test, y_test) = boston_housing.load_data()
scale=StandardScaler().fit(x_train)
x_train=scale.transform(x_train)
x_test=scale.transform(x_test)
在這裡我們使用了StandardScaler類進行預處理,因為它可以保存好標準化訓練集得到的均值和標準差,在轉化測試集時也要使用它,因為我們假設訓練數據和測試數據具有相同的分布,對測試數據不建議單獨標準化。
接下來我們搭建一個較為複雜的網路用於回歸問題:
import numpy as np
from keras import models
from keras.layers import Dense
from keras import optimizers
def normal_model(a,b):
model=models.Sequential()
model.add(Dense(1024,activation=a,input_shape=(13,)))
model.add(Dense(512,activation=a))
model.add(Dense(256,activation=a))
model.add(Dense(128,activation=a))
model.add(Dense(512,activation=a))
model.add(Dense(256,activation=a))
model.add(Dense(128,activation=a))
model.add(Dense(1,activation="linear"))
model.compile(optimizer=optimizers.SGD(),
loss=b,metrics=["mse"])
return(model)
model_1=normal_model("sigmoid","mse")
his=model_1.fit(x_train,y_train,
batch_size=32,validation_data=(x_test,y_test),
verbose=1,epochs=10)
w=his.history
需要特別注意,因為特徵有13維,所以我們需要設置13維的輸入,因為是回歸問題,我們可以將輸出單元設置為線性,並且只有一個;將訓練結果保存在變數中,畫圖來觀察loss隨著epochs的變化,因為訓練集的loss一定是隨著迭代的增加減小直至趨於收斂,所以我們只看驗證集上的loss:
import matplotlib.pyplot as plt
import seaborn as sns
sns.set(style="whitegrid")
plt.plot(range(10),w["val_loss"],"-",label="validation loss")
plt.title("Loss")
plt.xlabel("epochs")
plt.legend()
如圖,驗證集上的loss隨著epochs在波動,經過劇烈的上升後又劇烈的下降。
對於這樣的圖我們似乎就無法判斷是否發生了過擬合,因為loss忽高忽低,看起來只是在正常的波動,所以我們最好將這樣的曲線變得平滑一些,我們可以採用時間序列模型經常採用的指數平滑法:
def smooth_curve(points,factors=0.9):
smoothed_points= []
for point in points:
if smoothed_points:
previous=smoothed_points[-1]
smoothed_points.append(previous*factors+point*(1-factors))
else:
smoothed_points.append(point)
return(smoothed_points)
......
plt.plot(range(10),smooth_curve(w["val_loss"]),"o",label="validation loss")
......
如圖,我們不僅做了平滑處理,而且使用點代替了折線,可以看出,在剛開始訓練的時候,或者在第一個epochs之後,loss就已經開始上升,代表著嚴重的過擬合。
在訓練過程中,我們設置了batch為32,所以在重複過程中會有差別。我們當然可以考慮提前終止,只是提前終止在技術上是非常簡單的事情,所以此處不做提前終止的示例。
根據我們的理論知識,我們採取相應的正則化手段去削減模型容量的時候,需要觀察模型的經過幾次迭代才會產生過擬合,如果正則化手段可以將過擬合所需要的迭代次數增加,那麼就意味著有效的,因為在訓練過程中,訓練的Loss總會下降對應著參數值的變化,過擬合在多久會發生就會成為模型容量的度量。必須要注意,這一過程,我們需要保持模型的基本結構不變,優化演算法的學習率不變。
我們首先嘗試常見的正則化手段,在keras中,添加懲罰項的方法非常簡單,它直接添加在層裡面,表示這一層的權重矩陣,偏置,激活函數的閾值這三類參數構成的懲罰項均可以被添加到損失函數中,而其他沒有設置正則化的層的參數不是添加到損失函數中。簡而言之,我們可以實現針對某一層的正則化:
from keras import regularizers
......
model.add(Dense(1024,
kernel_regularizer=regularizers.l2(0.1),
activation=a,input_shape=(13,)))
......
上述代碼的意思是,我們對模型的第一層的權重矩陣進行了正則化,將懲罰係數設置為0.1,這已經是一個相當大的係數,我們繼續觀察Loss的變化:
如圖,模型在前6個epochs在微弱的波動,從第六個開始就產生過擬合,說明我們的正則化手段是有效的,它一定程度上削減了模型的容量,將過擬合的步數增加到了第六個epochs。
除此之外,我們還可以添加雜訊,在keras中,雜訊可以是單獨的一個層,分為加性雜訊和乘性雜訊,可以分別將雜訊加在輸入層和權重上,我們可以將模型的開始部位改為:
from keras.layers import GaussianNoise
......
model.add(GaussianNoise((0.9),input_shape=(13,)))
model.add(Dense(1024,activation=a))
......
這樣就將標準差為0.9的高斯雜訊加入了輸入中,就得到了:
如圖,模型的Loss在前4個epochs在保持下降,從第4個開始就產生過擬合,說明添加雜訊是有效的。
最後我們來嘗試使用dropout方法,在keras中dropout也是可以當作一個單獨的層,我們可以在輸入層和中間層分別添加Dropout層,分別代表有些特徵不會使用,有些神經元不會使用:
from keras.layers import Dropout
......
model.add(Dropout(0.2, input_shape=(13,)))
model.add(Dense(1024,activation=a))
model.add(Dropout(0.5))
......
這代表著我們在輸入層隨機丟棄了比例為0.2的特徵,在第一層丟棄了0.5的神經元,結果如下:
如圖,模型的Loss在前5個epochs在保持下降,從第5個開始就產生過擬合,說明Dropout方法是有效的。
在實際操作中,我們完全可以將這些方法融合在一起,即添加雜訊,也添加和正則化,還添加dropout,在訓練過程中,進行提前終止。
讀芯君開扒
課堂TIPS
? 在keras中,如果我們想添加提前終止,最便利的方法是利用回調函數EarlyStopping,它自動檢測模型的loss或者性能度量,當在幾步之內都沒有上升的時候就停止訓練,並將最優的模型保存下來。
? 如果我們相對網路的參數做一些額外的約束,例如非負,或者是想和一個預訓練模型進行參數綁定,我們可以使用keras的contraints。
? 當數據量較少時,我們應該做交叉驗證,這樣得到的結果會更加準確,本文只做簡單示例,未使用交叉驗證。
留言 點贊 發個朋友圈
我們一起分享AI學習與發展的乾貨
作者:唐僧不用海飛絲
如需轉載,請後台留言,遵守轉載規範


TAG:讀芯術 |