深度学习中的权重衰减原理及实现(基于pytorch)

391 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第16天,点击查看活动详情

1.需要解决的问题

我们知道过拟合现象是模型的训练误差远小于它在测试集上的误差。虽然增大训练数据集可能会减轻过拟合,但是获取额外的训练数据往往代价高昂

2. 环境配置及要求

  1. torch 1.12.1
  2. numpy 1.23.3
  3. jupter note环境运行

3. 方法

  1. 权重衰减等价于L2范数正则化。正则化通过为模型损失函数添加惩罚项使学出的模型参数值较小,是应对过拟合的常用手段。
  2. L2范数正则化在模型原损失函数基础上添加L2范数惩罚项,从而得到训练所需要最小化的函数。L2范数惩罚项指的是模型权重参数每个元素的平方和与一个正的常数的乘积。
  3. 权重衰减通过惩罚绝对值较大的模型参数为需要学习的模型增加了限制,这可能对过拟合有效。实际中,我们也会在惩罚项中添加偏差元素的平方和。

4.高维线性回归实验

我们以高维线性为例来引入一个过拟合问题,并使用权重衰减来应对过拟合。

image.png

import matplotlib_inline
import torch
import torch.nn as nn
import numpy as np
import sys
sys.path.append(r"E:\anaconda\envs\pytorch\Lib\d2lzh_pytorch")
import d2lzh_pytorch as d2l

首先进行环境配置。

image.png

n_train,n_test,num_inputs=20,100,200#将训练样本数设为20,测试集100维度
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,test_features=features[:n_train,:],features[n_train:,:]
train_labels,test_labels=labels[:n_train],labels[n_train:]

生成样本标签。

4.1 初始化模型参数

首先,定义随机初始化模型参数的函数。该函数为每个参数都附上梯度。

image.png

def init_params():
    w=torch.randn((num_inputs,1),requires_grad=True)
    b=torch.zeros(1,requires_grad=True)
    return [w,b]

4.2 定义L2范数惩罚项

这里我们只惩罚模型的权重参数。

image.png

def l2_penalty(w):
    return (w**2).sum/2

这里注意啊注意!!!是l,不是1,数字不能放开头。

4.3 定义训练和测试

image.png

batch_size,num_epochs,lr=1,100,0.003
net,loss=d2l.linreg,d2l.squared_loss
dataset=torch.utils.data.TensorDataset(train_features,train_labels)
train_iter=torch.utils.data.DataLoader(dataset,batch_size,shuffle=True)
def fit_and_plot(lambd):
    w,b=init_params()
    train_ls,test_ls=[],[]
    for _ in range(num_epochs):
        for X,y in train_iter:
            #添加L2范数惩罚项
            l=loss(net(X,w,b),y)+lambd*l2_penalty(w)
            l=l.sum()
            if w.grad is not None:
                w.grad.data.zero_()
                b.grad.data.zero_()
            l.backward()
            d2l.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())
        d2l.semilogy(range(1,num_epochs+1),train_ls,'epochs','loss',range(1,num_epochs+1),test_ls,['train,''test'])
        print('L2 norm of w:',w.norm().item())

定义了如何在训练数据集和测试数据集上分别训练和测试模型,这里再计算最终的损失函数时添加了L2范数惩罚项。

4.4 观察过拟合

image.png

fit_and_plot(lambd=0)

可能会出现的报错:

x and y must have same first dimension, but have shapes (100,) and (1,)

这是因为最后两行没有对齐导致的,只需要将其对齐就可解决问题。

4.5 使用权重衰减

image.png

fit_and_plot(lambd=3)

5.总结

  • 正则化通过为模型损失函数添加惩罚项使学出的模型参数值较小,是应对过拟合的常⽤手段。
  • 权重衰减等价于范数正则化,通常会使学到的权重参数的元素较接近0。
  • 权重衰减可以通过优化器中的 weight_decay 超参数来指定。
  • 可以定义多个优化器实例对不同的模型参数使⽤不同的迭代方法。