日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

PyTorch框架学习十六——正则化与Dropout

發布時間:2024/7/23 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 PyTorch框架学习十六——正则化与Dropout 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

PyTorch框架學習十六——正則化與Dropout

  • 一、泛化誤差
  • 二、L2正則化與權值衰減
  • 三、正則化之Dropout
  • 補充:

這次筆記主要關注防止模型過擬合的兩種方法:正則化與Dropout。

一、泛化誤差

一般模型的泛化誤差可以被分解為三部分:偏差、方差與噪聲。按照周志華老師西瓜書中的定義,這三者分別如下所示:

  • 偏差:度量學習算法的期望預測與真實結果的偏離程度,即刻畫了學習算法本身的擬合能力。
  • 方差:度量了同樣大小的訓練集的變動導致的學習性能的變化,刻畫了數據擾動所造成的影響。
  • 噪聲:表達了在當前任務上任何學習算法所能達到的期望泛化誤差的下界。
  • 這樣的表達可能不太好理解,下面給出了一張圖,幫助一下理解:

    二、L2正則化與權值衰減

    正則化是一種減小方差的策略,具體可以學習吳恩達老師的機器學習的視頻。

    損失函數衡量模型的輸出與真實標簽的差異,正則化使用的地方在目標函數,即在原來的代價函數的基礎上再加上正則化項。

  • L1正則化項:
  • L2正則化項:
    因為在實際使用中L2正則化使用的較多,所以這里重點介紹L2正則化。
  • L2正則化的目標函數如下所示:

    其中正則化項前的系數lambda/2,lambda調節正則化的程度,/2是為了反向傳播求導的時候和平方的2可以約掉。

    在反向傳播進行權值更新時,無正則化項和有正則化項的更新公式如下所示:

    一般lambda是在0到1之間的數,所以從上圖得知,有正則化時更新后的權值會比無正則化時更小一點,所以一般也將L2正則化稱為權值衰減(weight decay)。

    下面構建了兩個相同的網絡,一個沒有用正則化項,一個使用了正則化項,可以觀察它們各自的擬合效果:

    import torch import torch.nn as nn import matplotlib.pyplot as plt import sys, os from tools.common_tools import set_seed from torch.utils.tensorboard import SummaryWriterset_seed(1) # 設置隨機種子 n_hidden = 200 # 自定義一個全連接網絡,每層200個神經元 max_iter = 2000 # 最大迭代次數2000次 disp_interval = 200 # 繪圖的epoch間隔 lr_init = 0.01 # 初始化學習率# ============================ step 1/5 數據 ============================ # 構造一批虛擬的數據 def gen_data(num_data=10, x_range=(-1, 1)):w = 1.5train_x = torch.linspace(*x_range, num_data).unsqueeze_(1)train_y = w*train_x + torch.normal(0, 0.5, size=train_x.size())test_x = torch.linspace(*x_range, num_data).unsqueeze_(1)test_y = w*test_x + torch.normal(0, 0.3, size=test_x.size())return train_x, train_y, test_x, test_ytrain_x, train_y, test_x, test_y = gen_data(x_range=(-1, 1))# ============================ step 2/5 模型 ============================ class MLP(nn.Module):def __init__(self, neural_num):super(MLP, self).__init__()self.linears = nn.Sequential(nn.Linear(1, neural_num),nn.ReLU(inplace=True),nn.Linear(neural_num, neural_num),nn.ReLU(inplace=True),nn.Linear(neural_num, neural_num),nn.ReLU(inplace=True),nn.Linear(neural_num, 1),)def forward(self, x):return self.linears(x)# 實例化兩個上面構建的全連接網絡,用于比較 net_normal = MLP(neural_num=n_hidden) net_weight_decay = MLP(neural_num=n_hidden)# ============================ step 3/5 優化器 ============================ # net_normal 無正則化,net_weight_decay 有正則化,系數為1e-2 optim_normal = torch.optim.SGD(net_normal.parameters(), lr=lr_init, momentum=0.9) optim_wdecay = torch.optim.SGD(net_weight_decay.parameters(), lr=lr_init, momentum=0.9, weight_decay=1e-2)# ============================ step 4/5 損失函數 ============================ loss_func = torch.nn.MSELoss()# ============================ step 5/5 迭代訓練 ============================ writer = SummaryWriter(comment='_test_tensorboard', filename_suffix="12345678")for epoch in range(max_iter):# forwardpred_normal, pred_wdecay = net_normal(train_x), net_weight_decay(train_x)loss_normal, loss_wdecay = loss_func(pred_normal, train_y), loss_func(pred_wdecay, train_y)optim_normal.zero_grad()optim_wdecay.zero_grad()loss_normal.backward()loss_wdecay.backward()optim_normal.step()optim_wdecay.step()if (epoch+1) % disp_interval == 0:# 可視化for name, layer in net_normal.named_parameters():writer.add_histogram(name + '_grad_normal', layer.grad, epoch)writer.add_histogram(name + '_data_normal', layer, epoch)for name, layer in net_weight_decay.named_parameters():writer.add_histogram(name + '_grad_weight_decay', layer.grad, epoch)writer.add_histogram(name + '_data_weight_decay', layer, epoch)test_pred_normal, test_pred_wdecay = net_normal(test_x), net_weight_decay(test_x)# 繪圖plt.scatter(train_x.data.numpy(), train_y.data.numpy(), c='blue', s=50, alpha=0.3, label='train')plt.scatter(test_x.data.numpy(), test_y.data.numpy(), c='red', s=50, alpha=0.3, label='test')plt.plot(test_x.data.numpy(), test_pred_normal.data.numpy(), 'r-', lw=3, label='no weight decay')plt.plot(test_x.data.numpy(), test_pred_wdecay.data.numpy(), 'b--', lw=3, label='weight decay')plt.text(-0.25, -1.5, 'no weight decay loss={:.6f}'.format(loss_normal.item()), fontdict={'size': 15, 'color': 'red'})plt.text(-0.25, -2, 'weight decay loss={:.6f}'.format(loss_wdecay.item()), fontdict={'size': 15, 'color': 'red'})plt.ylim((-2.5, 2.5))plt.legend(loc='upper left')plt.title("Epoch: {}".format(epoch+1))plt.show()plt.close()

    最終的擬合效果:

    紅色的線顯然已經過擬合了,而藍色的線加了正則化項,比紅色的線的效果好一點,這就是L2正則化項緩解過擬合的一個舉例。

    因為在代碼中使用了TensorBoard可視化每一網絡層的權重,可以看一下有無正則化兩種情況下權值分布的差異:

    可以看出不加正則化時,權值是比較分散的,而且存在較大的值,加入正則化之后,權值的分布都集中在較小值的范圍,不存在較大的權值,這也是減輕過擬合的體現。

    三、正則化之Dropout

    Dropout的概念發揚光大于AlexNet之中,簡單來說就是對網絡中的每個神經元進行隨機失活。

    • 隨機:有一個失活概率Dropout probability。
    • 失活:該神經元對應的權值為0,即該神經元不與其他神經元連接。

    如下圖所示就是一次隨機失活的情況:

    訓練過程的每個epoch得到的失活后的網絡都不一樣,這樣使得模型具有多樣性,不會特別依賴某些固定的神經元,不會使得某些神經元的權重過大,緩解了過擬合的問題。

    注意:Dropout是在訓練過程進行隨機失活,在測試的時候是恢復為原來的網絡結構的,所以測試的時候,要將所有的權重乘以1-Dropout probability,以保持輸入與權值相乘的結果與訓練時一樣大。

    下面我們看一下在PyTorch中Dropout的實現:

    torch.nn.Dropout(p: float = 0.5, inplace: bool = False)

    參數如下:

    主要就是一個失活概率p,默認為0.5。

    然后需要注意的是,PyTorch在實現Dropout的時候,訓練時權重均乘以了1/(1-p),即除以1-p,這樣的話測試的時候就不用手動將所有的權重乘以1-Dropout probability了,方便了測試的過程。

    用上面L2正則化的代碼示例稍加修改作為Dropout的舉例:

    import torch import torch.nn as nn import matplotlib.pyplot as plt import sys, os from tools.common_tools import set_seed from torch.utils.tensorboard import SummaryWriterset_seed(1) # 設置隨機種子 n_hidden = 200 max_iter = 2000 disp_interval = 400 lr_init = 0.01# ============================ step 1/5 數據 ============================ def gen_data(num_data=10, x_range=(-1, 1)):w = 1.5train_x = torch.linspace(*x_range, num_data).unsqueeze_(1)train_y = w*train_x + torch.normal(0, 0.5, size=train_x.size())test_x = torch.linspace(*x_range, num_data).unsqueeze_(1)test_y = w*test_x + torch.normal(0, 0.3, size=test_x.size())return train_x, train_y, test_x, test_ytrain_x, train_y, test_x, test_y = gen_data(x_range=(-1, 1))# ============================ step 2/5 模型 ============================ class MLP(nn.Module):def __init__(self, neural_num, d_prob=0.5):super(MLP, self).__init__()self.linears = nn.Sequential(nn.Linear(1, neural_num),nn.ReLU(inplace=True),nn.Dropout(d_prob),nn.Linear(neural_num, neural_num),nn.ReLU(inplace=True),nn.Dropout(d_prob),nn.Linear(neural_num, neural_num),nn.ReLU(inplace=True),nn.Dropout(d_prob),nn.Linear(neural_num, 1),)def forward(self, x):return self.linears(x)net_prob_0 = MLP(neural_num=n_hidden, d_prob=0.) net_prob_05 = MLP(neural_num=n_hidden, d_prob=0.5)# ============================ step 3/5 優化器 ============================ optim_normal = torch.optim.SGD(net_prob_0.parameters(), lr=lr_init, momentum=0.9) optim_reglar = torch.optim.SGD(net_prob_05.parameters(), lr=lr_init, momentum=0.9)# ============================ step 4/5 損失函數 ============================ loss_func = torch.nn.MSELoss()# ============================ step 5/5 迭代訓練 ============================writer = SummaryWriter(comment='_test_tensorboard', filename_suffix="12345678") for epoch in range(max_iter):pred_normal, pred_wdecay = net_prob_0(train_x), net_prob_05(train_x)loss_normal, loss_wdecay = loss_func(pred_normal, train_y), loss_func(pred_wdecay, train_y)optim_normal.zero_grad()optim_reglar.zero_grad()loss_normal.backward()loss_wdecay.backward()optim_normal.step()optim_reglar.step()if (epoch+1) % disp_interval == 0:net_prob_0.eval()net_prob_05.eval()# 可視化for name, layer in net_prob_0.named_parameters():writer.add_histogram(name + '_grad_normal', layer.grad, epoch)writer.add_histogram(name + '_data_normal', layer, epoch)for name, layer in net_prob_05.named_parameters():writer.add_histogram(name + '_grad_regularization', layer.grad, epoch)writer.add_histogram(name + '_data_regularization', layer, epoch)test_pred_prob_0, test_pred_prob_05 = net_prob_0(test_x), net_prob_05(test_x)# 繪圖plt.clf()plt.scatter(train_x.data.numpy(), train_y.data.numpy(), c='blue', s=50, alpha=0.3, label='train')plt.scatter(test_x.data.numpy(), test_y.data.numpy(), c='red', s=50, alpha=0.3, label='test')plt.plot(test_x.data.numpy(), test_pred_prob_0.data.numpy(), 'r-', lw=3, label='d_prob_0')plt.plot(test_x.data.numpy(), test_pred_prob_05.data.numpy(), 'b--', lw=3, label='d_prob_05')plt.text(-0.25, -1.5, 'd_prob_0 loss={:.8f}'.format(loss_normal.item()), fontdict={'size': 15, 'color': 'red'})plt.text(-0.25, -2, 'd_prob_05 loss={:.6f}'.format(loss_wdecay.item()), fontdict={'size': 15, 'color': 'red'})plt.ylim((-2.5, 2.5))plt.legend(loc='upper left')plt.title("Epoch: {}".format(epoch+1))plt.show()plt.close()net_prob_0.train()net_prob_05.train()

    做的修改就是網絡模型里加入了Dropout層,刪去了L2正則化項,然后實例化了兩個模型,一個失活概率為0,即等效為不加Dropout層,一個失活概率為0.5,即加入Dropout層,將這兩個模型進行數據擬合,觀察結果如下:

    也可以看出,Dropout層的加入也一定程度上緩解了過擬合。

    同樣,我們也來看一下這時的權值分布,因為第一層是輸入層,沒有加Dropout層,所以我們看第三層的權值分布(第二層為ReLU層):

    也有類似的作用——收縮權重。

    補充:

    在使用Dropout層,以及后面要講的BN層這些東西時,還有一個需要注意的小細節,因為這些層在訓練模式和測試模式是有差別的,所以在不同時刻需要切換模式,用到的就是上面代碼中的

    net_prob_0.eval() net_prob_05.eval()

    以及:

    net_prob_0.train() net_prob_05.train()

    總結

    以上是生活随笔為你收集整理的PyTorch框架学习十六——正则化与Dropout的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。