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

正则化(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函数及反向传播

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值