-
欠擬合和過擬合
過擬合和欠擬合是導致模型泛化能力不高的兩種原因,都是模型學習能力與數據複雜度之間失配的 結果。- 欠擬合:是在模型學習能力較弱,而數據複雜度較高的情況出現,此時模型由於學習能力不足,無 法學習到數據集中的“一般規律”,因而導致泛化能力弱。
- 過擬合:是在模型學習能力過強的情況中出現,此時的模型學習能力太強,以至於將訓練單個樣本 自身的特定都能捕捉到,並將其認爲是“一般規律”,因而導致模型泛化能力下降
- 各自優缺點
欠擬合在訓練集和測試集上的性能都較差,而過擬合往往能較好地學習訓練集數據地性質,而在測試集上地性能較差。
-
欠擬合和過擬合解決辦法
1. 欠擬合的解決辦法: a. 增加輸入特徵項 b. 增減網絡 c. 減少正則化參數 2. 過擬合解決辦法: a. 數據清洗 b. 增大訓練集 c. 採用正則化 d. 增大正則化參數
-
正則化緩解過擬合
正則化在損失函數中引入模型複雜度指標,利用給w加權值,弱化了訓練數據的噪聲(一般不正則化b)
正則化的選擇:
1. L1正則化大概率會使很多參數變爲0,因此該方法可通過稀疏參數,即減少參數的數量,降低複雜度
2. L2正則化會使參數很接近零但不爲零,因此該方法可通過減小參數值的大小降低複雜度 -
案例:
#導入所需模塊 import tensorflow as tf from matplotlib import pyplot as plt import numpy as np import pandas as pd #讀入數據/標籤 生成x_train y_train df = pd.read_csv('dot.csv') x_data = np.array(df[['x1','x2']]) y_data = np.array(df['y_c']) x_train = np.vstack(x_data).reshape(-1,2) y_train = np.vstack(y_data).reshape(-1,1) Y_c = [['red' if y else 'blue'] for y in y_train] #轉換x的數據類型,否則後面矩陣相乘時會因數據類型問題報錯 x_train = tf.cast(x_train,tf.float32) y_train = tf.cast(y_train,tf.float32) #from_tensor_slices函數切分傳入張量的第一個維度,生成相應的數據集,使輸入特徵和標籤值一一對應 train_db = tf.data.Dataset.from_tensor_slices((x_train,y_train)).batch(32) #生成神經網絡參數,輸入層爲兩個神經單元,隱藏層爲11個神經元,1層隱藏層,輸出層爲1個神經元 w1 = tf.Variable(tf.random.normal([2,11]),dtype=tf.float32) b1 = tf.Variable(tf.constant(0.01, shape=[11])) w2 = tf.Variable(tf.random.normal([11,1]),dtype=tf.float32) b2 = tf.Variable(tf.constant(0.01, shape=[1])) lr = 0.01 #學習率 epoch = 400 #循環次數 #訓練部分 for epoch in range(epoch): for step,(x_train,y_train) in enumerate(train_db): with tf.GradientTape() as tape: #記錄梯度信息 h1 = tf.matmul(x_train,w1) + b1 #記錄神經網絡乘加運算 h1 = tf.nn.relu(h1) y = tf.matmul(h1,w2) + b2 #採用均方誤差損失函數mse = mean(sum(y-out)^2) loss_mse = tf.reduce_mean(tf.square(y_train - y)) #添加l2正則化 loss_regularization = [] #tf.nn.l2_loss(w) = sum(w ** 2) / 2 loss_regularization.append(tf.nn.l2_loss(w1)) loss_regularization.append(tf.nn.l2_loss(w2)) loss_regularization = tf.reduce_sum(loss_regularization) loss = loss_mse + 0.03 * loss_regularization #REGULARIZER = 0.03 #計算loss對各個參數的梯度 variables = [w1,b1,w2,b2] grads = tape.gradient(loss,variables) #實現梯度更新 #w1 = w1 - lr * w1_grad tape.gradient是自動求導結果與[w1,b1,w2,b2] 索引爲0,1,2,3 w1.assign_sub(lr * grads[0]) b1.assign_sub(lr * grads[1]) w2.assign_sub(lr * grads[2]) b2.assign_sub(lr * grads[3]) #每20個epoch,打印loss信息 if epoch % 20 == 0: print('epoch:',epoch,'loss:',float(loss)) #預測部分 print("**************predict*************") #xx在 -3到3之間步長爲0.01,yy在-3到3之間步長0.01,生成間隔數值點 xx,yy = np.mgrid[-3:3:.1,-3:3:.1] #將xx,yy拉直,併合並配對爲二維張量,生成二維座標點 grid = np.c_[xx.ravel(),yy.ravel()] grid = tf.cast(grid,tf.float32) #將網絡座標點喂入神經網絡,進行預測,probs爲輸出 probs = [] for x_test in grid: #使用訓練好的參數進行預測 h1 = tf.matmul([x_test],w1) + b1 h1 = tf.nn.relu(h1) y = tf.matmul(h1,w2) + b2 #y爲預測結果 probs.append(y) #取第0列給x1,取第一列給x2 x1 = x_data[:,0] x2 = x_data[:,1] #probs的shape調整成xx的樣子 probs = np.array(probs).reshape(xx.shape) #畫座標爲x1,x2的散點圖,顏色爲color squeeze去掉維度是1的維度,相當於[['red'],['blue']],內層括號變爲['red','blue'] plt.scatter(x1,x2,color = np.squeeze(Y_c)) #把座標xx yy和對應的值probs放入contour函數,給probs值爲0.5的所有點上色 plt點show後 顯示的是紅藍點的分界線 plt.contour(xx,yy,probs,levels=[.5]) plt.show()
-
正則化和沒有正則化的效果對比
下面的是筆者的微信公衆號,歡迎關注,會持續更新c++、python、tensorflow、機器學習、深度學習等系列文章