3.11 模型選擇描焰、欠擬合和過擬合
在前幾節(jié)基于Fashion-MNIST數(shù)據(jù)集的實驗中瘫证,我們評價了機器學習模型在訓練數(shù)據(jù)集和測試數(shù)據(jù)集上的表現(xiàn)咐容。如果你改變過實驗中的模型結(jié)構(gòu)或者超參數(shù)舆逃,你也許發(fā)現(xiàn)了:當模型在訓練數(shù)據(jù)集上更準確時,它在測試數(shù)據(jù)集上卻不一定更準確戳粒。這是為什么呢路狮?
3.11.1 訓練誤差和泛化誤差
在解釋上述現(xiàn)象之前,我們需要區(qū)分訓練誤差(training error)和泛化誤差(generalization error)蔚约。通俗來講奄妨,前者指模型在訓練數(shù)據(jù)集上表現(xiàn)出的誤差,后者指模型在任意一個測試數(shù)據(jù)樣本上表現(xiàn)出的誤差的期望苹祟,并常常通過測試數(shù)據(jù)集上的誤差來近似砸抛。計算訓練誤差和泛化誤差可以使用之前介紹過的損失函數(shù),例如線性回歸用到的平方損失函數(shù)和softmax回歸用到的交叉熵損失函數(shù)树枫。
讓我們以高考為例來直觀地解釋訓練誤差和泛化誤差這兩個概念直焙。訓練誤差可以認為是做往年高考試題(訓練題)時的錯誤率,泛化誤差則可以通過真正參加高考(測試題)時的答題錯誤率來近似砂轻。假設(shè)訓練題和測試題都隨機采樣于一個未知的依照相同考綱的巨大試題庫奔誓。如果讓一名未學習中學知識的小學生去答題,那么測試題和訓練題的答題錯誤率可能很相近搔涝。但如果換成一名反復練習訓練題的高三備考生答題厨喂,即使在訓練題上做到了錯誤率為0和措,也不代表真實的高考成績會如此。
在機器學習里杯聚,我們通常假設(shè)訓練數(shù)據(jù)集(訓練題)和測試數(shù)據(jù)集(測試題)里的每一個樣本都是從同一個概率分布中相互獨立地生成的臼婆。基于該獨立同分布假設(shè)幌绍,給定任意一個機器學習模型(含參數(shù))颁褂,它的訓練誤差的期望和泛化誤差都是一樣的。例如傀广,如果我們將模型參數(shù)設(shè)成隨機值(小學生)颁独,那么訓練誤差和泛化誤差會非常相近。但我們從前面幾節(jié)中已經(jīng)了解到伪冰,模型的參數(shù)是通過在訓練數(shù)據(jù)集上訓練模型而學習出的誓酒,參數(shù)的選擇依據(jù)了最小化訓練誤差(高三備考生)。所以贮聂,訓練誤差的期望小于或等于泛化誤差靠柑。也就是說,一般情況下吓懈,由訓練數(shù)據(jù)集學到的模型參數(shù)會使模型在訓練數(shù)據(jù)集上的表現(xiàn)優(yōu)于或等于在測試數(shù)據(jù)集上的表現(xiàn)歼冰。由于無法從訓練誤差估計泛化誤差,一味地降低訓練誤差并不意味著泛化誤差一定會降低耻警。
機器學習模型應關(guān)注降低泛化誤差隔嫡。
3.11.2 模型選擇
在機器學習中,通常需要評估若干候選模型的表現(xiàn)并從中選擇模型甘穿。這一過程稱為模型選擇(model selection)腮恩。可供選擇的候選模型可以是有著不同超參數(shù)的同類模型温兼。以多層感知機為例秸滴,我們可以選擇隱藏層的個數(shù),以及每個隱藏層中隱藏單元個數(shù)和激活函數(shù)募判。為了得到有效的模型缸榛,我們通常要在模型選擇上下一番功夫。下面兰伤,我們來描述模型選擇中經(jīng)常使用的驗證數(shù)據(jù)集(validation data set)。
3.11.2.1 驗證數(shù)據(jù)集
從嚴格意義上講钧排,測試集只能在所有超參數(shù)和模型參數(shù)選定后使用一次敦腔。不可以使用測試數(shù)據(jù)選擇模型,如調(diào)參恨溜。由于無法從訓練誤差估計泛化誤差符衔,因此也不應只依賴訓練數(shù)據(jù)選擇模型找前。鑒于此,我們可以預留一部分在訓練數(shù)據(jù)集和測試數(shù)據(jù)集以外的數(shù)據(jù)來進行模型選擇判族。這部分數(shù)據(jù)被稱為驗證數(shù)據(jù)集躺盛,簡稱驗證集(validation set)。例如形帮,我們可以從給定的訓練集中隨機選取一小部分作為驗證集槽惫,而將剩余部分作為真正的訓練集。
然而在實際應用中辩撑,由于數(shù)據(jù)不容易獲取界斜,測試數(shù)據(jù)極少只使用一次就丟棄。因此合冀,實踐中驗證數(shù)據(jù)集和測試數(shù)據(jù)集的界限可能比較模糊各薇。從嚴格意義上講,除非明確說明君躺,否則本書中實驗所使用的測試集應為驗證集峭判,實驗報告的測試結(jié)果(如測試準確率)應為驗證結(jié)果(如驗證準確率)。
3.11.2.3 K折交叉驗證
3.11.3 欠擬合和過擬合
接下來棕叫,我們將探究模型訓練中經(jīng)常出現(xiàn)的兩類典型問題:一類是模型無法得到較低的訓練誤差林螃,我們將這一現(xiàn)象稱作欠擬合(underfitting);另一類是模型的訓練誤差遠小于它在測試數(shù)據(jù)集上的誤差谍珊,我們稱該現(xiàn)象為過擬合(overfitting)治宣。在實踐中,我們要盡可能同時應對欠擬合和過擬合砌滞。雖然有很多因素可能導致這兩種擬合問題侮邀,在這里我們重點討論兩個因素:模型復雜度和訓練數(shù)據(jù)集大小。
關(guān)于模型復雜度和訓練集大小對學習的影響的詳細理論分析可參見我寫的這篇博客贝润。
3.11.3.1 模型復雜度
因為高階多項式函數(shù)模型參數(shù)更多绊茧,模型函數(shù)的選擇空間更大,所以高階多項式函數(shù)比低階多項式函數(shù)的復雜度更高打掘。因此华畏,高階多項式函數(shù)比低階多項式函數(shù)更容易在相同的訓練數(shù)據(jù)集上得到更低的訓練誤差。給定訓練數(shù)據(jù)集尊蚁,模型復雜度和誤差之間的關(guān)系通常如圖3.4所示亡笑。給定訓練數(shù)據(jù)集,如果模型的復雜度過低横朋,很容易出現(xiàn)欠擬合仑乌;如果模型復雜度過高,很容易出現(xiàn)過擬合。應對欠擬合和過擬合的一個辦法是針對數(shù)據(jù)集選擇合適復雜度的模型晰甚。
3.11.3.2 訓練數(shù)據(jù)集大小
影響欠擬合和過擬合的另一個重要因素是訓練數(shù)據(jù)集的大小衙传。一般來說,如果訓練數(shù)據(jù)集中樣本數(shù)過少厕九,特別是比模型參數(shù)數(shù)量(按元素計)更少時蓖捶,過擬合更容易發(fā)生。此外扁远,泛化誤差不會隨訓練數(shù)據(jù)集里樣本數(shù)量增加而增大俊鱼。因此,在計算資源允許的范圍之內(nèi)穿香,我們通常希望訓練數(shù)據(jù)集大一些亭引,特別是在模型復雜度較高時,例如層數(shù)較多的深度學習模型皮获。
3.11.4 多項式函數(shù)擬合實驗
為了理解模型復雜度和訓練數(shù)據(jù)集大小對欠擬合和過擬合的影響焙蚓,下面我們以多項式函數(shù)擬合為例來實驗。首先導入實驗需要的包或模塊洒宝。
%matplotlib inline
import torch
import numpy as np
import sys
sys.path.append("..")
import d2lzh_pytorch as d2l
3.11.4.1 生成數(shù)據(jù)集
n_train, n_test, true_w, true_b = 100, 100, [1.2, -3.4, 5.6], 5
features = torch.randn((n_train + n_test, 1))
poly_features = torch.cat((features, torch.pow(features, 2), torch.pow(features, 3)), 1)
labels = (true_w[0] * poly_features[:, 0] + true_w[1] * poly_features[:, 1]
+ true_w[2] * poly_features[:, 2] + true_b)
labels += torch.tensor(np.random.normal(0, 0.01, size=labels.size()), dtype=torch.float)
看一看生成的數(shù)據(jù)集的前兩個樣本购公。
features[:2], poly_features[:2], labels[:2]
輸出:
(tensor([[-1.0613],
[-0.8386]]), tensor([[-1.0613, 1.1264, -1.1954],
[-0.8386, 0.7032, -0.5897]]), tensor([-6.8037, -1.7054]))
3.11.4.2 定義、訓練和測試模型
我們先定義作圖函數(shù)semilogy雁歌,其中 y 軸使用了對數(shù)尺度宏浩。
# 本函數(shù)已保存在d2lzh_pytorch包中方便以后使用
def semilogy(x_vals, y_vals, x_label, y_label, x2_vals=None, y2_vals=None,
legend=None, figsize=(3.5, 2.5)):
d2l.set_figsize(figsize)
d2l.plt.xlabel(x_label)
d2l.plt.ylabel(y_label)
d2l.plt.semilogy(x_vals, y_vals)
if x2_vals and y2_vals:
d2l.plt.semilogy(x2_vals, y2_vals, linestyle=':')
d2l.plt.legend(legend)
和線性回歸一樣,多項式函數(shù)擬合也使用平方損失函數(shù)靠瞎。因為我們將嘗試使用不同復雜度的模型來擬合生成的數(shù)據(jù)集比庄,所以我們把模型定義部分放在fit_and_plot
函數(shù)中。多項式函數(shù)擬合的訓練和測試步驟與3.6節(jié)(softmax回歸的從零開始實現(xiàn))介紹的softmax回歸中的相關(guān)步驟類似乏盐。
num_epochs, loss = 100, torch.nn.MSELoss()
def fit_and_plot(train_features, test_features, train_labels, test_labels):
net = torch.nn.Linear(train_features.shape[-1], 1)
# 通過Linear文檔可知佳窑,pytorch已經(jīng)將參數(shù)初始化了,所以我們這里就不手動初始化了
batch_size = min(10, train_labels.shape[0])
dataset = torch.utils.data.TensorDataset(train_features, train_labels)
train_iter = torch.utils.data.DataLoader(dataset, batch_size, shuffle=True)
optimizer = torch.optim.SGD(net.parameters(), lr=0.01)
train_ls, test_ls = [], []
for _ in range(num_epochs):
for X, y in train_iter:
l = loss(net(X), y.view(-1, 1))
optimizer.zero_grad()
l.backward()
optimizer.step()
train_labels = train_labels.view(-1, 1)
test_labels = test_labels.view(-1, 1)
train_ls.append(loss(net(train_features), train_labels).item())
test_ls.append(loss(net(test_features), test_labels).item())
print('final epoch: train loss', train_ls[-1], 'test loss', test_ls[-1])
semilogy(range(1, num_epochs + 1), train_ls, 'epochs', 'loss',
range(1, num_epochs + 1), test_ls, ['train', 'test'])
print('weight:', net.weight.data,
'\nbias:', net.bias.data)
3.11.4.3 三階多項式函數(shù)擬合(正常)
fit_and_plot(poly_features[:n_train, :], poly_features[n_train:, :],
labels[:n_train], labels[n_train:])
輸出:
final epoch: train loss 0.00010175639908993617 test loss 9.790256444830447e-05
weight: tensor([[ 1.1982, -3.3992, 5.6002]])
bias: tensor([5.0014])
3.11.4.4 線性函數(shù)擬合(欠擬合)
我們再試試線性函數(shù)擬合父能。很明顯神凑,該模型的訓練誤差在迭代早期下降后便很難繼續(xù)降低。在完成最后一次迭代周期后何吝,訓練誤差依舊很高溉委。線性模型在非線性模型(如三階多項式函數(shù))生成的數(shù)據(jù)集上容易欠擬合。
fit_and_plot(features[:n_train, :], features[n_train:, :], labels[:n_train],
labels[n_train:])
輸出:
final epoch: train loss 249.35157775878906 test loss 168.37705993652344
weight: tensor([[19.4123]])
bias: tensor([0.5805])
3.11.4.5 訓練樣本不足(過擬合)
事實上爱榕,即便使用與數(shù)據(jù)生成模型同階的三階多項式函數(shù)模型瓣喊,如果訓練樣本不足,該模型依然容易過擬合黔酥。讓我們只使用兩個樣本來訓練模型型宝。顯然八匠,訓練樣本過少了,甚至少于模型參數(shù)的數(shù)量趴酣。這使模型顯得過于復雜,以至于容易被訓練數(shù)據(jù)中的噪聲影響坑夯。在迭代過程中岖寞,盡管訓練誤差較低,但是測試數(shù)據(jù)集上的誤差卻很高柜蜈。這是典型的過擬合現(xiàn)象仗谆。
fit_and_plot(poly_features[0:2, :], poly_features[n_train:, :], labels[0:2],
labels[n_train:])
輸出:
final epoch: train loss 1.198514699935913 test loss 166.037109375
weight: tensor([[1.4741, 2.1198, 2.5674]])
bias: tensor([3.1207])
我們將在接下來的兩個小節(jié)繼續(xù)討論過擬合問題以及應對過擬合的方法。
小結(jié)
- 由于無法從訓練誤差估計泛化誤差淑履,一味地降低訓練誤差并不意味著泛化誤差一定會降低隶垮。機器學習模型應關(guān)注降低泛化誤差。
- 可以使用驗證數(shù)據(jù)集來進行模型選擇秘噪。
- 欠擬合指模型無法得到較低的訓練誤差狸吞,過擬合指模型的訓練誤差遠小于它在測試數(shù)據(jù)集上的誤差。
- 應選擇復雜度合適的模型并避免使用過少的訓練樣本指煎。
注:本節(jié)除了代碼之外與原書基本相同蹋偏,原書傳送門