常见过拟合、欠拟合原因及解决办法

引言

在机器学习中,我们将模型在训练集上的误差称之为训练误差,又称之为经验误差,在新的数据集(比如测试集)上的误差称之为泛化误差,泛化误差也可以说是模型在总体样本上的误差。对于一个好的模型应该是经验误差约等于泛化误差,也就是经验误差要收敛于泛化误差,根据霍夫丁不等式可知经验误差在一定条件下是可以收敛于泛化误差的。
当机器学习模型对训练集学习的太好的时候(再学习数据集的通性的时候,也学习了数据集上的特性,这些特性是会影响模型在新的数据集上的表达能力的,也就是泛化能力),此时表现为经验误差很小,但往往此时的泛化误差会很大,这种情况我们称之为过拟合,而当模型在数据集上学习的不够好的时候,此时经验误差较大,这种情况我们称之为欠拟合。具体表现如下图所示,第一幅图就是欠拟合,第三幅图就是过拟合。

在这里插入图片描述

过拟合

原因

1、训练集的数量级和模型的复杂度不匹配。训练集的数量级要小于模型的复杂度

2、训练集和测试集特征分布不一致

3、样本里的噪音数据干扰过大,大到模型过分的记住了噪音特征,而忽略了真实的输入输出间的关系

4、权值学习迭代次数足够多(Overtraining),拟合了训练数据中的噪声和训练样例中没有代表性的特征

方法

1、simpler model structure
调小模型复杂度,使其适合自己训练集的数量级(缩小宽度和减小深度)

2、data augmentation
训练集越多,过拟合的概率越小。在计算机视觉领域中,增广的方式是对图像旋转,缩放,剪切,添加噪声等

3、regularization
参数太多,会导致我们的模型复杂度上升,容易过拟合,也就是我们的训练误差会很小。正则化是指通过引入额外新信息来解决过拟合问题的一种。这种额外信息通常的形式是模型复杂性带来的惩罚度。正则化可以保持模型简单,另外,规则项的使用还可以约束我们模型的特性。

4、dropout
在训练的时候让神经元以一定概率不工作。
dropout会导致网络的训练速度慢2、3倍,而且数据小的时候,dropout的效果并不会太好,因此只会在大型网络上使用。
在这里插入图片描述

左图没有dropout的标准神经网络,右图有dropout的神经网络,即在训练时候以一定的概率p来跳过一定的神经元

5、Early stopping
对模型进行训练的过程即使对模型的参数进行学习更新的过程,这个参数学习的过程往往会用到一些迭代方法,如梯度下降(Gradient descent)学习算法。Early stopping便是一种迭代次数截断的方法来防止过拟合的,即在模型对训练数据集迭代收敛之前停止迭代来防止过拟合。
其具体做法是,在每一个Epoch结束时(一个Epoch集为对所有的训练数据的一轮遍历)计算validation data 的 accuracy,当accuracy不再提高时,就停止训练。这种做法很符合直观感受,因为accuracy都不再提高了,在继续训练也是无益的。那么该做法的重点就是“怎样才认为accuracy不再提高了?” “并不是accuracy一降下来便认为不再提高了,因为可能经过这个Epoch后,accuracy降低了,但是随后的Epoch又让accuracy上去了,因此不能根据一次两次连续降低就判断不再提高了”。
一般做法是:在训练过程中,记录到目前为止最好的alidation accuracy,当连续10次Epoch(或者更多次)没达到最佳accuracy时,则可以认为accuracy不再提高了。此时便可以停止迭代了(Early Stopping),这种策略也称为“No-improvement-in-n” , n即Epoch的次数,可以根据实际情况选取,如10、20、30…

开源代码

import numpy as np
import torch

class EarlyStopping:
   """Early stops the training if validation loss doesn't improve after a given patience."""
   def __init__(self, patience=7, verbose=False, delta=0, path='checkpoint.pt', trace_func=print):
       """
       Args:
           patience (int): How long to wait after last time validation loss improved.
           				   上次验证集损失值改善后等待几个epoch
                           Default: 7
           verbose (bool): If True, prints a message for each validation loss improvement. 
           					如果是True,为每个验证集损失值改善打印一条信息
                           Default: False
           delta (float): Minimum change in the monitored quantity to qualify as an improvement.
           					检测数量的最小变化,以符合改进的要求
                           Default: 0
           path (str): Path for the checkpoint to be saved to.
                           Default: 'checkpoint.pt'
           trace_func (function): trace print function.
                           Default: print            
       """
       self.patience = patience
       self.verbose = verbose
       self.counter = 0
       self.best_score = None
       self.early_stop = False
       self.val_loss_min = np.Inf
       self.delta = delta
       self.path = path
       self.trace_func = trace_func
   def __call__(self, val_loss, model):

       score = -val_loss

       if self.best_score is None:
           self.best_score = score
           self.save_checkpoint(val_loss, model)
       elif score < self.best_score + self.delta:
           self.counter += 1
           self.trace_func(f'EarlyStopping counter: {self.counter} out of {self.patience}')
           if self.counter >= self.patience:
               self.early_stop = True
       else:
           self.best_score = score
           self.save_checkpoint(val_loss, model)
           self.counter = 0

   def save_checkpoint(self, val_loss, model):
       '''Saves model when validation loss decrease.
       验证损失减少时保存模型
       '''
       if self.verbose:
           self.trace_func(f'Validation loss decreased ({self.val_loss_min:.6f} --> {val_loss:.6f}).  Saving model ...')
       # 这里会存储迄今最优的模型
       torch.save(model.state_dict(), self.path)
       self.val_loss_min = val_loss

伪代码——pytorch

# 打包数据集

mydata_loader = Dataloader(dataset= , batch_size= 批量大小, shuffle = True or False 是否打乱数据顺序)
model = MyModel()
# 指定损失函数, 这里是交叉熵损失函数
criterion = nn.CrossEntropyLoss()
# 指定优化器
optimizer = torch.nn.Adam(model.parameters())
# 初始化early stopping 对象
# 这里是当验证集损失在连续20次训练周期中都没有得到降低时,停止模型训练,防止过拟合
patience = 20
early_stopping = EarlyStopping(patience = patience, verbose = True)

batch_size = 64
n_epochs = 100 #可以设置大一点,比较希望通过早停法来结束模型训练

# 训练模型,直到epoch == n_epochs 或者触发early_stopping来结束训练

for epoch in range(1, n_epochs+1):
	# 模型设置为训练模式
	model.train()

	# 按小批量训练
	for batch, (data, label) in enumerate(mydata_loader):
		# 清空所有参数的梯度
		optimizer.zero_grad()
		# 输出模型预测值
		output = model(data)
		# 计算损失
		loss = criterion(output, label)
		# 计算损失对于各个参数的梯度
		loss.backward()
		# 执行单步优化操作: 更新参数
		optimizer.step()
	# 模型设置为评估/测试模式,关闭dropout,并将模型参数锁定
	model.eval()
	# 一般如果验证集不是很大,模型验证时就不需要按批量进行,但要注意输入参数的维度不能错
	# 预测数据pre_data 对应目标/标签 pre_label
	valid_output = model(pre_data)
	valid_loss = criterion(valid_output, pre_label)

	early_stopping(valid_loss, model)
	# 若满足early stopping 要求
	if early_stopping.early_stop:
		print("Early Stopping!")
		# 结束模型训练
		break

# 获得 early stopping 时的模型参数
model.load_state_dict(torch.load('checkpoint.pt'))
	

参考文档:pytorch-实现早停法

参考文档:深度学习技巧之早停法
6、ensemble
集成学习算法也可以有效的减轻过拟合。
Bagging通过评价多个模型的结果,来降低模型的方差。Boosting不仅能过减小偏差,还能减小方差。

欠拟合

原因及方法

1、欠拟合是由于学习不足,可以考虑添加特征,从数据中挖掘更多的特征,有时候还需要对特征进行变换,使用组合特征和高次特征

2、模型简单也会导致欠拟合,如线性模型只能拟合一次函数的数据。尝试使用更高级的模型有助于解决欠拟合,如svm等

3、正则化参数是用来防止过拟合的,出现欠拟合的情况就要考虑减少正则化参数了。

  • 3
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
欠拟合是指模型在训练数据上表现不佳,无法很好地拟合数据的特征。对于Python中的人工神经网络(Artificial Neural Network,ANN),欠拟合可能是由于模型的复杂度不足或者训练数据的质量不高所导致的。 以下是一些可能导致Python ANN欠拟合原因解决方法: 1. 模型复杂度不足:如果模型的结构太简单,无法捕捉到数据中的复杂关系,就容易出现欠拟合解决方法是增加模型的复杂度,例如增加隐藏层的数量或神经元的数量。 2. 数据量不足:如果训练数据量太少,模型可能无法学习到足够的特征。解决方法是增加训练数据量,可以通过数据增强技术来扩充数据集。 3. 特征选择不当:如果选择的特征不足以描述数据的特点,模型就容易出现欠拟合解决方法是重新选择更具有代表性的特征,或者使用特征工程技术进行特征提取和转换。 4. 学习率过高:如果学习率设置过高,模型可能会在训练过程中跳过最优解,导致欠拟合解决方法是降低学习率,使模型能够更好地收敛。 5. 正则化参数过大:正则化是一种用于控制模型复杂度的技术,如果正则化参数设置过大,模型可能会过度惩罚复杂度,导致欠拟合解决方法是调整正则化参数的大小,找到一个合适的平衡点。 6. 训练时间过短:如果训练时间过短,模型可能没有充分学习到数据的特征,导致欠拟合解决方法是增加训练时间,或者使用早停(early stopping)等技术来确定合适的停止训练时机。 7. 数据预处理不当:如果数据没有进行适当的预处理,例如缺失值处理、标准化等,模型可能无法有效地学习到数据的特征。解决方法是对数据进行适当的预处理,确保数据的质量和一致性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值