在多分类任务实验中用torch.nn实现 𝑳𝟐 正则化

12、在多分类任务实验中用torch.nn实现 𝑳𝟐 正则化

L2正则化的功效作用:

1. 在深度学习中,用的比较多的正则化技术是L2正则化,其形式是在原先的损失函数后边再加多一项:12𝜆𝜃2𝑖12λθi2,那加上L2正则项的损失函数就可以表示为:𝐿(𝜃)=𝐿(𝜃)+𝜆∑𝑛𝑖𝜃2𝑖L(θ)=L(θ)+λ∑inθi2,其中𝜃θ就是网络层的待学习的参数,𝜆λ则控制正则项的大小,较大的取值将较大程度约束模型复杂度,反之亦然。

2. L2约束通常对稀疏的有尖峰的权重向量施加大的惩罚,而偏好于均匀的参数。这样的效果是鼓励神经单元利用上层的所有输入,而不是部分输入。所以L2正则项加入之后,权重的绝对值大小就会整体倾向于减少,尤其不会出现特别大的值(比如噪声),即网络偏向于学习比较小的权重。所以L2正则化在深度学习中还有个名字叫做“权重衰减”(weight decay),也有一种理解这种衰减是对权值的一种惩罚,所以有些书里把L2正则化的这一项叫做惩罚项(penalty)。

3. 我们通过一个例子形象理解一下L2正则化的作用,考虑一个只有两个参数𝑤1w1和𝑤2w2的模型,其损失函数曲面如下图所示。从a可以看出,最小值所在是一条线,整个曲面看起来就像是一个山脊。那么这样的山脊曲面就会对应无数个参数组合,单纯使用梯度下降法难以得到确定解。但是这样的目标函数若加上一项0.1×(𝑤21+𝑤22)0.1×(w12+w22),则曲面就会变成b图的曲面,最小值所在的位置就会从一条山岭变成一个山谷了,此时我们搜索该目标函数的最小值就比先前容易了,所以L2正则化在机器学习中也叫做“岭回归”(ridge regression)。

代码部分

#导入必要的包
import torch
import torch.nn as nn
import torchvision 
import torchvision.transforms as transforms
import torch.nn.functional as F
from torch.utils.data import DataLoader,TensorDataset 
import numpy as np
%matplotlib inline
#读取数据,将数据放在GPU上
train_dataset = torchvision.datasets.MNIST(
    root = './data',
    train = True,
    transform = transforms.ToTensor(),
    download = False,
)
test_dataset = torchvision.datasets.MNIST(
    root = './data',
    train = False,
    download = False,
    transform = transforms.ToTensor(),
)
print(train_dataset.data.shape)
print(train_dataset.targets.shape)
device='cuda:0'
train_loader = DataLoader(train_dataset,batch_size= 64,shuffle=False)
test_loader = DataLoader(test_dataset,batch_size= 64,shuffle= True)
torch.Size([60000, 28, 28])
torch.Size([60000])
#定义模型
class LinearNet(nn.Module):
    def __init__(self,num_input,num_hidden,num_output):
        super(LinearNet,self).__init__()
        self.linear1 = nn.Linear(num_input,num_hidden).to(device)
        self.linear2 =nn.Linear(num_hidden,num_output).to(device)
        self.relu = nn.ReLU()
        self.flatten = nn.Flatten()
    def forward(self,x):
        out = self.flatten(x)
        out = self.relu(self.linear1(out))
        out = self.linear2(out)
        return out  
#定义隐藏单元个数
num_input,num_hidden ,num_output = 784,256,10

#把模型移动到GPU上
net = LinearNet(num_input,num_hidden,num_output).to(device = 'cuda:0')

for param in net.state_dict():
    print(param)
loss = nn.CrossEntropyLoss()
num_epochs = 100
net = LinearNet(num_input,num_hidden,num_output)
param_w = [net.linear1.weight,net.linear2.weight]
param_b = [net.linear1.bias,net.linear2.bias]

#优化器中的weight_decay就是L2惩罚系数
optimzer_w = torch.optim.SGD(param_w,lr=0.001,weight_decay=0.01)
optimzer_b = torch.optim.Adam(param_b,lr=0.001)
linear1.weight
linear1.bias
linear2.weight
linear2.bias
#定义训练函数
def train(net,num_epochs):
    train_ls,test_ls = [],[]
    for epoch in range(num_epochs):
        ls = 0
        for x ,y in train_loader:
            x,y = x.cuda(),y.cuda()
            y_pred = net(x)
            l = loss(y_pred,y)
            optimzer_w.zero_grad()
            optimzer_b.zero_grad()
            l.backward()
            optimzer_w.step()
            optimzer_b.step()
            ls += l.item()
        train_ls.append(ls)
        
        ls = 0
        for x ,y in test_loader:
            x,y = x.cuda(),y.cuda()
            y_pred = net(x)
            l = loss(y_pred,y)
            l += l.item()
            ls += l.item()
        test_ls.append(ls)
        print('epoch: %d, train loss: %f, test loss: %f'%(epoch+1,train_ls[-1],test_ls[-1]))
#开始训练
train(net,num_epochs)
posted @ 2022-10-24 13:10  cyberbase  阅读(753)  评论(0编辑  收藏  举报