【动手学深度学习笔记】之通过权重衰减法解决过拟合问题
时间:2022-07-23
本文章向大家介绍【动手学深度学习笔记】之通过权重衰减法解决过拟合问题,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
点击【拇指笔记】,关注我的公众号。
1.通过权重衰减解决过拟合问题
1.1 权重衰减
为了减轻上一篇文章提到的过拟合现象,往往需要增大训练集,但增大训练集的代价往往是高昂的。
因此这里介绍一种常用的缓解过拟合问题的方法:权重衰减。
1.2 实现方法
权重衰减通过惩罚绝对值较大的模型参数为需要学习的模型增加了限制。权重衰减等价于范数正则化。正则化通过为模型损失函数添加惩罚项使学习得到的模型参数值较小。
范数正则化在模型原损失函数基础上添加范数惩罚项,范数惩罚项指的是模型权重参数()每个元素的平方和与一个正的常数的乘积。
以如下这个损失函数为例
对应的迭代方程为
它的带有范数惩罚项的新损失函数为
其中为超参数()。当较大时,惩罚项比重较大,这会使学到的权重参数较接近0。当为0时,惩罚项完全不起作用。
当优化算法为小批量随机梯度下降(SGD)时,的迭代方程b变为
由此可见,因为添加了范数正则化,迭代方程中的权重参数自乘了一个小于1的数()。因此范数正则化又叫做权重衰减。实际场景中,有时也需要在惩罚项中添加偏差元素的平方和。
1.3 引入过拟合问题
以高维线性回归为例,引入过拟合问题。
以下面这个维度为的线性函数为例,生成人工数据集。
噪声项服从均值为0,标准差为0.01的正态分布。假设,训练集样本数为20。
1.3.1 生成人工数据集
根据模型,随机生成特征值,计算得到标签。
n_train,n_test,num_inputs = 20,100,200
true_w,true_b = torch.ones(num_inputs,1)*0.01,0.05
#设置为与输入数据同形,方便计算
features = torch.randn((n_train+n_test,num_inputs))
#随机生成训练集和测试集中的特征值
labels = torch.matmul(features,true_w)+true_b
labels += torch.tensor(np.random.normal(0,0.01,size = labels.size()),dtype = torch.float)
#生成训练集和测试集中的标签
train_features = features[:n_train,:]
test_features = features[n_train:,:]
train_labels = labels[:n_train,:]
test_labels = labels[n_train:,:]
#分割测试集和训练集
1.3.2 定义和初始化模型
先将权重参数和偏差参数初始化,
def init():
w = torch.randn((num_inputs,1),requires_grad = True)
b = torch.zeros(1,requires_grad = True)
return [w,b]
def linear(x,w,b): return torch.mm(x,w)+b
1.3.3 定义损失函数和优化函数
使用之前在线性回归中介绍的平方误差函数和小批量随机梯度下降算法。
#平方误差损失函数
def square_loss(y_hat,y):
return (y_hat-y.view(y_hat.size()))**2/2
#小批量随机梯度下降
def sgd(params,lr,batch_size):
for param in params:
param.data -= lr*param.grad/batch_size
1.3.4 定义范数惩罚项
这里只惩罚权重参数。
def l2(w): return (w**2).sum()/2
1.3.5 训练模型
batch_size,num_epochs,lr = 1,100,0.003
net,loss = linear,square_loss
dataset = torch.utils.data.TensorDataset(train_features,train_labels)
train_iter = torch.utils.data.DataLoader(dataset,batch_size,shuffle = True)
def train(lambda1):
#通过设置lambda=0,可以实现过拟合效果。设置lambda=3,实现权重衰减,减轻过拟合。
w,b = init()
train_ls,test_ls = [],[]
for epoch in range(num_epochs+1):
for x,y in train_iter:
l = loss(net(x,w,b),y) +lambda1*l2(w)
l = l.sum()
if w.grad is not None:
#如果权重参数的梯度信息不是None,代表已经开始计算,需要进行梯度清零
w.grad.data.zero_()
b.grad.data.zero_()
l.backward()
sgd([w,b],lr,batch_size)
train_ls.append(loss(net(train_features,w,b),train_labels).mean().item())
test_ls.append(loss(net(test_features,w,b),test_labels).mean().item())
print('权重参数的L2范数',w.norm().item())
1.3.6 过拟合效果
#令lambda=0,L2范数为0。即不开启权重衰减
train(0)
过拟合情况下,对数化的训练误差和泛化误差随学习周期的变化如图
可以看出,出现了严重的过拟合。
1.3.7 使用权重衰减矫正过拟合
#令lambda=3,开启权重衰减
train(3)
使用权重衰减后,对数化的训练误差和泛化误差随学习周期的变化如图
不难看出,使用权重衰减法后, 过拟合现象得到一定程度的缓解。
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 如何用R语言绘制生成正态分布图表
- hdu 5143 NPY and arithmetic progression(暴力+思维)
- 正则表达式之简易markdown文件解析器
- 2015.CCF计算机软件能力认证试题第二题
- Codeforces Round #547 (Div. 3)A. Game 23
- Codeforces Round #547 (Div. 3)C. Polycarp Restores Permutation
- 动态规划入门_数塔问题
- Rust所有者被修改了会发生什么?
- 如何编写高质量代码
- 动态规划入门_钱币兑换问题
- Codeforces Round #547 (Div. 3)D. Colored Boots
- JavaScript 性能优化
- 优化循环的方法-循环展开
- 程序性能优化-局部性原理
- Codeforces Round #547 (Div. 3)E. Superhero Battle