深度学习_16_权重衰退调整过拟合

news2024/11/15 21:44:21

所谓过拟合即模型复杂度较高,但用于训练数据集过于简单,最后导致模型将过多无用渣质作为学习对象

这个在上篇 深度学习_15_过拟合&欠拟合 已经详细介绍,以下便不再赘述。

上篇提到要想解决过拟合现象可以试着降低模型复杂度,又或者用复杂度匹配的数据集训练模型,但是数据集一般都是采集好的,无法更改,更改模型复杂度又可能涉及到更改模型本身,所以为了解决上述困扰,这里使用权重衰退方式调整模型,以达到让模型正常拟合

本次调整的代码对象仍是上篇实例代码

理论:

在这里插入图片描述
权重衰退采用限制模型本身w的数据取值范围,使模型的参数平方和小于θ,从而使模型的损失降低,从而限制模型的复杂度

在这里插入图片描述
上篇提到过测试集合的损失在达到低谷后又会反弹,这是模型过拟合的表现,原因就是模型学习了其他的杂质,而我们利用上述权重衰退使得模型的参数平方和小于θ,这样模型想去学习新的参数,就会受到这个θ大小的限制,导致其无法学习新的θ,从而模型的大小被我们限制了起来,而杂质部分参数都会以0呈现,也就是模型前四个维度会趋近真正模型,后面杂质维度会趋近于0

θ大小也要把控好,若θ太小,模型会欠拟合

上述终究是理论,得用数学公式表示出来,也就等效于下方:

在这里插入图片描述

朴素的说下面两个公式等价
在这里插入图片描述
在这里插入图片描述
证明λ趋近0即相当于θ趋近无穷,对损失没有限制,λ趋近无穷则整体损失会变大,模型是往损失减小的方向学习,所以会间接导致w会变小,这与θ变小限制w的大小效果相同

在这里插入图片描述

实例代码:

对上篇代码增添了权重衰退法则,并写了两个不同的版本,两版本本质区别在于用了不同的优化模型手段,效果差别不大

版本1代码:

import math
import torch
from torch import nn
from d2l import torch as d2l
import matplotlib.pyplot as plt

# 生成随机的数据集
max_degree = 20  # 多项式的最大阶数
n_train, n_test = 100, 100  # 训练和测试数据集大小
true_w = torch.zeros(max_degree)
true_w[0:4] = torch.Tensor([5, 1.2, -3.4, 5.6])

# 生成特征
features = torch.randn((n_train + n_test, 1))
permutation_indices = torch.randperm(features.size(0))
# 使用随机排列的索引来打乱features张量(原地修改)
features = features[permutation_indices]
poly_features = torch.pow(features, torch.arange(max_degree).reshape(1, -1))
for i in range(max_degree):
    poly_features[:, i] /= math.gamma(i + 1)

# 生成标签
labels = torch.matmul(poly_features, true_w)
labels += torch.normal(0, 0.1, size=labels.shape)

def evaluate_loss(net, data_iter, loss):
    metric = d2l.Accumulator(2)
    for X, y in data_iter:
        out = net(X)
        y = y.reshape(out.shape)
        l = loss(out, y)
        metric.add(l.sum(), l.numel())
    return metric[0] / metric[1]
def l2_penalty(w):
    w = w[0].weight
    return torch.sum(w.pow(2)) / 2
# 修改后的训练函数
def train(train_features, test_features, train_labels, test_labels, lambd,
          num_epochs=400):
    loss = nn.MSELoss()  # 损失函数
    input_shape = train_features.shape[-1]
    net = nn.Sequential(nn.Linear(input_shape, 1, bias=False))
    batch_size = min(10, train_labels.shape[0])

    train_iter = d2l.load_array((train_features, train_labels.reshape(-1, 1)),
                                batch_size)
    test_iter = d2l.load_array((test_features, test_labels.reshape(-1, 1)),
                               batch_size, is_train=False)
    trainer = torch.optim.SGD(net.parameters(), lr=0.01, weight_decay=lambd)  # 优化器调整模型

    # 用于存储测试损失的列表
    test_losses = []
    train_losses = []
    total_loss = 0
    total_samples = 0
    for epoch in range(num_epochs):
        for X, y in train_iter:
            trainer.zero_grad()  # 删除之前的梯度
            out = net(X)
            l = loss(out, y) + lambd * l2_penalty(net)
            l.backward()  # 将梯度传递回模型
            trainer.step()  # 梯度更新
            total_loss += l.sum().item()  # 统计所有元素损失
            total_samples += y.numel()    # 统计个数
            # 将当前的损失值添加到列表中
        a = total_loss / total_samples  # 本次训练的平均损失
        train_losses.append(a)  # 存
        test_loss = evaluate_loss(net, test_iter, loss)  #  本次训练的测试损失
        test_losses.append(test_loss)
        total_loss = 0
        total_samples = 0
        print(f"Epoch {epoch + 1}/{num_epochs}:")
        print(f"训练损失: {a:.4f}  测试损失: {test_loss:.4f}")
       # print(f"  训练损失:  测试损失: {loss(out, y):.4f}")
    print(net[0].weight)
    # 假设 test_losses 是已经计算出的测试损失值列表
    plt.figure(figsize=(10, 6))
    plt.plot(train_losses, label='train', color='blue', linestyle='-', marker='.')
    plt.plot(test_losses, label='test', color='purple', linestyle='--', marker='.')
    plt.xlabel('epoch')
    plt.ylabel('loss')
    plt.title('Test Loss over Epochs')
    plt.legend()
    plt.grid(True)
    plt.ylim(0, 1)  # 设置y轴的范围从0.01到100
    plt.show()


# 选择多项式特征中的前4个维度
train(poly_features[:n_train, :4], poly_features[n_train:, :4],
      labels[:n_train], labels[n_train:], 0)

版本2代码:

import math
import torch
from torch import nn
from d2l import torch as d2l
import matplotlib.pyplot as plt

# 生成随机的数据集
max_degree = 20  # 多项式的最大阶数
n_train, n_test = 100, 100  # 训练和测试数据集大小
true_w = torch.zeros(max_degree)
true_w[0:4] = torch.Tensor([5, 1.2, -3.4, 5.6])

# 生成特征
features = torch.randn((n_train + n_test, 1))
permutation_indices = torch.randperm(features.size(0))
# 使用随机排列的索引来打乱features张量(原地修改)
features = features[permutation_indices]
poly_features = torch.pow(features, torch.arange(max_degree).reshape(1, -1))
for i in range(max_degree):
    poly_features[:, i] /= math.gamma(i + 1)

# 生成标签
labels = torch.matmul(poly_features, true_w)
labels += torch.normal(0, 0.1, size=labels.shape)


# 以下是你原来的训练函数,没有修改
def evaluate_loss(net, data_iter, loss):
    metric = d2l.Accumulator(2)
    for X, y in data_iter:
        out = net(X)
        y = y.reshape(out.shape)
        l = loss(out, y)
        metric.add(l.sum(), l.numel())
    return metric[0] / metric[1]


def l2_penalty(w):
    w = w[0].weight
    return torch.sum(w.pow(2)) / 2


def train(train_features, test_features, train_labels, test_labels, lambd,
          num_epochs=400):
    loss = d2l.squared_loss
    input_shape = train_features.shape[-1]
    net = nn.Sequential(nn.Linear(input_shape, 1, bias=False))
    batch_size = min(10, train_labels.shape[0])

    train_iter = d2l.load_array((train_features, train_labels.reshape(-1, 1)),
                                batch_size)
    test_iter = d2l.load_array((test_features, test_labels.reshape(-1, 1)),
                               batch_size, is_train=False)

    # 用于存储训练和测试损失的列表
    train_losses = []
    test_losses = []
    total_loss = 0
    total_samples = 0
    for epoch in range(num_epochs):
        for X, y in train_iter:
            out = net(X)
            l = loss(out, y) + lambd * l2_penalty(net)

            # 反向传播和优化器更新
            l.sum().backward()
            d2l.sgd(net.parameters(), lr=0.01, batch_size= batch_size)
            total_loss += l.sum().item()  # 统计所有元素损失
            total_samples += y.numel()  # 统计个数
        a = total_loss / total_samples  # 本次训练的平均损失
        train_losses.append(a)
        test_loss = evaluate_loss(net, test_iter, loss)
        test_losses.append(test_loss)
        total_loss = 0
        total_samples = 0
        print(f"Epoch {epoch + 1}/{num_epochs}:")
        print(f"训练损失: {a:.4f}   测试损失: {test_loss:.4f} ")
    print(net[0].weight)

    # 绘制损失曲线
    plt.figure(figsize=(10, 6))
    plt.plot(train_losses, label='train', color='blue', linestyle='-', marker='.')
    plt.plot(test_losses, label='test', color='purple', linestyle='--', marker='.')
    plt.xlabel('epoch')
    plt.ylabel('loss')
    plt.title('Loss over Epochs')
    plt.legend()
    plt.grid(True)
    plt.ylim(0, 100)  # 设置y轴的范围从0.01到100
    plt.show()


# 选择多项式特征中的前4个维度
train(poly_features[:n_train, :4], poly_features[n_train:, :4],
      labels[:n_train], labels[n_train:], 0)

代码分析:

def l2_penalty(w):
    w = w[0].weight
    return torch.sum(w.pow(2)) / 2

取模型参数平方和除以2

            out = net(X)
            l = loss(out, y) + lambd * l2_penalty(net)

            # 反向传播和优化器更新
            l.sum().backward()
            d2l.sgd(net.parameters(), lr=0.01, batch_size= batch_size)

用模型算出结果,然后计算损失,算出梯度并返还到模型中,利用sgd优化算法,更新模型参数
没有用torch本身优化函数所以l.sum().backward()不能简写

其他不再赘述,上篇已经写的很明白了

过拟合:

在这里插入图片描述
很明显测试集在损失达到最低后又上升,这是过拟合现象

利用权重衰退调整过拟合

在这里插入图片描述
在上述过拟合条件下将λ设为0.006即可缓解过拟合现象
顺带提一下,train损失比test损失高出的部分有训练损失多加的lambd * l2_penalty(net)部分和loss(out, y)升高部分,总体来说是两者制衡效果的体现

正常拟合

在这里插入图片描述

可看出上述调整过后的过拟合test损失与正常拟合的test损失及其接近,说明调成效果不错

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1491055.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

边缘计算网关在机床生产中的应用-天拓四方

随着工业4.0的推进,物联网(IoT)技术在各个工业领域中的应用日益广泛。特别是在机床行业,物联网技术的引入不仅提高了生产效率,还实现了对机床设备的实时监控和远程维护。在这一背景下,边缘计算网关的角色愈…

牛客网 计算某个字符出现的次数

在本题中,我们是要统计一个字符串中重复字母出现的次数,我们把输入的字母转换成小写,然后把字符串也都转换成小写,然后把字符串中包含字母的地方替换成空。然后直接用字符串减去替换完成的字符串,就是我们要统计的个数…

c++ opecv项目实战

1、银行卡识别项目 参考文章 操作流程: 1、提取模板的每个数字 读取图片->转换为灰度图像->二值化图像(大于10取0,小于取255)->轮廓检测->绘制轮廓->对所有轮廓进行排序->提取模板所有轮廓每个数字 2、读取信用卡->转换为灰度图像…

unity Game视图看不到贴花,但是在Scene视图能看到

解决方法:找到URP的配置文件 ,修改Quality–RederScale为1,就可以了,这是unity 的bug,2022版本以后就没有这个问题了

09 Qt扩展LineEdit组件:Input输入框

系列文章目录 01 Qt自定义风格控件的基本原则-CSDN博客 02 从QLabel聊起:自定义控件扩展-图片控件-CSDN博客 03 从QLabel聊起:自定义控件扩展-文本控件-CSDN博客 04 自定义Button组件:令人抓狂的QToolButton文本图标居中问题-CSDN博客 0…

ROS读书记录1:机器人SLAM导航核心技术与实战1

机器人SLAM导航核心技术与实战1 第一章第2章 ROS简介 视频参考: 《机器人SLAM导航核心技术与实战》书籍配套教学视频 第一章 第2章 ROS简介 ROS:机器人开发平台 ①ROS是一个分布式通信框架(最核心的本质 ②ROS是一个开发工具的集台 ③ROS是一系列开源软件包 计算…

OpenDDS之QosXml库编译(Windows + VS2019)

目录 1、需求背景2、基础环境3、编译xercesc3.1、下载xercesc3.2、编译xercesc 4、编译ACE_XML_Utils4.1、生成XML_Utils解决方案4.2、编译XML_Utils 5、编译QOS_XML_XSC_Handlerd5.1、生成QOS_XML_XSC_Handlerd解决方案5.2、编译QOS_XML_XSC_Handlerd 6、测试例子6.1、生成dum…

百度文库旋转验证码识别

最近研究了一下图像识别,一直找到很好的应用场景,今天我就发现可以用百度的旋转验证码来做一个实验。没想到效果还挺好,下面就是实际的识别效果。 1、效果演示 2、如何识别 2.1准备数据集 首先需要使用爬虫,对验证码图片进行采…

leetcode最大二叉树

在本题中,我们是要将给定的数组构成一个二叉树,其根节点是数组中最大的元素,左子树都是最大值左边元素组成的,右子树都是最大值右边元素组成的。所以本题的关键在于我们先需要找到最大的元素。 我们构造二叉树,一般是采…

Vue.js 实用技巧:深入理解 Vue.mixin

🤍 前端开发工程师、技术日更博主、已过CET6 🍨 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 🕠 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 🍚 蓝桥云课签约作者、上架课程《Vue.js 和 E…

商业数据增长超88%!小红书热门内容解析,用户“打卡”新玩法

长久以来,“打卡”在社交媒体盛行,频频涌现新风潮,几乎覆盖美食、旅游、美妆等众多热门行业,今天吃了什么、玩了什么、做了什么?大众都喜欢通过打卡来分享。特别是小红书平台,打卡内容热度经久不衰&#xf…

LeetCode Python - 31.下一个排列

目录 题目答案运行结果 题目 整数数组的一个 排列 就是将其所有成员以序列或线性顺序排列。 例如,arr [1,2,3] ,以下这些都可以视作 arr 的排列:[1,2,3]、[1,3,2]、[3,1,2]、[2,3,1] 。 整数数组的 下一个排列 是指其整数的下一个字典序更…

xss.haozi.me:0x03及04

这里有一个正则所以&#xff08;&#xff09;要用到实体编码 <a href"javascript:alert1">cc</a> 03 04都一样

Softmax 回归 + 损失函数 + 图片分类数据集【动手学深度学习v2】李沐动手学深度学习课程笔记

目录 Softmax回归 损失函数 图片分类数据集 Softmax回归从零开始实现 Softmax回归简洁实现 Softmax回归 回归和分类的区别 回归问题举例上节课的预测房价问题&#xff0c;分类问题就是对样本进行分类 回归和分类的具体区别 假设真实的类别为第i个类别&#xff08;值为1&#x…

掌握WhatsApp手机号质量评分:增加信息可达性

WhatsApp手机号质量评分是用于衡量用户手机号与平台互动的健康度&#xff0c;确保用户通讯时的合规性和安全性。在实掌握WhatsApp手机号质量评分实际应用中&#xff0c;这个评分会影响用户的消息发送的可达性。高质量的评分意味着用户的账户被视为可信赖的&#xff0c;其发送的…

知识点碎片一,物联网通信协议和技术

loT通信协议 1. 前言 本文属于老吴个人对物联网研发学习的路线整理&#xff0c;属于个人对物流网产品研发的知识碎片的学习&#xff0c;文章没有先后顺序&#xff0c;随笔记录。文章如果有错误&#xff0c;希望各位读者指出问题所在&#xff0c;老吴将不胜感激。 2. 名称概述…

动网格学习:如何系统学习,案例及相关学习内容目录-学习材料

一、学习文章及相关案例 动网格&#xff08;Moving Mesh&#xff09;是一种在数值模拟中用于处理流动区域随时间变化的技术。在流体动力学模拟中&#xff0c;当物理模型或某些区域的网格需要随着流动的进行而动态改变时&#xff0c;就会采用动网格技术。例如&#xff0c;在模…

设计师必备!8款在线原型图工具分享

在线原型图的核心功能是可视化需求&#xff0c;因此一个易于使用的在线原型图工具对原型图设计至关重要。使用熟悉的Photoshop 对于Illustrator来说&#xff0c;虽然它们功能强大&#xff0c;但界面太复杂&#xff0c;初学者很难快速上手&#xff0c;面对批量调整的在线原型图还…

PostgreSQL restartpoint 原理详解

背景 大部分人对 PG 的 checkpoint 机制会熟悉一点&#xff0c;但是对 restartpoint 却不太熟悉&#xff0c;网上介绍这方面的文章也比较少。因此&#xff0c;本文将以 PG 14.7 的社区代码为基础&#xff0c;介绍 PG 中的 restartpoint 机制。 原理介绍 什么是 restartpoint…

VR 全景模式OpenGL原理

VR 全景模式OpenGL原理 VR 全景模式原理 VR 全景模式原理将画面渲染到球面上&#xff0c;相当于从球心去观察内部球面&#xff0c;观察到的画面 360 度无死角&#xff0c;与普通播平面渲染的本质区别在渲染图像部分&#xff0c;画面渲染到一个矩形平面上&#xff0c;而全景需…