过拟合、欠拟合与方差/偏差的关系
过拟合、欠拟合与方差/偏差的关系
flyfish
用测量苹果重量说明偏差和方差
核心符号及含义(苹果重量场景)
符号 | 含义解释(苹果重量) |
---|---|
μ\muμ | 真实值:某一批苹果的“真实平均重量”(比如用高精度仪器测得,客观真实,假设为150克)。 |
x1,x2,...,xnx_1, x_2, ..., x_nx1,x2,...,xn | 测量值:用某工具(如秤)对这批苹果中n个苹果的重量测量结果(单位:克)。 |
xˉ\bar{x}xˉ | 平均测量值:n个测量值的平均值,即xˉ=x1+x2+...+xnn\bar{x} = \frac{x_1 + x_2 + ... + x_n}{n}xˉ=nx1+x2+...+xn。 |
1. 偏差(Bias)的定义与计算
偏差描述的是“测量工具的系统误差”:即平均测量值与真实值的差距,体现“测量结果是否整体偏离真实值”。
公式:
Bias=xˉ−μ\text{Bias} = \bar{x} - \muBias=xˉ−μ
(带符号:正偏差表示测量值整体偏高,负偏差表示整体偏低;绝对值表示偏差大小)
2. 方差(Variance)的定义与计算
方差描述的是“测量值的离散程度”:即多个测量值围绕平均测量值的分散程度,体现“苹果大小是否均匀”(方差越大,苹果大小差异越明显)。
公式:
Variance=1n∑i=1n(xi−xˉ)2\text{Variance} = \frac{1}{n}\sum_{i=1}^{n}(x_i - \bar{x})^2Variance=n1i=1∑n(xi−xˉ)2
案例对比:不同偏差和方差的苹果重量测量
假设某批苹果的真实平均重量为μ=150 g\mu = 150 \, \text{g}μ=150g(客观真实值),我们用4个案例对比偏差和方差的大小:
案例1:偏差大,方差小(秤不准,但苹果大小均匀)
- 场景:用一台有问题的秤,总是少称10克(系统误差),且这批苹果大小很均匀。
- 测量5个苹果的重量(单位:g):130、135、140、145、150
- 计算:
- 平均测量值xˉ=130+135+140+145+1505=140 g\bar{x} = \frac{130+135+140+145+150}{5} = 140 \, \text{g}xˉ=5130+135+140+145+150=140g
- 偏差:Bias=140−150=−10 g\text{Bias} = 140 - 150 = -10 \, \text{g}Bias=140−150=−10g(绝对值10g,偏差大,整体测量值偏低)
- 方差:
Variance=(130−140)2+(135−140)2+(140−140)2+(145−140)2+(150−140)25\text{Variance} = \frac{(130-140)^2 + (135-140)^2 + (140-140)^2 + (145-140)^2 + (150-140)^2}{5}Variance=5(130−140)2+(135−140)2+(140−140)2+(145−140)2+(150−140)2
=100+25+0+25+1005=2505=50 g2= \frac{100 + 25 + 0 + 25 + 100}{5} = \frac{250}{5} = 50 \, \text{g}^2=5100+25+0+25+100=5250=50g2(方差小,苹果大小较均匀)
案例2:偏差小,方差大(秤准确,但苹果大小不一)
- 场景:用一台准确的秤(无系统误差),但这批苹果大小差异很大。
- 测量5个苹果的重量(单位:g):120、140、150、160、180
- 计算:
- 平均测量值xˉ=120+140+150+160+1805=150 g\bar{x} = \frac{120+140+150+160+180}{5} = 150 \, \text{g}xˉ=5120+140+150+160+180=150g
- 偏差:Bias=150−150=0 g\text{Bias} = 150 - 150 = 0 \, \text{g}Bias=150−150=0g(偏差小,测量值整体准确)
- 方差:
Variance=(120−150)2+(140−150)2+(150−150)2+(160−150)2+(180−150)25\text{Variance} = \frac{(120-150)^2 + (140-150)^2 + (150-150)^2 + (160-150)^2 + (180-150)^2}{5}Variance=5(120−150)2+(140−150)2+(150−150)2+(160−150)2+(180−150)2
=900+100+0+100+9005=20005=400 g2= \frac{900 + 100 + 0 + 100 + 900}{5} = \frac{2000}{5} = 400 \, \text{g}^2=5900+100+0+100+900=52000=400g2(方差大,苹果大小差异明显)
案例3:偏差大,方差大(秤不准,且苹果大小不一)
- 场景:用一台有问题的秤,总是多称20克(系统误差),且这批苹果大小差异大。
- 测量5个苹果的重量(单位:g):160、180、200、220、240
- 计算:
- 平均测量值xˉ=160+180+200+220+2405=200 g\bar{x} = \frac{160+180+200+220+240}{5} = 200 \, \text{g}xˉ=5160+180+200+220+240=200g
- 偏差:Bias=200−150=50 g\text{Bias} = 200 - 150 = 50 \, \text{g}Bias=200−150=50g(绝对值50g,偏差大,整体测量值偏高)
- 方差:
Variance=(160−200)2+(180−200)2+(200−200)2+(220−200)2+(240−200)25\text{Variance} = \frac{(160-200)^2 + (180-200)^2 + (200-200)^2 + (220-200)^2 + (240-200)^2}{5}Variance=5(160−200)2+(180−200)2+(200−200)2+(220−200)2+(240−200)2
=1600+400+0+400+16005=40005=800 g2= \frac{1600 + 400 + 0 + 400 + 1600}{5} = \frac{4000}{5} = 800 \, \text{g}^2=51600+400+0+400+1600=54000=800g2(方差大,苹果大小差异极大)
案例4:偏差小,方差小(秤准确,且苹果大小均匀)
- 场景:用一台准确的秤(无系统误差),且这批苹果大小很均匀。
- 测量5个苹果的重量(单位:g):148、149、150、151、152
- 计算:
- 平均测量值xˉ=148+149+150+151+1525=150 g\bar{x} = \frac{148+149+150+151+152}{5} = 150 \, \text{g}xˉ=5148+149+150+151+152=150g
- 偏差:Bias=150−150=0 g\text{Bias} = 150 - 150 = 0 \, \text{g}Bias=150−150=0g(偏差小,测量值整体准确)
- 方差:
Variance=(148−150)2+(149−150)2+(150−150)2+(151−150)2+(152−150)25\text{Variance} = \frac{(148-150)^2 + (149-150)^2 + (150-150)^2 + (151-150)^2 + (152-150)^2}{5}Variance=5(148−150)2+(149−150)2+(150−150)2+(151−150)2+(152−150)2
=4+1+0+1+45=105=2 g2= \frac{4 + 1 + 0 + 1 + 4}{5} = \frac{10}{5} = 2 \, \text{g}^2=54+1+0+1+4=510=2g2(方差小,苹果大小几乎一致)
对比
案例 | 偏差大小(绝对值) | 方差大小 | 含义解读 |
---|---|---|---|
案例1 | 大(10g) | 小(50) | 秤有系统误差(总少称),但苹果大小均匀(方差小)。 |
案例2 | 小(0g) | 大(400) | 秤准确(无偏差),但苹果大小差异大(方差大)。 |
案例3 | 大(50g) | 大(800) | 秤误差大,且苹果大小极不一致。 |
案例4 | 小(0g) | 小(2) | 秤准确,且苹果大小非常均匀(理想状态)。 |
1. PyTorch代码实现
下面通过合成数据验证两种现象:
- 生成非线性数据(如 y=x2y = x^2y=x2 + 噪声)
- 用简单模型(线性模型)模拟欠拟合
- 用复杂模型(深层神经网络)模拟过拟合
import torch
import torch.nn as nn
import torch.optim as optim
import numpy as np
import matplotlib.pyplot as plt# 1. 生成合成数据(非线性关系)
np.random.seed(42)
x = np.random.uniform(-3, 3, 100) # 输入特征
y = x**2 + np.random.normal(0, 1, 100) # 目标:二次函数+噪声# 划分训练集和测试集
x_train, y_train = x[:70], y[:70]
x_test, y_test = x[70:], y[70:]# 转换为PyTorch张量
x_train = torch.tensor(x_train, dtype=torch.float32).view(-1, 1)
y_train = torch.tensor(y_train, dtype=torch.float32).view(-1, 1)
x_test = torch.tensor(x_test, dtype=torch.float32).view(-1, 1)
y_test = torch.tensor(y_test, dtype=torch.float32).view(-1, 1)# 2. 定义模型
# 简单模型(线性模型,容易欠拟合)
class SimpleModel(nn.Module):def __init__(self):super().__init__()self.linear = nn.Linear(1, 1) # 仅1个线性层def forward(self, x):return self.linear(x)# 复杂模型(深层网络,容易过拟合)
class ComplexModel(nn.Module):def __init__(self):super().__init__()self.layers = nn.Sequential(nn.Linear(1, 64),nn.ReLU(),nn.Linear(64, 64),nn.ReLU(),nn.Linear(64, 1) # 3层网络,高复杂度)def forward(self, x):return self.layers(x)# 3. 训练函数
def train_model(model, x_train, y_train, x_test, y_test, epochs=1000):criterion = nn.MSELoss()optimizer = optim.Adam(model.parameters(), lr=0.01)train_losses = []test_losses = []for epoch in range(epochs):# 训练模式model.train()optimizer.zero_grad()y_pred = model(x_train)loss = criterion(y_pred, y_train)loss.backward()optimizer.step()train_losses.append(loss.item())# 测试模式(不更新参数)model.eval()with torch.no_grad():y_pred_test = model(x_test)test_loss = criterion(y_pred_test, y_test)test_losses.append(test_loss.item())return model, train_losses, test_losses# 4. 训练两个模型
simple_model = SimpleModel()
complex_model = ComplexModel()simple_model, simple_train_loss, simple_test_loss = train_model(simple_model, x_train, y_train, x_test, y_test
)
complex_model, complex_train_loss, complex_test_loss = train_model(complex_model, x_train, y_train, x_test, y_test
)# 5. 可视化结果
plt.figure(figsize=(12, 8))# 子图1:损失曲线
plt.subplot(2, 2, 1)
plt.plot(simple_train_loss, label='Simple Model (Train)')
plt.plot(simple_test_loss, label='Simple Model (Test)')
plt.title('Underfitting (Simple Model)')
plt.xlabel('Epochs')
plt.ylabel('MSE Loss')
plt.legend()plt.subplot(2, 2, 2)
plt.plot(complex_train_loss, label='Complex Model (Train)')
plt.plot(complex_test_loss, label='Complex Model (Test)')
plt.title('Overfitting (Complex Model)')
plt.xlabel('Epochs')
plt.ylabel('MSE Loss')
plt.legend()# 子图2:拟合曲线
plt.subplot(2, 1, 2)
# 原始数据
plt.scatter(x_train, y_train, c='blue', label='Train Data', alpha=0.5)
plt.scatter(x_test, y_test, c='red', label='Test Data', alpha=0.5)# 简单模型预测(欠拟合)
x_range = torch.linspace(-3, 3, 100).view(-1, 1)
simple_pred = simple_model(x_range).detach().numpy()
plt.plot(x_range, simple_pred, 'g--', label='Simple Model (Underfitting)')# 复杂模型预测(过拟合)
complex_pred = complex_model(x_range).detach().numpy()
plt.plot(x_range, complex_pred, 'purple', label='Complex Model (Overfitting)')# 真实函数(参考)
plt.plot(x_range, x_range**2, 'k', label='True Function (y=x²)')plt.title('Fitting Curves')
plt.xlabel('x')
plt.ylabel('y')
plt.legend()plt.tight_layout()
plt.show()
结果
1. 欠拟合(简单线性模型):高偏差、低方差
从 损失曲线 看:
- 训练损失和测试损失都很高(最终损失远高于真实函数的理论误差),说明模型连训练数据的基本规律(二次关系)都没学会 → 高偏差。
- 训练损失和测试损失的差距很小(曲线几乎重合),说明模型对训练数据的波动不敏感(换测试数据,表现和训练集差不多)→ 低方差。
从 拟合曲线 看:
- 简单模型的预测曲线(绿色虚线)是直线,和真实二次曲线(黑色实线)差距极大,无法捕捉数据的非线性趋势 → 模型假设(线性)与数据真实分布(非线性)的偏差 → 高偏差。
2. 过拟合(复杂神经网络):低偏差、高方差
从 损失曲线 看:
- 训练损失极低(接近0),说明模型在训练集上几乎完美拟合(包括噪声)→ 低偏差(训练集上的预测和真实值接近)。
- 测试损失远高于训练损失(曲线分叉明显),说明模型对训练数据的细节(如噪声)过度学习,换测试数据后泛化能力差 → 高方差(对训练数据的波动敏感,泛化时不稳定)。
从 拟合曲线 看:
- 复杂模型的预测曲线(紫色实线)剧烈波动,强行贴合训练数据的每个点(包括噪声),比如在
x≈-2
和x≈2
处过度弯曲 → 模型对训练数据的微小波动反应强烈 → 高方差。
简单说就是
欠拟合(简单模型):
- 训练损失和测试损失都很高(无法拟合二次关系)
- 拟合曲线接近直线,无法捕捉数据的非线性模式(高偏差)
- 训练集和测试集损失差距小(低方差)
过拟合(复杂模型):
- 训练损失极低(完美拟合训练数据,包括噪声)
- 测试损失明显高于训练损失(泛化能力差)
- 拟合曲线剧烈波动,过度贴合训练数据中的噪声(高方差)
过拟合(Overfitting):模型过度学习训练数据的细节(包括噪声),导致在训练集上表现极好,但泛化到新数据(测试集)时表现很差。此时模型的方差(Variance)会增大。
方差(Variance):衡量模型对训练数据波动的敏感程度。高方差意味着模型在不同训练子集上训练出的结果差异很大,对输入的微小变化反应剧烈,泛化能力差。
欠拟合(Underfitting):模型过于简单,无法捕捉数据的潜在模式,导致在训练集和测试集上表现都很差。此时模型的偏差(Bias)会增大,而方差通常较低(模型对数据变化不敏感)。
偏差看模型和真实规律的差距
方差看模型对数据波动的敏感程
偏差 反映模型对“真实规律”的拟合能力(与真实值的系统误差)
方差 反映模型对“训练数据波动”的敏感程度(泛化时的稳定性)
过拟合对应高方差:模型对训练数据过度敏感,泛化差。
欠拟合对应高偏差:模型过于简单,无法捕捉数据规律。
理想模型应在偏差和方差之间取得平衡(偏差-方差权衡)。
偏差(Bias)和方差(Variance)
一、数学定义:用“预测误差”拆解
假设我们要预测的真实值为 yyy,模型的预测值为 y^\hat{y}y^。模型的总误差(比如均方误差MSE)可以拆解为三个部分:
总误差=偏差2+方差+噪声 \text{总误差} = \text{偏差}^2 + \text{方差} + \text{噪声} 总误差=偏差2+方差+噪声
1. 偏差(Bias):模型的“系统性误差”
数学定义:
偏差衡量模型的“平均预测值”与“真实值”的差距,公式为:
Bias(y^)=E[y^]−y \text{Bias}(\hat{y}) = \mathbb{E}[\hat{y}] - y Bias(y^)=E[y^]−y
(E[y^]\mathbb{E}[\hat{y}]E[y^] 表示在不同训练数据集上,模型预测值的平均值)
理解:
偏差是模型“先天假设”与“数据真实规律”的差距。比如用线性模型预测二次曲线数据(y=x2y=x^2y=x2),模型的“线性假设”本身就和真实规律冲突,导致无论怎么训练,平均预测值总会偏离真实值——这就是高偏差。
2. 方差(Variance):模型的“不稳定性”
数学定义:
方差衡量模型在“不同训练数据集”上的预测值的波动程度,公式为:
Variance(y^)=E[(y^−E[y^])2] \text{Variance}(\hat{y}) = \mathbb{E}\left[ \left( \hat{y} - \mathbb{E}[\hat{y}] \right)^2 \right] Variance(y^)=E[(y^−E[y^])2]
理解:
方差是模型对训练数据“细节波动”的敏感程度。比如一个非常复杂的模型(如深层神经网络),用不同的训练子集(即使来自同一分布)训练后,预测结果可能差异很大(有的拟合这个噪声点,有的拟合那个噪声点)——这就是高方差。
3. 噪声(Noise):数据本身的不可避免误差
噪声是数据本身的随机性(比如测量误差),是任何模型都无法消除的下限。
二、如何判断“偏差大小”和“方差大小”?
通过实验结果(损失曲线、预测曲线)可以直观判断,结合之前的PyTorch例子:
1. 看“偏差大小”:
核心看模型是否能“学到数据的基本规律”。
-
高偏差:
- 训练损失和测试损失都很高(比如线性模型预测二次曲线,最终MSE很大);
- 预测曲线与真实规律差距明显(比如直线 vs 二次曲线);
- 表现:模型太简单,连训练数据的基本模式都没学会(欠拟合)。
-
低偏差:
- 训练损失很低(模型在训练集上能很好拟合,接近真实值);
- 预测曲线在训练数据附近与真实规律贴合(比如复杂模型在训练点上几乎完美命中)。
2. 看“方差大小”:
核心看模型在“不同数据”上的预测是否稳定。
-
高方差:
- 训练损失很低,但测试损失远高于训练损失(模型对训练数据过拟合,换数据就不行);
- 用不同训练子集训练的模型,预测曲线差异很大(比如有的在A点凸起,有的在B点凹陷);
- 表现:模型太复杂,对训练数据的细节(包括噪声)过度敏感(过拟合)。
-
低方差:
- 训练损失和测试损失差距小(模型在新数据上的表现与训练集接近);
- 用不同训练子集训练的模型,预测曲线比较接近(波动小);
- 表现:模型稳定性高,但可能因为太简单而偏差高(如欠拟合的线性模型)。
怎么拆解
一、前提假设与符号定义
为了清晰推导,先明确几个符号和假设:
- 输入为 xxx,真实的潜在函数(数据生成规律)为 f(x)f(x)f(x),即“理想答案”是 f(x)f(x)f(x)。
- 实际观测到的标签 yyy 包含噪声(比如测量误差),即 y=f(x)+εy = f(x) + \varepsilony=f(x)+ε,其中噪声 ε\varepsilonε 满足:
- 均值为0:E[ε]=0\mathbb{E}[\varepsilon] = 0E[ε]=0(噪声无系统性偏差);
- 方差为 σ2\sigma^2σ2:E[ε2]=σ2\mathbb{E}[\varepsilon^2] = \sigma^2E[ε2]=σ2(噪声的波动程度)。
- 模型对输入 xxx 的预测值为 y^\hat{y}y^(依赖于训练数据,不同训练集会得到不同的 y^\hat{y}y^)。
二、MSE的数学定义
均方误差(MSE)衡量模型预测值与真实观测值的平均平方差,定义为:
MSE=E[(y^−y)2] \text{MSE} = \mathbb{E}\left[ (\hat{y} - y)^2 \right] MSE=E[(y^−y)2]
其中 E[⋅]\mathbb{E}[\cdot]E[⋅] 表示对“所有可能的训练数据”取期望(因为模型训练依赖数据,不同数据会导致不同的预测)。
三、分解过程:从MSE到“偏差² + 方差 + 噪声”
我们的目标是将 E[(y^−y)2]\mathbb{E}[(\hat{y} - y)^2]E[(y^−y)2] 拆分为偏差、方差和噪声。关键技巧是引入“模型的平均预测值” yˉ=E[y^]\bar{y} = \mathbb{E}[\hat{y}]yˉ=E[y^](对所有训练数据的预测取平均),通过加减 yˉ\bar{y}yˉ 展开平方项:
步骤1:展开平方项
(y^−y)2=(y^−yˉ+yˉ−y)2 (\hat{y} - y)^2 = (\hat{y} - \bar{y} + \bar{y} - y)^2 (y^−y)2=(y^−yˉ+yˉ−y)2
根据平方公式 (a+b)2=a2+2ab+b2(a + b)^2 = a^2 + 2ab + b^2(a+b)2=a2+2ab+b2,展开得:
=(y^−yˉ)2+2(y^−yˉ)(yˉ−y)+(yˉ−y)2 = (\hat{y} - \bar{y})^2 + 2(\hat{y} - \bar{y})(\bar{y} - y) + (\bar{y} - y)^2 =(y^−yˉ)2+2(y^−yˉ)(yˉ−y)+(yˉ−y)2
步骤2:取期望并化简
对两边取期望 E[⋅]\mathbb{E}[\cdot]E[⋅],MSE变为:
MSE=E[(y^−yˉ)2]+2E[(y^−yˉ)(yˉ−y)]+E[(yˉ−y)2] \text{MSE} = \mathbb{E}\left[ (\hat{y} - \bar{y})^2 \right] + 2\mathbb{E}\left[ (\hat{y} - \bar{y})(\bar{y} - y) \right] + \mathbb{E}\left[ (\bar{y} - y)^2 \right] MSE=E[(y^−yˉ)2]+2E[(y^−yˉ)(yˉ−y)]+E[(yˉ−y)2]
步骤3:分析中间项(交叉项)
注意到 yˉ=E[y^]\bar{y} = \mathbb{E}[\hat{y}]yˉ=E[y^],因此 E[y^−yˉ]=E[y^]−yˉ=0\mathbb{E}[\hat{y} - \bar{y}] = \mathbb{E}[\hat{y}] - \bar{y} = 0E[y^−yˉ]=E[y^]−yˉ=0(偏差为0)。
而 (yˉ−y)(\bar{y} - y)(yˉ−y) 与 (y^−yˉ)(\hat{y} - \bar{y})(y^−yˉ) 相互独立(前者是平均预测与真实值的差,后者是单次预测与平均的波动),因此交叉项的期望为:
2E[(y^−yˉ)]⋅E[(yˉ−y)]=2×0×(yˉ−y)=0 2\mathbb{E}\left[ (\hat{y} - \bar{y}) \right] \cdot \mathbb{E}\left[ (\bar{y} - y) \right] = 2 \times 0 \times (\bar{y} - y) = 0 2E[(y^−yˉ)]⋅E[(yˉ−y)]=2×0×(yˉ−y)=0
交叉项消失,MSE简化为:
MSE=E[(y^−yˉ)2]+E[(yˉ−y)2] \text{MSE} = \mathbb{E}\left[ (\hat{y} - \bar{y})^2 \right] + \mathbb{E}\left[ (\bar{y} - y)^2 \right] MSE=E[(y^−yˉ)2]+E[(yˉ−y)2]
步骤4:代入真实值 y=f(x)+εy = f(x) + \varepsilony=f(x)+ε
将 y=f(x)+εy = f(x) + \varepsilony=f(x)+ε 代入第二项 E[(yˉ−y)2]\mathbb{E}\left[ (\bar{y} - y)^2 \right]E[(yˉ−y)2],展开得:
E[(yˉ−f(x)−ε)2]=E[(yˉ−f(x))2−2(yˉ−f(x))ε+ε2] \mathbb{E}\left[ (\bar{y} - f(x) - \varepsilon)^2 \right] = \mathbb{E}\left[ (\bar{y} - f(x))^2 - 2(\bar{y} - f(x))\varepsilon + \varepsilon^2 \right] E[(yˉ−f(x)−ε)2]=E[(yˉ−f(x))2−2(yˉ−f(x))ε+ε2]
利用噪声的性质 E[ε]=0\mathbb{E}[\varepsilon] = 0E[ε]=0 和 E[ε2]=σ2\mathbb{E}[\varepsilon^2] = \sigma^2E[ε2]=σ2,化简得:
=(yˉ−f(x))2+σ2 = (\bar{y} - f(x))^2 + \sigma^2 =(yˉ−f(x))2+σ2
步骤5:最终分解式
结合上述结果,MSE的完整分解为:
MSE=(Bias)2+Variance+Noise { \text{MSE} = (\text{Bias})^2 + \text{Variance} + \text{Noise} } MSE=(Bias)2+Variance+Noise
其中:
- 偏差平方(Bias²):(yˉ−f(x))2=(E[y^]−f(x))2(\bar{y} - f(x))^2 = (\mathbb{E}[\hat{y}] - f(x))^2(yˉ−f(x))2=(E[y^]−f(x))2
模型的“平均预测值”与“真实规律”的差距(系统性误差)。 - 方差(Variance):E[(y^−yˉ)2]\mathbb{E}\left[ (\hat{y} - \bar{y})^2 \right]E[(y^−yˉ)2]
模型预测值围绕“平均预测值”的波动程度(对训练数据的敏感程度)。 - 噪声(Noise):σ2\sigma^2σ2
数据本身的不可控误差(所有模型的误差下限)。