欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

PyTorch实现L1,L2正则化以及Dropout

程序员文章站 2022-07-13 10:38:46
...

正则化(Regularization)

机器学习中,许多策略被显式的设计来减少测试误差(可能会以增大训练误差为代价),这些策略统称为正则化。正则化的目的是限制参数过多或者过大,避免模型更加复杂。

L1正则化和L2正则化是在损失函数后面会添加一个额外项,可以看做是损失函数的惩罚项。所谓“惩罚”是指对损失函数中的某些参数做一些限制。

L1正则化和L2正则化的作用:

  • L1正则化可以产生稀疏权值矩阵,即产生一个稀疏模型,可以用于特征选择
  • L2正则化可以防止模型过拟合(overfitting);一定程度上,L1也可以防止过拟合

Dropout

Dropout可以作为训练深度神经网络的一种trick供选择。在每个训练批次中,通过忽略一半的特征检测器(让一半的隐层节点值为0),这样可以使模型泛化性更强,因为它不会太依赖某些局部的特征,从而明显地减少过拟合现象。

Dropout流程:

  1. 首先随机(临时)删掉网络中一半的隐藏神经元,输入输出神经元保持不变。
  2. 把输入x通过修改后的网络前向传播,然后把得到的损失结果通过修改的网络反向传播。一小批训练样本执行完这个过程后,在没有被删除的神经元上按照随机梯度下降法更新对应的参数(w,b)。
  3. 然后继续重复这一过程:
    恢复被删掉的神经元(此时被删除的神经元保持原样,而没有被删除的神经元已经有所更新);
    从隐藏层神经元中随机选择一个一半大小的子集临时删除掉(备份被删除神经元的参数);
    对一小批训练样本,先前向传播然后反向传播损失并根据随机梯度下降法更新参数(没有被删除的那一部分参数得到更新,删除的神经元参数保持被删除前的结果)。

pytorch实现代码

#L2正则化:torch.optim集成了很多优化器,如SGD,Adadelta,Adam,Adagrad,RMSprop等
#这些优化器自带的一个参数weight_decay,用于指定权值衰减率,相当于L2正则化中的λ参数
import torch
import torch.nn as nn
import numpy as np

class net(nn.Module):
    def __init__(self):
        super().__init__()
        self.fc1 = nn.Linear(100,50)
        self.fc2 = nn.Linear(50,1)
        self.relu = nn.ReLU(inplace=True)
    def forward(self, inputs):
        layer = self.fc1(inputs)
        layer = self.relu(layer)
        layer = self.fc2(layer)
        return layer

inputs = np.random.normal(size=(8,100))
inputs = torch.tensor(inputs).float()
labels = np.ones((8,1))
labels = torch.tensor(labels).float()

n = net()
weight_p, bias_p = [],[]
for name, p in n.named_parameters():
    if 'bias' in name:
        bias_p += [p]
    else:
        weight_p += [p]
        
criterion = nn.MSELoss()
logit = n(inputs)
loss = criterion(input=logit, target=labels)
opt = torch.optim.SGD([{'params': weight_p, 'weight_decay':1e-5},
                      {'params': bias_p, 'weight_decay':0}], 
                      lr=1e-2, 
                      momentum=0.9)

opt.zero_grad()
loss.backward()
opt.step()  
#Dropout
import torch
import numpy as np

class Dropout:
    def __init__(self, dropout_ratio=0.5):
        self.dropout_ratio = dropout_ratio
        self.train_flg = True
        self.mask = None
    def __call__(self, x, manual_mask=None, train_flg=True):
        if train_flg:
            if manual_mask is None:
                self.mask = np.random.rand(*x.shape) > self.dropout_ratio
            else:
                self.mask = manual_mask
            out = x * self.mask / (1.0 - self.dropout_ratio)
            return out
        else:
            return x
    def backward(self, d_loss):
        dx = d_loss * self.mask / (1.0 - self.dropout_ratio)
        return dx

np.set_printoptions(precision=6, suppress=True, linewidth=120)
np.random.seed(12)
torch.random.manual_seed(3)

x_numpy = np.random.random((3, 7))
x_tensor = torch.tensor(x_numpy, requires_grad=True)

drop_out_numpy = Dropout(dropout_ratio=0.45)
drop_out_tensor = torch.nn.Dropout(p=0.45)

print("\n----- 训练阶段 -----")
train_flag = True
drop_out_tensor.train()

out_tensor = drop_out_tensor(x_tensor)
mask = out_tensor > 0
mask = mask.data.numpy()
out_numpy = drop_out_numpy(x_numpy, mask, train_flg=train_flag)

print("train mask : \n", mask)
print("train x : \n", x_numpy)
print("numpy out : \n", out_numpy)
print("tensor out : \n", out_tensor.data.numpy())

print("\n----- 反向传播 -----")
d_loss_numpy = np.random.random((3, 7))
d_loss_tensor = torch.tensor(d_loss_numpy, requires_grad=True)

dx_numpy = drop_out_numpy.backward(d_loss_numpy)
out_tensor.backward(d_loss_tensor)
dx_tensor = x_tensor.grad
print("dx_numpy : \n", dx_numpy)
print("dx_tensor : \n", dx_tensor.data.numpy())

print("\n----- 测试阶段 -----")
train_flag = False
drop_out_tensor.eval()

out_tensor = drop_out_tensor(x_tensor)
mask = out_tensor > 0
mask = mask.data.numpy()
out_numpy = drop_out_numpy(x_numpy, mask, train_flg=train_flag)

print("test mask : \n", mask)
print("test x : \n", x_numpy)
print("numpy out : \n", out_numpy)
print("tensor out : \n", out_tensor.data.numpy())

参考:
机器学习中正则化项L1和L2的直观理解
机器学习中的范数规则化之(一)L0、L1与L2范数
【通俗易懂】机器学习中 L1 和 L2 正则化的直观解释
正则化及正则化项的理解
理解dropout
深度学习中Dropout原理解析
神经网络九:Regularization(正则化)与Dropout
Python和PyTorch对比实现dropout函数及反向传播