詳解tensorflow之過擬合問題實戰
阿新 • • 發佈:2020-11-02
過擬合問題實戰
1.構建資料集
我們使用的資料集樣本特性向量長度為 2,標籤為 0 或 1,分別代表了 2 種類別。藉助於 scikit-learn 庫中提供的 make_moons 工具我們可以生成任意多資料的訓練集。
import matplotlib.pyplot as plt # 匯入資料集生成工具 import numpy as np import seaborn as sns from sklearn.datasets import make_moons from sklearn.model_selection import train_test_split from tensorflow.keras import layers,Sequential,regularizers from mpl_toolkits.mplot3d import Axes3D
為了演示過擬合現象,我們只採樣了 1000 個樣本資料,同時新增標準差為 0.25 的高斯噪聲資料:
def load_dataset(): # 取樣點數 N_SAMPLES = 1000 # 測試數量比率 TEST_SIZE = None # 從 moon 分佈中隨機取樣 1000 個點,並切分為訓練集-測試集 X,y = make_moons(n_samples=N_SAMPLES,noise=0.25,random_state=100) X_train,X_test,y_train,y_test = train_test_split(X,y,test_size=TEST_SIZE,random_state=42) return X,X_train,y_test
make_plot 函式可以方便地根據樣本的座標 X 和樣本的標籤 y 繪製出資料的分佈圖:
def make_plot(X,plot_name,file_name,XX=None,YY=None,preds=None,dark=False,output_dir=OUTPUT_DIR): # 繪製資料集的分佈, X 為 2D 座標, y 為資料點的標籤 if dark: plt.style.use('dark_background') else: sns.set_style("whitegrid") axes = plt.gca() axes.set_xlim([-2,3]) axes.set_ylim([-1.5,2]) axes.set(xlabel="$x_1$",ylabel="$x_2$") plt.title(plot_name,fontsize=20,fontproperties='SimHei') plt.subplots_adjust(left=0.20) plt.subplots_adjust(right=0.80) if XX is not None and YY is not None and preds is not None: plt.contourf(XX,YY,preds.reshape(XX.shape),25,alpha=0.08,cmap=plt.cm.Spectral) plt.contour(XX,levels=[.5],cmap="Greys",vmin=0,vmax=.6) # 繪製散點圖,根據標籤區分顏色m=markers markers = ['o' if i == 1 else 's' for i in y.ravel()] mscatter(X[:,0],X[:,1],c=y.ravel(),s=20,cmap=plt.cm.Spectral,edgecolors='none',m=markers,ax=axes) # 儲存向量圖 plt.savefig(output_dir + '/' + file_name) plt.close()
def mscatter(x,ax=None,m=None,**kw): import matplotlib.markers as mmarkers if not ax: ax = plt.gca() sc = ax.scatter(x,**kw) if (m is not None) and (len(m) == len(x)): paths = [] for marker in m: if isinstance(marker,mmarkers.MarkerStyle): marker_obj = marker else: marker_obj = mmarkers.MarkerStyle(marker) path = marker_obj.get_path().transformed( marker_obj.get_transform()) paths.append(path) sc.set_paths(paths) return sc
X,y_test = load_dataset() make_plot(X,"haha",'月牙形狀二分類資料集分佈.svg')
2.網路層數的影響
為了探討不同的網路深度下的過擬合程度,我們共進行了 5 次訓練實驗。在𝑛 ∈ [0,4]時,構建網路層數為n + 2層的全連線層網路,並通過 Adam 優化器訓練 500 個 Epoch
def network_layers_influence(X_train,y_train): # 構建 5 種不同層數的網路 for n in range(5): # 建立容器 model = Sequential() # 建立第一層 model.add(layers.Dense(8,input_dim=2,activation='relu')) # 新增 n 層,共 n+2 層 for _ in range(n): model.add(layers.Dense(32,activation='relu')) # 建立最末層 model.add(layers.Dense(1,activation='sigmoid')) # 模型裝配與訓練 model.compile(loss='binary_crossentropy',optimizer='adam',metrics=['accuracy']) model.fit(X_train,epochs=N_EPOCHS,verbose=1) # 繪製不同層數的網路決策邊界曲線 # 視覺化的 x 座標範圍為[-2,3] xx = np.arange(-2,3,0.01) # 視覺化的 y 座標範圍為[-1.5,2] yy = np.arange(-1.5,2,0.01) # 生成 x-y 平面取樣網格點,方便視覺化 XX,YY = np.meshgrid(xx,yy) preds = model.predict_classes(np.c_[XX.ravel(),YY.ravel()]) print(preds) title = "網路層數:{0}".format(2 + n) file = "網路容量_%i.png" % (2 + n) make_plot(X_train,title,file,XX,preds,output_dir=OUTPUT_DIR + '/network_layers')
3.Dropout的影響
為了探討 Dropout 層對網路訓練的影響,我們共進行了 5 次實驗,每次實驗使用 7 層的全連線層網路進行訓練,但是在全連線層中間隔插入 0~4 個 Dropout 層並通過 Adam優化器訓練 500 個 Epoch
def dropout_influence(X_train,y_train): # 構建 5 種不同數量 Dropout 層的網路 for n in range(5): # 建立容器 model = Sequential() # 建立第一層 model.add(layers.Dense(8,activation='relu')) counter = 0 # 網路層數固定為 5 for _ in range(5): model.add(layers.Dense(64,activation='relu')) # 新增 n 個 Dropout 層 if counter < n: counter += 1 model.add(layers.Dropout(rate=0.5)) # 輸出層 model.add(layers.Dense(1,activation='sigmoid')) # 模型裝配 model.compile(loss='binary_crossentropy',metrics=['accuracy']) # 訓練 model.fit(X_train,verbose=1) # 繪製不同 Dropout 層數的決策邊界曲線 # 視覺化的 x 座標範圍為[-2,YY.ravel()]) title = "無Dropout層" if n == 0 else "{0}層 Dropout層".format(n) file = "Dropout_%i.png" % n make_plot(X_train,output_dir=OUTPUT_DIR + '/dropout')
4.正則化的影響
為了探討正則化係數𝜆對網路模型訓練的影響,我們採用 L2 正則化方式,構建了 5 層的神經網路,其中第 2,4 層神經網路層的權值張量 W 均新增 L2 正則化約束項:
def build_model_with_regularization(_lambda): # 建立帶正則化項的神經網路 model = Sequential() model.add(layers.Dense(8,activation='relu')) # 不帶正則化項 # 2-4層均是帶 L2 正則化項 model.add(layers.Dense(256,activation='relu',kernel_regularizer=regularizers.l2(_lambda))) model.add(layers.Dense(256,kernel_regularizer=regularizers.l2(_lambda))) # 輸出層 model.add(layers.Dense(1,activation='sigmoid')) model.compile(loss='binary_crossentropy',metrics=['accuracy']) # 模型裝配 return model
下面我們首先來實現一個權重視覺化的函式
def plot_weights_matrix(model,layer_index,output_dir=OUTPUT_DIR): # 繪製權值範圍函式 # 提取指定層的權值矩陣 weights = model.layers[layer_index].get_weights()[0] shape = weights.shape # 生成和權值矩陣等大小的網格座標 X = np.array(range(shape[1])) Y = np.array(range(shape[0])) X,Y = np.meshgrid(X,Y) # 繪製3D圖 fig = plt.figure() ax = fig.gca(projection='3d') ax.xaxis.set_pane_color((1.0,1.0,0.0)) ax.yaxis.set_pane_color((1.0,0.0)) ax.zaxis.set_pane_color((1.0,0.0)) plt.title(plot_name,fontproperties='SimHei') # 繪製權值矩陣範圍 ax.plot_surface(X,Y,weights,cmap=plt.get_cmap('rainbow'),linewidth=0) # 設定座標軸名 ax.set_xlabel('網格x座標',fontsize=16,rotation=0,fontproperties='SimHei') ax.set_ylabel('網格y座標',fontproperties='SimHei') ax.set_zlabel('權值',rotation=90,fontproperties='SimHei') # 儲存矩陣範圍圖 plt.savefig(output_dir + "/" + file_name + ".svg") plt.close(fig)
在保持網路結構不變的條件下,我們通過調節正則化係數 𝜆 = 0.00001,0.001,0.1,0.12,0.13
來測試網路的訓練效果,並繪製出學習模型在訓練集上的決策邊界曲線
def regularizers_influence(X_train,y_train): for _lambda in [1e-5,1e-3,1e-1,0.13]: # 設定不同的正則化係數 # 建立帶正則化項的模型 model = build_model_with_regularization(_lambda) # 模型訓練 model.fit(X_train,verbose=1) # 繪製權值範圍 layer_index = 2 plot_title = "正則化係數:{}".format(_lambda) file_name = "正則化網路權值_" + str(_lambda) # 繪製網路權值範圍圖 plot_weights_matrix(model,plot_title,output_dir=OUTPUT_DIR + '/regularizers') # 繪製不同正則化係數的決策邊界線 # 視覺化的 x 座標範圍為[-2,YY.ravel()]) title = "正則化係數:{}".format(_lambda) file = "正則化_%g.svg" % _lambda make_plot(X_train,output_dir=OUTPUT_DIR + '/regularizers')
regularizers_influence(X_train,y_train)
到此這篇關於詳解tensorflow之過擬合問題實戰的文章就介紹到這了,更多相關tensorflow 過擬合內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!