神經網絡的復雜度
1.空間復雜度
層數 = 隱藏層的層數 + 1個輸出層
總參數 = 總w + 總b
2.時間復雜度
乘加運算次數 = 總w
指數衰減學習率
學習率lr表征了參數每次更新的幅度,設置過小,參數更新會很慢,設置過大,參數不容易收斂。
在實際應用中,可以先使用較大學習率,快速找到較優值,然后逐步減小學習率,使模型找到最優解。
比如,指數衰減學習率。
指數衰減學習率 = 初始學習率 * 學習率衰減率^(當前輪數/多少輪衰減一次)
- 初始學習率:最初設置的學習率。
- 學習率衰減率:學習率按照這個比例指數衰減。
- 當前輪數:可以用 epoch 表示(當前迭代了多少次數據集),也可以用 step 表示(當前迭代了多少次batch)。
- 多少輪衰減一次:迭代多少次更新一次學習率,決定了學習率更新的頻率。
# 例:
# 數據集迭代次數
epoch = 50
# 初始學習率 lr_base = 0.2
# 學習率衰減率 lr_decay = 0.99
# 多少輪衰減一次 lr_step = 1
for epoch in range(epoch):
# 指數衰減學習率 lr = lr_base * lr_decay ** (epoch/lr_step)
# 參數求導 with tf.GradientTape() as tape: loss = tf.square(w + 1)
grads = tape.gradient(loss, w)
# 參數自更新 w.assign_sub(lr * grads)
激活函數
線性函數表達力不夠,加入非線性函數(激活函數),使得神經網絡可以隨層數的增加提升表達力。
優秀的激活函數需要滿足:
- 非線性:只有當激活函數是非線性時,才不會被單層網絡所替代,使多層網絡有了意義。
- 可微性:優化器大多使用梯度下降法更新參數,若激活函數不可微(不可求導),就不能更新參數。
- 單調性:當激活函數是單調的,能保證單層網絡的損失函數是凸函數,更容易收斂。
- 近似恆等性:f(x) ≈ x,這樣的神經網絡更穩定。
激活函數輸出值
- 如果激活函數的輸出是有限值,權重對特征的影響會更顯著,用梯度下降的方法更新參數會更穩定。
- 如果激活函數的輸出是無限值,參數的初始值對模型的影響非常大,建議使用更小的學習率。
幾種常見的激活函數
Sigmoid 激活函數
tf.nn.sigmoid(x)
Tanh 激活函數
tf.nn.tanh(x)
Relu 激活函數
tf.nn.relu(x)
Leaky Relu 激活函數
tf.nn.leaky_relu(x)
對初學者的建議:
- 首選 relu 激活函數。
- 學習率設置較小值。
- 輸入特征標准化,即讓輸入特征滿足以0為均值,1為標准差的正態分布。
- 初始參數中心化,即讓隨機生成的參數滿足以0為均值,√(2/當前層輸入特征個數) 為標差的正態分布。
損失函數loss
損失函數,即前向傳播預測結果 y 與已知標准答案 y_ 的差距。
神經網絡的優化目標就是找到某套參數,使得預測結果與標准答案無限接近,即 loss 值最小。
主流loss有三種:
均方誤差
loss = tf.reduce_mean(tf.square(y_ - y))
自定義
loss = tf.reduce_mean(tf.where(條件語句, 真返回A, 假返回B))
交叉熵
交叉熵越大,兩個概率分布越遠
交叉熵越小,兩個概率分布越近
y_pro = y.nn.softmax(y)
tf.losses.categorical_crossentropy(y_, y_pro)
執行分類問題時,通常先用 softmax 函數使輸出結果符合概率分布,再求交叉熵損失函數。
tensorflow給出了同時計算概率分布和交叉熵的函數:
tf.nn.softmax_cross_entropy_with_logits(y_, y)
欠擬合與過擬合
欠擬合:模型不能有效擬合數據集,對現有數據集學習不夠徹底。
過擬合:模型對數據擬合太好,但對新數據難以做出判斷,缺乏泛化力。
網絡訓練過程中會遇到的情況:
loss 是訓練集的損失值,val_loss 是測試集的損失值。
loss 不斷下降,val_loss 不斷下降:網絡仍在學習;(最好情況)
loss 不斷下降,val_loss 趨於不變:網絡過擬合;(增大數據集 || 正則化)
loss 趨於不變,val_loss 不斷下降:數據集有問題;(檢查dataset)
loss 趨於不變,val_loss 趨於不變:學習遇到瓶頸;(減少學習率 || 減少批量數目)
loss 不斷上升,val_loss 不斷上升:網絡結構設計或訓練超參數設置不當,數據集經過清洗等問題。(最壞情況)
欠擬合的解決方法:
- 增加輸入特征項
- 增加網絡參數
- 減少正則化參數
過擬合的解決方法:
- 數據清洗
- 增大訓練集
- 采用正則化
- 增大正則化參數
正則化減少過擬合:
正則化,就是在損失函數中引入模型復雜度指標,給每個參數 w 加上權重,抑制訓練中的噪聲。
正則化通常只對參數 w 使用,不對偏置 b 使用。
loss = loss(y_, y) + regularizer * loss(w)
loss(y_, y):以前求得的 loss 值。
regularizer:參數 w 在總 loss 中的比重.
loss(w):
- 對所有參數 w 求和(L1正則化:大概率會使很多參數變為0,可用來稀疏參數,降低模型復雜度)
- 對所有參數 w 的平方求和(L2正則化:會使參數接近0但不等於0,可用來減小參數的數值,有效緩解數據集中因噪聲引起的過擬合)
# 例: with tf.GradientTape() as tape:
...
# 原始 loss loss_mse = tf.reduce_mean(tf.square(y_ - y)) # 用來寄存所有參數 w L2正則化后的結果 loss_regularization = [] # 將所有參數 w 做 L2正則化處理,並存在loss_regularization中 loss_regularization.append(tf.nn.l2_loss(w1)) loss_regularization.append(tf.nn.l2_loss(w2)) # 計算所有參數 w L2正則化后的總和 loss_regularization = tf.reduce_sum(loss_regularization) # 正則化 loss = loss_mse + 0.03 * loss_regularization # 對各參數求導 grads = tape.gradient(loss, [w1, b1, w2, b2]) # 參數自更新 w1.assign_sub(lr * grads[0]) b1.assign_sub(lr * grads[1]) w2.assign_sub(lr * grads[2]) b2.assign_sub(lr * grads[3])
...
優化器更新網絡參數
借鑒博客:
https://www.cnblogs.com/niulang/p/11752605.html