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

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

这个在上篇 深度学习_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].weightreturn 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 = 0total_samples = 0for 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 = 0total_samples = 0print(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到100plt.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].weightreturn torch.sum(w.pow(2)) / 2def train(train_features, test_features, train_labels, test_labels, lambd,num_epochs=400):loss = d2l.squared_lossinput_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 = 0total_samples = 0for 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 = 0total_samples = 0print(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到100plt.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].weightreturn 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.hqwc.cn/news/503299.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Windows 10 合并磁盘分区 (G and H)

Windows 10 合并磁盘分区 [G and H] 1. 设备和驱动器2. 计算机 -> 管理 -> 存储 -> 磁盘管理3. 删除卷4. 新建简单卷5. 设备和驱动器References 1. 设备和驱动器 2. 计算机 -> 管理 -> 存储 -> 磁盘管理 3. 删除卷 H: -> right-click -> 删除卷 H: 变…

html2canvas 将DOM节点转成图片

官网地址:html2canvas - Screenshots with JavaScript 将js文件保存到本地 可以新建一个txt文件,然后丢进去修改后缀名称即可。 在项目中引入js文件: import html2canvas from "../html2canvas.min.js" 这是我准备画的DOM节点。…

【AIGC】微笑的秘密花园:红玫瑰与少女的美好相遇

在这个迷人的画面中,我们目睹了一个迷人的时刻,女子则拥有一头柔顺亮丽的秀发,明亮的眼睛如同星河般璀璨,优雅而灵动,她的微笑如春日暖阳,温暖而又迷人。站在红玫瑰花瓣的惊人洪水中。 在一片湛蓝无云的晴…

【AI Agent系列】【MetaGPT多智能体学习】5. 多智能体案例拆解 - 基于MetaGPT的智能体辩论(附完整代码)

本系列文章跟随《MetaGPT多智能体课程》(https://github.com/datawhalechina/hugging-multi-agent),深入理解并实践多智能体系统的开发。 本文为该课程的第四章(多智能体开发)的第三篇笔记。主要是对课程刚开始环境搭…

C#,哈夫曼编码(Huffman Code)压缩(Compress )与解压缩(Decompress)算法与源代码

David A. Huffman 1 哈夫曼编码简史(Huffman code) 1951年,哈夫曼和他在MIT信息论的同学需要选择是完成学期报告还是期末考试。导师Robert M. Fano给他们的学期报告的题目是,寻找最有效的二进制编码。由于无法证明哪个已有编码是…

Facebook直播网络需要满足什么条件

Facebook直播已经成为了企业、个人和组织开展在线活动、互动和营销的重要平台之一。然而,要确保Facebook直播的顺利进行和观众体验的良好,需要满足一系列关键条件。本文将探讨Facebook直播网络 需要满足的关键条件。 1、稳定的互联网连接: 稳…

7. 构建简单 IPv6 网络

7.1 实验介绍 7.1.1 关于本实验 IPv6(Internet Protocol Version 6)也被称为IPng(IP Next Generation)。它是Internet工程任务组IETF(Internet Engineering Task Force)设计的一套规范,是IPv4…

babylonjs入门-半球光

基于babylonjs封装的一些功能和插件 ,希望有更多的小伙伴一起玩babylonjs; 欢迎加群(点击群号传送):464146715 官方文档 中文文档 案例传送门 懒得打字 粘贴复制 一气呵成

OSCP靶场--Craft

OSCP靶场–Craft 考点(1.odt恶意宏文档getshell 2.SeImpersonatePrivilege土豆提权【PrintSpoofer】) 1.nmap扫描 nmap -Pn -sCV — open -p- — min-rate 10000 -oN nmap/open 192.168.249.169 Starting Nmap 7.92 ( https://nmap.org ) at 2022–10–23 06:58 EDT Nmap sc…

如何克隆树莓派系统到较小的硬盘/SD卡上(如何分区、设置修复引导)

最近有个老固态硬盘空下来了,虽然写入速度没那么快,但是足够满足千兆网络了,所以我就想把现在给树莓派使用的固态硬盘换下来。由于一些设置很浪费时间,所以我不打算重装系统。此外这个老固态是 120GB 的,要小于正在使用…

【Unity】机器人末端执行器仿真

机械手臂的末端执行器使用多项式来计算转动角度可能有几个原因: 精确控制:机械臂的运动通常需要高度的精确性,特别是在精密工作或复杂运动轨迹的情况下。多项式,特别是高阶的,可以很好地近似复杂的非线性关系和运动轨迹…

【Vue3】深入理解Vue中的ref属性

💗💗💗欢迎来到我的博客,你将找到有关如何使用技术解决问题的文章,也会找到某个技术的学习路线。无论你是何种职业,我都希望我的博客对你有所帮助。最后不要忘记订阅我的博客以获取最新文章,也欢…