动手学深度学习学习笔记(13)

三阶多项式函数拟合
这个模型的训练误差和测试数据集的误差都较低,模型参数也接近真实值。

fit_and_plot(poly_features[:n_train,:],poly_features[n_train:,:],
labels[:n_train], labels[n_train:])

线性函数拟合 欠拟合
训练误差始终很高,线性模型在非线性模型生成的数据集上容易欠拟合。

fit_and_plot(features[:n_train, :],features[n_train:,:],
labels[:n_train],labels[n_train:])

训练样本不足 过拟合
即使使用同样的三阶模型,但是样本不足,依然容易产生过拟合。

fit_and_plot(poly_features[0:2, :],poly_features[n_train:, :],
labels[0:2], labels[n_train:])

权重衰减
应对过拟合问题的常用方法:权重衰减

方法
权重衰减等价于L2范数正则化。正则化通过为模型损失函数添加惩罚项使学出的模型参数值较小,是应对过拟合的常用手段。
L2范数正则化在模型原损失函数基础上添加L2范数惩罚项,从而得到训练所需要最小化的函数。L2范数惩罚项指的是模型权重参数每个元素的平方和与一个正的常数的乘积。
当权重参数都为0的时候,惩罚项最小。当λ较大时,惩罚项在损失函数中的比重较大,回事学到的权重参数的元素较接近为0.当λ设为0是,惩罚项完全不起作用。可以发现添加了惩罚项的损失函数迭代方式发生了变化。
L2范数正则化令权重w1和w2先自称小于1的数,再减去不含惩罚项的梯度,所以又叫做权重衰减。
权重衰减通过惩罚绝对值较大的模型参数为需要学习的模型增加了限制,这可能对过拟合有效。
实际应用中,有时也要在惩罚项中添加偏差元素的平方和。

高维线性回归实验
设数据样本的维度为p,将p设为200,将训练数据集的样本数设低,20.

%matplotlib inline
import torch
import torch.nn as nn
import numpy as np
import sys
sys.path.append("...")
import d2lzh_pytorch as d2l

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, test_features = features[:n_train, :], features[n_train:, :]
train_labels, test_labels = labels[:n_train], labels[n_train:]

从零开始实现
在目标函数后添加L2范数惩罚项来实现权重衰减

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

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

定义L2范数惩罚项
这里只惩罚模型的权重参数

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

定义训练和测试

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:
			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())

观察过拟合
当lambd设为0时,没有权重衰减,结果训练误差远小于测试集上的误差,出现过拟合现象。

使用权重衰减
lambd设为3,训练巡查有所提高,但是过拟合现象有所缓解

简洁实现
构造优化器时通过weight_decay参数来制定权重衰减超参数。
默认下,PyTorch只会对权重和偏差同时衰减。
可以对权重和偏差分别构造优化器,实现只对权重衰减。

def fit_and_plot_pytorch(wd):
	net = nn.linear(num_inputs, 1)
	nn.init.normal_(net.weight, mean = 0, std = 1)
	nn.init.normal_(net.bias, mean = 0, std = 1)
	optimizer_w = torch.optim.SGD(params = [net.weight], lr = lr, weight_decay = wd)
	optimizer_b = torch.optim.SGD(params = [net.bias], lr = lr)

	train_ls , test_ls = [],[]
	for_ in range(num_epochs):
		for X,y in train_iter:
			l = loss(net(X),y).mean()
			optimizer_w.zero_grad()
			optimizer_b.zero_grad()

			l.backward()
			optimizer_w.step()
			optimizer_b.step()
		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())
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值