第七章 过拟合

一、过拟合与欠拟合

  • 线性模型
    在这里插入图片描述

  • 非线性模型
    在这里插入图片描述

  • 拟合过程存在噪声
    在这里插入图片描述

  • 多次项的拟合能力
    在这里插入图片描述

在这里插入图片描述

注:随着阶数越来越高,学习(拟合)数据的能力越来越强

  • 在神经网络模型中反映为更深的神经网络,即:前向传播过程可以表示为高阶的多项式

1.1 欠拟合

① 表现为预测模型不能很好的拟合已知数据
② 数值上反映为:训练集、测试集的准确率均比较低
在这里插入图片描述

1.2 过拟合

表现为过度的拟合训练集,即:预测模型包含了训练集噪声
② 数值上反映为:训练集的准确率均比较高;测试集的准确率比较低
在这里插入图片描述

1.3 总结拟合的三种情况

在这里插入图片描述

注:现实中,由于计算机计算能力逐步提高,神经网络越来越复杂,更多时候是过拟合


二、交叉验证 — 判定模型的拟合程度

  • 之前的test数据集充当了验证集的功能,用以判断拟合程度
    在这里插入图片描述

  • early stopping:可以选取训练集与测试(验证)集均表现“好”时的参数作为checkpoint,用于制止checkpoint之后会出现过拟合的情况
    在这里插入图片描述

  • 标准的工程中,包括:训练集、验证集(用于判定拟合程度)、测试集(实际中用户的使用情况)
    在这里插入图片描述

  • pytorch实现中,将原始的训练集拆分为:训练集 + 验证集两部分
    torch.utils.data.random_split(dataset,[sub_dataset1_num,sub_dataset2_num])
    在这里插入图片描述

# -*- coding: UTF-8 -*-
'''
@version: 1.0
@PackageName: pytorch_learning - high_level_multi_classificial_task.py
@author: yonghao
@Description: 使用pytorch集成的方法快速搭建深度学习网络
@since 2021/02/22 17:57
'''
import torch, torchvision
from torch import nn
from visdom import Visdom

# 创建一个visdom对象
vis = Visdom()
# torch.cuda.set_device(0)
# 设置visdom可视化迭代次数
global_step = 0
# 每批量个数
batch_size = 200
train_db = torchvision.datasets.MNIST('mnist_data', train=True, download=True,
transform=torchvision.transforms.Compose([
torchvision.transforms.ToTensor(),
torchvision.transforms.Normalize(
(0.1307,), (0.3081,))
]))
train_db, val_db = torch.utils.data.random_split(train_db, [50000, 10000])
test_db = torchvision.datasets.MNIST('mnist_data/', train=False, download=True,
transform=torchvision.transforms.Compose([
torchvision.transforms.ToTensor(),
torchvision.transforms.Normalize(
(0.1307,), (0.3081,))
]))
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)

test_loader = torch.utils.data.DataLoader(
test_db, batch_size=batch_size, shuffle=False)


# 构建网络
class MLB(nn.Module):
def __init__(self):
super(MLB, self).__init__()
self.model = nn.Sequential(
nn.Linear(28 * 28, 200),
nn.ReLU(inplace=True),
nn.Linear(200, 200),
nn.ReLU(inplace=True),
nn.Linear(200, 10)
# nn.ReLU(inplace=True)
)

def forward(self, x):
x = self.model(x)
return x


# 训练
device = torch.device('cuda:0')
criteon = nn.CrossEntropyLoss().to(device)
net = MLB().to(device)


def train(learning_rate=1e-3, epochs=7):
optimizer = torch.optim.SGD(net.parameters(), lr=learning_rate)
for epoch in range(epochs):
for batch_idx, (data, label) in enumerate(train_loader):
data = data.view(-1, 28 * 28)
data, label = data.to(device), label.cuda()
out = net(data)
loss = criteon(out, label)
optimizer.zero_grad()
loss.backward()
optimizer.step()
# 将train_loss 加载至visdom
global global_step
            vis.line([loss.item()], [global_step], win='train_loss', update='append')
global_step += 1
if batch_idx % 100 == 0:
print("Train Epoch: {} [ {} / {} ({:.0f}%)] \tLoss:{:.6f}".format(epoch, batch_idx * len(data),
len(train_loader.dataset),
100. * batch_idx / len(train_loader),
loss.item()))
# test()


# 验证
def validata():
val_loss = 0
correct = 0
for data, label in val_loader:
data = data.view(-1, 28 * 28).to(device)
label = label.cuda()
out = net(data)
pred = out.argmax(dim=1)
correct += pred.eq(label).sum()
val_loss += criteon(out, label).item()
val_loss /= len(val_loader.dataset)
print("\nVal set:Average loss:{:.4f},Accuracy:{}/{} ({:.0f}%)\n".format(val_loss, correct,
len(val_loader.dataset),
100. * correct / len(val_loader.dataset)))


# 测试
def test():
test_loss = 0
correct = 0
for data, label in test_loader:
data = data.view(-1, 28 * 28).to(device)
label = label.cuda()
out = net(data)
pred = out.argmax(dim=1)
correct += pred.eq(label).sum()
test_loss += criteon(out, label).item()
test_loss /= len(test_loader.dataset)
print("\nTest set:Average loss:{:.4f},Accuracy:{}/{} ({:.0f}%)\n".format(test_loss, correct,
len(test_loader.dataset),
100. * correct / len(test_loader.dataset)))


if __name__ == "__main__":
vis.line([0.], [0.], win='train_loss', opts=dict(title='train loss'))
train()
validata()
test()
# print(torch.cuda.is_available())  # 查看cuda是否可用
#
# print(torch.cuda.device_count())  # 返回GPU数目
#
# print(torch.cuda.get_device_name(0))  # 返回GPU名称,设备索引默认从0开始
#
# print(torch.cuda.current_device())  # 返回当前设备索引

三、降低过拟合

  • 方式一:更多的数据集
  • 方式二:降低模型复杂度
    ① 减少隐藏层,使模型变浅
    正则化
  • 方式三:随机失活Droput
  • 方式四:数据增强
  • 方式五:提前停止(根据validation set与train set间accuration 或 loss对比,提前终止train过程)
    在这里插入图片描述

3.1 正则化

损失函数添加参数范数项
在这里插入图片描述

  • 对损失函数求最小值时,会使各参数(w,b等)尽可能趋向于0,此时可以削减前向传播高次项的影响,从而降低了模型的复杂程度
    在这里插入图片描述

  • 举例展示正则化
    在这里插入图片描述

  • L1,L2正则化
    在这里插入图片描述

  • pytorch实现正则化
    只需要对梯度下降算法定制对象 optim.SGD(weight_decay) 中weight_decay设置值,其作为二范数前的超参数 λ \lambda λ
    在这里插入图片描述

在这里插入图片描述

四、动量与学习率衰减

4.1 动量

  • 动量即为惯性量,使当前参数更新值与 ① 当前参数值在loss函数的梯度;②之前一次的参数梯度下降值 均有关
    在这里插入图片描述

  • pytorch实现
    仅需要设置 optim.SGD(momentum) 中momentum参数值(动量超参数 β \beta β=0.9)
    在这里插入图片描述

4.2 学习率衰减

  • 过小、适中、过大
    在这里插入图片描述

  • 工程上设置学习率:随着迭代次数越来越小,即衰减的学习率
    在这里插入图片描述

在这里插入图片描述

  • pytorch实现
    ① 方案一:设置梯度下降中,自动检测loss值处于平缓区时,下降学习率
    在这里插入图片描述

② 方案二:设置梯度下降中,每固定迭代设定值次数后,衰减学习率
在这里插入图片描述


五、Early stopping,dropout等

5.1 Early stopping

找寻学习过程中,训练集与验证集(图中为test set)均处于准确度上升时对应最大准确率时的各个参数值。(或对应loss均下降时最小值时的各个参数)
在这里插入图片描述

5.2 Dropout随机失活

在这里插入图片描述

在这里插入图片描述

  • pytorch实现Dropout
    nn.Dropout(drop_rate):对线性层实现dropout
    在这里插入图片描述

  • torch.nn.Dropout() 与 tf.nn.dropout()的区别
    在这里插入图片描述

  • 在做验证、测试时应使用:.eval() 手动关闭训练时的dropout
    在这里插入图片描述

  • 使用mini-batch做训练集分割,每次梯度下降计算仅针对于mini-batch大小的数据,减小显存的使用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ModelBulider

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值