31,32,33_过拟合、欠拟合的概念、L2正则化,Pytorch过拟合欠拟合,交叉验证-Train-Val-Test划分,划分训练集和测试集,K-fold,Regularization
1.26.過擬合、欠擬合及其解決方案
1.26.1.過擬合、欠擬合的概念
1.26.1.1.訓練誤差和泛化誤差
1.26.1.2.驗證數據集與K-fold驗證
1.26.1.3.過擬合和欠擬合
1.26.1.4.導致過擬合和欠擬合的關鍵因素
1.26.2.L2正則化
1.26.3.drop out
1.27.Pytorch過擬合&欠擬合
1.27.1.理想化情況
1.27.1.1.場景一:線性模型—房價預測
1.27.1.2.場景二:非線性模型—GPA
1.27.2.真實情況
1.27.3.模型學習能力
1.27.4.欠擬合與過擬合
1.28.Train-Val-Test劃分
1.28.1.1.How to detect(如何檢測)
1.28.1.2.Splitting(劃分訓練集和測試集)
1.28.1.3.for example
1.28.1.4.test while train
1.28.1.5.train test trade-off
1.28.1.6.for others judge
1.28.1.7.train-val-test
1.28.1.8.K-fold cross-validation
1.28.1.9.k-fold cross validation
1.26.過擬合、欠擬合及其解決方案
1.26.1.過擬合、欠擬合的概念
1.26.1.1.訓練誤差和泛化誤差
前者指模型在訓練數據集上表現出的誤差,后者模型在任意一個測試數據樣本上表現的誤差的期望,并常常通過測試數據集上的誤差來近似。
1.26.1.2.驗證數據集與K-fold驗證
預留一部分在訓練數據集和測試數據集以外的數據來進行模型選擇,這部分數據被稱為驗證數據集,簡稱驗證集(validation set)。在K折交叉驗證中,把原始訓練數據集分割成K個不重合的子數據集,然后做K次模型訓練和驗證。每一次,使用一個子數據集驗證模型,并使用其他K-1個子數據集來訓練模型。在這K次訓練和驗證中,每次用來驗證模型的子數據集都不同。最后,對這K次訓練誤差和驗證誤差分別求平均。
1.26.1.3.過擬合和欠擬合
欠擬合:模型無法得到較低的訓練誤差。
過擬合:模型的訓練誤差遠小于它在測試數據集上的誤差。
1.26.1.4.導致過擬合和欠擬合的關鍵因素
?數據集大小:影響欠擬合和過擬合的另一個重要因素是訓練數據集的大小。一般來說,如果訓練數據集中樣本數過少,特別是比模型參數數量(按元素計)更少時,過擬合更容易發生。此外,泛化誤差不會隨訓練數據集里樣本數量增加而減小。因此,在計算資源允許的范圍之內,通常希望訓練數據集大一些,特別是在模型復雜度較高時,例如層數較多的深度學習模型。
?模型復雜程度:
1.26.2.L2正則化
1.26.3.drop out
1.27.Pytorch過擬合&欠擬合
1.27.1.理想化情況
1.27.1.1.場景一:線性模型—房價預測
橫坐標是房屋面積,縱坐標是房屋價格。可以看出這兩者呈現線性關系。
1.27.1.2.場景二:非線性模型—GPA
老師給學生打分時,往往大部分學生一般的成績,成績差或成績好的則占少數。因此總體上趨近于高斯模型,呈現非線性關系。
1.27.2.真實情況
從以上兩個例子中,我們都已經提前知道了問題中的具體模型,不知道的只有模型的參數,如期望,方差。然而在現實生活中,大部分要解決的問題是不知道具體模型的。如手寫數字識別,我們既不知道它的模型,也不知道里面需要包含什么參數。那么如何解決這個問題呢?
另外我們還要考慮另一個因素的影響:噪聲。并不是所有的數據集都是嚴格按照模型的。如房價關系的線性模型,房價與面積在呈線性關系的同時往往有些許誤差。我們可以認為誤差服從高斯分布,因此為了盡量減少誤差的影響,我們需要大量的數據集來訓練模型。同時,如果數據集太少,可能被誤認為不滿足線性關系,而采用其他關系進行預測。
1.27.3.模型學習能力
我們對利用數據訓練模型時,往往會選擇不同的模型,可能一次方,二次方。。。到n次方,不同類型,不同次方的模型,次方越高,模型波動越大越復雜。
那么如何衡量不同模型的學習能力?
可以看出,只有一個參數的常數函數,學習能力最差,輸出的是固定值,隨著次方增加,參數越來越多,學習能力越來越強。
最近的深度學習網絡層次越來越深,參數也越來越大,也從側面反映出模型的model capacity越來越強。
1.27.4.欠擬合與過擬合
接下來我們觀察兩種情況:
情況一:欠擬合
我們用的模型復雜度小于真實數據模型的復雜度,就好像利用線性模型去預測非線性模型的GPA函數。這種情況會造成模型的表達能力不夠,無法表達真實數據模型,這種情況叫做欠擬合。
再舉一個WGAN的例子,早期的WGAN對模型加了許多約束,導致生成的數據表達能力不夠強,上面三幅圖無法像下面三幅圖一樣表達許多精美的圖片。
那么欠擬合如何體現出來,我們如何發現模型出現欠擬合?
訓練集準確度低
測試集準確度低
情景二:過擬合
我們訓練出的模型為了擬合所有數據變得過分復雜,為了降低loss,模型趨近于每一個點,訓練模型復雜度大于真實數據集復雜度,這樣會導致在訓練集上的效果非常好,但是在測試集上的效果不好,這種情況叫做過擬合。
那么過擬合如何體現出來,我們如何發現模型出現過擬合?
上面的圖分別表示:欠擬合,適配良好,過擬合
1.28.Train-Val-Test劃分
1.28.1.1.How to detect(如何檢測)
1.28.1.2.Splitting(劃分訓練集和測試集)
合理的 Train/Test 集劃分會有效地減少 under-fitting 和 over-fitting 現象
以數字識別為例,正常一個數據集我們要劃分出來訓練部分和測試部分,如下圖所示:
左側橘色部分作為訓練部分,神經網路在該區域內不停地學習,將特征轉入到函數中,學習好后得到一個函數模型。隨后將上圖右面白色區域的測試部分導入到該模型中,進行accuracy和loss的驗證
通過不斷地測試,查看模型是否調整到了一個最佳的參數,及結果是否發生了over-fitting現象。
1.28.1.3.for example
import torch import torch.nn as nn import torch.nn.functional as F import torch.optim as optim from torchvision import datasets, transformsbatch_size=200 learning_rate=0.01 epochs=10# 使用 train=True 或 train=False來進行數據集的劃分 # train=True時為訓練集,相反即為測試集 train_db = datasets.MNIST('../data', train=True, download=True,transform=transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.1307,), (0.3081,))]))# 訓練-測試代碼寫法 # 一般使用DataLoader函數來讓機器學習或測試 train_loader = torch.utils.data.DataLoader(train_db,batch_size=batch_size, shuffle=True)test_db = datasets.MNIST('../data', train=False, transform=transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.1307,), (0.3081,)) ])) test_loader = torch.utils.data.DataLoader(test_db,batch_size=batch_size, shuffle=True)1.28.1.4.test while train
1.28.1.5.train test trade-off
1.28.1.6.for others judge
其實正常情況下除了Train Set和挑選最佳參數的Test Set外,一般還要有Validation Set。
Val Set代替Test Set的功能,而Test Set則要交給客戶,進行實際驗證,正常情況下Test Set是不加入到測試中的
說個很具體的場景,就比方說 Kaggle 競賽中,比賽的主辦方給你訓練的數據集,一般我們拿來都會自己分成 Train Set 和 Val Set 兩部分,用 Train Set 訓練,Val Set 挑選最佳參數,訓練好以后提交模型,此時主辦方會用它自己的數據集,即 Test Set 去測試你的模型,得到一個 Score。
從上面的過程能看出,Val Set可以理解為是從Train Set找拆出來的一部分,而與Test Set沒有關系
# 這里注意,正常情況下數據集是要有validation(驗證)集的,若沒有設置,即將test和val集合并為一個了 # 這里注意,正常情況下數據集是要有validation(驗證)集的,若沒有設置,即將test和val集合并為一個了 print('train:', len(train_db), 'test:', len(test_db)) # 首先先查看train和test數據集的數量,看看是否滿足預訂的分配目標 # 隨機分配法將數據分為50k和10k的數量 train_db, val_db = torch.utils.data.random_split(train_db, [50000, 10000]) print('db1:', len(train_db), 'db2:', len(val_db)) train_loader = torch.utils.data.DataLoader(train_db,batch_size=batch_size, shuffle=True) val_loader = torch.utils.data.DataLoader(val_db,batch_size=batch_size, shuffle=True)1.28.1.7.train-val-test
1.28.1.8.K-fold cross-validation
1.28.1.9.k-fold cross validation
?hold-out(留出法)
直接將數據集劃分為兩個互斥的集合
但是這種方法,只有新劃分的訓練集會參與到backward過程中
?K-fold cross-validation(K拆交叉驗證)
即把數據分成K份,每次拿出一份作為驗證集,剩下k-1份作為訓練集,重新K次。最后平均K次的結果,作為誤差評估的結果。
這種方法可以將驗證集充分利用起來,從而使得每個數據集都可以參與backward過程中。
不過這種方法對模型的提升有限,畢竟數據集并沒有增加。
1.30.Regularization
為了解決torch.optim優化器只能實現L2正則化以及懲罰網絡中的所有參數的缺陷,這里實現類似于TensorFlow正則化的方法。
1.30.1.自定義正則化Regularization類
這里封裝成一個實現正則化的Regularization類,各個方法都給出了注釋。
# -*- coding: UTF-8 -*-import torch# 檢查GPU是否可用 device = torch.device("cuda" if torch.cuda.is_available() else "cpu") # device='cuda' print("--------device:{}".format(device)) print("--------Pytorch version:{}".format(torch.__version__))class Regularization(torch.nn.Module):def __init__(self, model, weight_decay, p=2):''':param model 模型:param weight_decay: 正則化參數:param p: 范數計算中的冪指數值,默認求2范數,當p=0為L2正則化,p=1為L1正則化'''super(Regularization, self).__init__()if weight_decay <= 0:print("param weight_decay can not <=0")exit(0)self.model = modelself.weight_decay = weight_decayself.p = pself.weight_list = self.get_weight(model)self.weight_info(self.weight_list)def to(self, device):'''指定運行模式:param device: cuda or cpu:return:'''self.device = devicesuper().to(device)return selfdef get_weight(self, model):'''獲得模型的權重列表:param model::return:'''weight_list = []for name, param in model.named_parameters():if 'weight' in name:weight = (name, param)weight_list.append(weight)return weight_listdef regularization_loss(self, weight_list, weight_decay, p=2):'''計算張量范數:param weight_list::param weight_decay::param p: 范數計算中的冪指數值,默認求2范數:return:'''reg_loss = 0for name, w in weight_list:l2_reg = torch.norm(w, p=p)reg_loss = reg_loss + l2_regreg_loss = weight_decay * reg_lossreturn reg_lossdef weight_info(self, weight_list):'''打印權重列表信息:param weight_list::return:'''print("-------regularization weight--------")for name, w in weight_list:print(name)print("------------------------------------")def forward(self, model):# 獲得最新的權重self.weight_list = self.get_weight(model)reg_loss = self.regularization_loss(self.weight_list, self.weight_decay, p=self.p)return reg_loss1.30.2.Regularization使用方法
使用方法很簡單,就當一個普通Pytorch模塊來使用,例如:
# 檢查GPU是否可用 device = torch.device("cuda" if torch.cuda.is_available() else "cpu")print("------device:{}".format(device)) print("------Pytorch version:{}".format(torch.__version__))weight_decay = 100.0 #正則化參數 learning_rate=0.01model = Regularization().to(device) # 初始化正則化 if weight_decay > 0:reg_loss = Regularization(model, weight_decay, p=2).to(device) else:print("no regularization")# CrossEntropyLoss=softmax+cross entropy criterion = nn.CrossEntropyLoss().to(device) # 不需要指定參數weight_decay optimizer = optim.Adam(model.parameters(), lr=learning_rate)# train batch_train_data = ... batch_train_label = ...out = model(batch_train_data)# loss and regularization loss = criterion(input=out, target=batch_train_label) if weight_decay > 0:loss = loss + reg_loss(model) total_loss = loss.item()# backprop # 清除當前所有的累積梯度 optimizer.zero_grad() total_loss.backward() optimizer.step()訓練時輸出的 loss和Accuracy信息:
(1)當weight_decay=0.0時,未使用正則化
(2)當weight_decay=10.0時,使用正則化
(3)當weight_decay=10000.0時,使用正則化
對比torch.optim優化器的實現L2正則化方法,這種Regularization類的方法也同樣達到正則化的效果,并且與TensorFlow類似,loss把正則化的損失也計算了。
此外更改參數p,如當p=0表示L2正則化,p=1表示L1正則化。
總結
以上是生活随笔為你收集整理的31,32,33_过拟合、欠拟合的概念、L2正则化,Pytorch过拟合欠拟合,交叉验证-Train-Val-Test划分,划分训练集和测试集,K-fold,Regularization的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 从凤阳三步两桥去中医院坐几路车?
- 下一篇: 奔驰唯雅诺左边右边出风口无冷风怎么办你好