200字范文,内容丰富有趣,生活中的好帮手!
200字范文 > 【深度学习】正则化方法——L1和L2正则化

【深度学习】正则化方法——L1和L2正则化

时间:2020-06-26 14:29:44

相关推荐

【深度学习】正则化方法——L1和L2正则化

文章目录

一、正则化的概念二、避免模型过拟合——L1正则化&L2正则化

一、正则化的概念

凡是能解决模型泛化误差而不是训练误差的方法,都被称为正则化。

模型的泛化误差主要是由模型过拟合引起的,所以正则化的各种方法用于解决模型过拟合的问题。

二、避免模型过拟合——L1正则化&L2正则化

L1和L2正则化的核心思想就是限制模型参数的取值范围。模型取值范围大同样可以训练出一个泛化能力强的模型,那为什么要限制模型参数的取值范围呢?

模型取值范围大同样可以训练出一个泛化能力强的模型,但是出现过拟合的几率也大大提升了(可以选择的范围大,自然就选了一整套相互配合起来可以让损失最小的参数,但是这些参数有可能只是在迎合训练集)。另一方面,参数取得太大会放大输入模型的样本之中的噪声,让输出结果失真。

综上所述,无论是从参数取值范围大会提高过拟合几率的角度来看,还是从参数太大会放大噪声的角度来看,参数取值范围太大都是非常不利的,所以需要对范围进行限制。

明白了L1和L2正则化的核心思想就是限制模型参数的取值范围之后,来解决下一个问题:如何减小模型参数的取值范围?

首先,理解一下L1和L2正则化中的L1和L2是什么意思。L1和L2就是L1范数和L2范数。L1范数是我们非常熟悉的曼哈顿距离,L2范数也是非常熟悉的欧式距离。对于一个向量 ω ⃗ \vec{\omega} ω 而言,其L1范数和L2范数分别是:

L 1 范数: ∣ ∣ ω ⃗ ∣ ∣ 1 = ∣ ω 1 ∣ + ∣ ω 2 ∣ + … + ∣ ω n ∣ L 2 范数: ∣ ∣ ω ⃗ ∣ ∣ 2 = ω 1 2 + ω 2 2 + … + ω n 2 L1范数:||\vec{\omega}||_1=|\omega_1|+|\omega_2|+…+|\omega_n| \\ L2范数:||\vec{\omega}||_2=\sqrt{\omega_1^2+\omega_2^2+…+\omega_n^2} L1范数:∣∣ω ∣∣1​=∣ω1​∣+∣ω2​∣+…+∣ωn​∣L2范数:∣∣ω ∣∣2​=ω12​+ω22​+…+ωn2​ ​

在损失函数之中,在尾项之中加入L2正则项,为梯度下降加入减小权重的目标,就可以在减小损失的同时减小权重。假设原本的损失函数是 ι ( ω ⃗ , b ⃗ ) \iota(\vec{\omega},\vec{b}) ι(ω ,b ),改正之后的损失函数就是:

ι ′ ( ω ⃗ , b ⃗ ) = ι ( ω ⃗ , b ⃗ ) + λ 2 L 2 2 ( w ⃗ ) \iota'(\vec{\omega},\vec{b})=\iota(\vec{\omega},\vec{b})+\frac{\lambda}{2} L_2^2(\vec{w}) ι′(ω ,b )=ι(ω ,b )+2λ​L22​(w )其中, λ \lambda λ是一个超参数,用来控制正则项的惩罚力度。越大,则最终权重会越小。

L1范数和L2范数作为正则项的区别在于,L1范数可以带来稀疏性。从L1范数的图像之中可以看出,L1正则化之后的损失函数想要最小化, ω ⃗ \vec{\omega} ω 的取值相比起L2正则化更容易接近或者落在坐标轴上,这意味着会将某些权重的值设置为0或者接近于0,权重消失或者接近于消失,就是所谓“带来稀疏性”。

ι ′ ( ω ⃗ , b ⃗ ) \iota'(\vec{\omega},\vec{b}) ι′(ω ,b )对 ω \omega ω求梯度,之后利用梯度下降更新权重,可以得到:

ω ⃗ t + 1 = ω ⃗ t − η ( ∂ ι ( ω ⃗ , b ⃗ ) ∂ ω ⃗ + λ ω ⃗ ) = ( 1 − λ η ) ω ⃗ t − η ∂ ι ( ω ⃗ , b ⃗ ) ∂ ω ⃗ t \vec{\omega}_{t+1}=\vec{\omega}_t-\eta(\frac{\partial \iota(\vec{\omega},\vec{b})}{\partial \vec{\omega}}+\lambda\vec{\omega})=(1-\lambda\eta)\vec{\omega}_t-\eta\frac{\partial \iota(\vec{\omega},\vec{b})}{\partial \vec{\omega}_t} ω t+1​=ω t​−η(∂ω ∂ι(ω ,b )​+λω )=(1−λη)ω t​−η∂ω t​∂ι(ω ,b )​由于 λ η \lambda\eta λη是小于1的,所以每一次梯度下降的时候,权重都会衰减。

故L2正则化也称为权重衰减。

在pytorch之中,进行权重衰减非常简单,只需要在梯度下降的函数中加入一个参数即可。如下:

# 梯度下降优化器(对权重w设置权重衰减。默认会对权重和偏置都做权重衰减,虽然偏置没有必要做权重衰减)trainer = torch.optim.SGD(net.parameters(), lr=lr, weight_decay=1e-4)

训练一个模型的完整源码如下:

import torchimport matplotlib.pyplot as pltimport numpy as npfrom torch.utils import datafrom torchvision import datasetsfrom torchvision import transformsfrom torch import nndef get_train_test_loader(image_size=28, train_batch_size=10, test_batch_size=10, num_workers=0, is_download=True):"""获得训练数据生成器和验证数据生成器,这个数据集总共有10个类别(即10个标签):param image_size: 图片的大小,取28:param train_batch_size: 数据生成器的批量大小:param num_workers: 数据生成器每次读取时调用的线程数量:param is_download: 是否要下载数据集(如果还未下载设置为True):return: 训练数据生成器和验证数据生成器"""data_transform = pose([# 设置图片大小transforms.Resize(image_size),# 转化为tensor张量transforms.ToTensor()])train_data = datasets.FashionMNIST(root='../data', train=True, download=is_download, transform=data_transform)test_data = datasets.FashionMNIST(root='../data', train=False, download=is_download, transform=data_transform)train_loader = data.DataLoader(train_data, batch_size=train_batch_size, shuffle=True, num_workers=num_workers,drop_last=True)test_loader = data.DataLoader(test_data, batch_size=test_batch_size, shuffle=False, num_workers=num_workers,drop_last=True)return train_loader, test_loaderdef accuracy(y_hat, y):"""模型训练完成后,判断预测结果的准确率"""if y_hat.shape[0] < 2 and y_hat.shape[1] < 2:raise ValueError("dimesion error")# 得到预测的y_hat每一行中最大概率所在的索引(索引即类别)y_hat = y_hat.argmax(axis=1)# 判断预测类别是否与实际类别相等judge = y_hat.type(y.dtype) == y# 现在cmp是一个bool类型的向量,转成0和1,统计1的数量return float(judge.type(y.dtype).sum()) / len(y)def init_weights(m):"""将网络中每一个线性层的所有权重都利用标准差为0.01的正态分布进行初始化,b没有初始化,所以初始为0"""if type(m) == nn.Linear:nn.init.normal_(m.weight, std=0.01)# 学习率lr = 0.03# 批量大小batch_size = 100test_batch_size = 10000# dropout概率p = 0.5# 最开始一个展平层用来给输入的x整形,接下来第一层是线性层,结果经过RuLU激活之后,进入下一个线性层,之后结果进行输出。隐藏层共有392个神经元net = nn.Sequential(nn.Flatten(), nn.Linear(784, 392), nn.ReLU(), nn.Dropout(p),nn.Linear(392,100), nn.ReLU(), nn.Dropout(p), nn.Linear(100, 10))# apply会将net中的每一层都作为参数进入init_weights,当发现是线性层,会对线性层的w自动初始化net.apply(init_weights)# 损失函数是交叉熵函数,参数是y_hat和y,注意,会对传入的y_hat先进行一次softmax处理loss = nn.CrossEntropyLoss()# 梯度下降优化器(对权重w设置权重衰减。默认会对权重和偏置都做权重衰减,虽然偏置没有必要做权重衰减)trainer = torch.optim.SGD(net.parameters(), lr=lr, weight_decay=1e-4)# 获取数据生成器以及数据train_loader, test_loader = get_train_test_loader(train_batch_size=batch_size, test_batch_size=test_batch_size,is_download=False)train_loader_test, _ = get_train_test_loader(train_batch_size=60000, is_download=False)# 学习代数num_epoch = 10# 用来正常显示中文标签plt.rcParams['font.sans-serif'] = ['SimHei']# 用来正常显示负号plt.rcParams['axes.unicode_minus'] = False# 交互模式plt.ion()fig = plt.figure()ax = fig.add_subplot()ax.grid(True, axis="y")epoch_x, validate_accuracy_y, test_accuracy_y, loss_y = [], [], [], []line_validate, = ax.plot(epoch_x,validate_accuracy_y,color='black',linestyle="--",label="训练集准确率")line_test, = ax.plot(epoch_x,test_accuracy_y,color='blue',label="测试集准确率")line_loss, = ax.plot(epoch_x,loss_y,color='red',label="损失函数")ax.set(xticks=np.arange(0,12,1),xlim=(0,11),yticks=np.arange(0,1.1,0.05),ylim=(0,1))ax.legend()for i in range(num_epoch):epoch_x.append(i + 1)for x, y in train_loader:# 模型得到预测值y_hat = net(x)# 损失函数l = loss(y_hat, y)print(f"\r{batch_size}个批量样本损失为{l}", end="", flush=True)trainer.zero_grad()# 求偏导l.backward()# 梯度下降trainer.step()with torch.no_grad():for x, y in train_loader_test:y_hat = net(x)l = loss(y_hat, y)loss_y.append(l)print(f"\n第{i}代,所有训练样本损失为{l}")validate_accuracy = accuracy(y_hat, y)print(f"验证集预测正确率:{validate_accuracy}")validate_accuracy_y.append(validate_accuracy)for x, y in test_loader:test_accuracy = accuracy(net(x), y)print(f"测试集预测正确率:{test_accuracy}")test_accuracy_y.append(test_accuracy)print("=" * 25)line_validate.set_data(epoch_x,validate_accuracy_y)line_test.set_data(epoch_x,test_accuracy_y)line_loss.set_data(epoch_x,loss_y)plt.draw()plt.pause(0.1)plt.ioff()plt.show()

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。