一、为什么要对权重进行正则化
为了防止过拟合的发生,因为过拟合学习到了训练数据中的噪声,而没有较好的学习到普遍规律,所以泛化误差较大。
二、权重正则化的作用
正则化的目的是通过引入惩罚项来限制模型的复杂度,从而避免过拟合。在权重正则化中,对模型的权重(即连接神经元的参数)施加限制,防止它们变得过大或者过于复杂。
三、正则化是怎么实现权重衰减的
损失函数的定义:
又因为,所以对wj求导后,结果是
加入惩罚项后:
权重更新:
这里xi是指的x=[x1,x2...xn]中的样本,j表示xi样本中第j个特征,wj就是第j个特征的权重。从上式也可以看出来加入惩罚项后,越大的权重,衰减的越多,进一步说损失函数是向着w权重下降的方向移动。
权重衰减的公式如下:
对权重w的L2正则项的计算如下
代码实现如下
def l2_penalty(w):
return torch.sum(w.pow(2))/2
完整的代码
import torch
from torch import nn
from d2l import torch as d2l
n_train,n_test,num_inputs,batch_size = 20,100,200,5
# n_train表示训练集中的样本数量为20个
# n_test表示测试集中的样本数量为100个
# num_inputs 表示每个样本中的特征数量为200
true_w,true_b = torch.ones((num_inputs,1)) * 0.01,0.05
# 下一行代码是生成训练数据,即通过给定的真实权重 true_w 和真实偏置 true_b,以及样本数量 n_train,合成一个训练集
train_data = d2l.synthetic_data(true_w, true_b, n_train)
# 下一行代码的作用是 将训练数据train_data加载为一个数据迭代器train_iter,
# 使得模型可以按照指定的批量大小(batch_size)来从train_data中选取训练数据
train_iter = d2l.load_array(train_data, batch_size)
test_data = d2l.synthetic_data(true_w, true_b, n_test)
test_iter = d2l.load_array(test_data, batch_size, is_train=False)
def init_params():# 网络中的参数初始化
w = torch.normal(0,1,size=(num_inputs,1),requires_grad=True)
b = torch.zeros(1,requires_grad=True)
return [w,b]
def l2_penalty(w): #l2惩罚项
return torch.sum(w.pow(2))/2
def train(lambd):
w, b = init_params()
net, loss = lambda X: d2l.linreg(X, w, b), d2l.squared_loss
num_epochs, lr = 100, 0.003
animator = d2l.Animator(xlabel='epochs', ylabel='loss', yscale='log',
xlim=[5, num_epochs], legend=['train', 'test'])
for epoch in range(num_epochs):
for X, y in train_iter:# 这里是通过数据加载器每次取出5个样本
with autograd.record():
# 增加了L2范数惩罚项,
# 广播机制使l2_penalty(w)成为一个长度为batch_size的向量
l = loss(net(X), y) + lambd * l2_penalty(w)
l.backward()
d2l.sgd([w, b], lr, batch_size)
if (epoch + 1) % 5 == 0:
animator.add(epoch + 1, (d2l.evaluate_loss(net, train_iter, loss),
d2l.evaluate_loss(net, test_iter, loss)))
print('w的L2范数是:', np.linalg.norm(w))
train(lambd=3)