李沐动手学深度学习V2-Dropout丢弃法笔记以及代码实现

  1. 模型过拟合两种解决方法,也都是属于正则化方式:
    (1)权重衰减
    (2)Dropout丢弃法
  2. 模型过拟合出现的原因是模型太过复杂,从而时模型把数据的噪音都完美拟合了出来,也就是把训练数据训练的过于拟合了,而在测试数据集上面误差却比训练时相差太大,权重衰减和Dropout就是使模型变得简单,不那么复杂
  3. 权重衰减通过限制模型权重参数为一个小的范围,使模型函数趋于平滑;权重衰减是作用于loss函数上面,常见的有L1 norm,L2 norm等正则项
  4. Dropout通过对输出层以每一个元素以P概率丢掉,1-P的概率保留,同时保留的元素数值需要除以(1-P),从而保证输出层所有元素数值在使用dropout前后的期望值(均值)不变,每个层丢掉一些神经元(输出元素),且每一次batch_size数据迭代时drop的元素都不一样,从而当迭代几百万次时,每个输出层的输出元素都有可能丢掉多次,从而保证了模型的稳定性
  5. Dropout通常使用在全连接层上面,batch_norm作用于卷积层上面
  6. 在测试模型时,我们为了拿到更加确定性的结果,而不是一个随机的结果,一般对输出层不使用Dropout丢弃法,Dropout丢弃法只使用于训练模型时。因此在Pytorch中模型含有Dropout层时,当模型开始训练时需要在前面加入model.train()代码,表示模型处于训练状态,此时需要使用dropout层,当模型开始处于测试状态时,需要在前面加入model.evel()代码,此时模型不使用dropout层
  7. 当我们将丢弃法应用到隐藏层,以P的概率将隐藏单元置为零时, 结果可以看作是一个只包含原始神经元子集的网络。 比如在 下图中多层感知机Dropout前后的形状,删除了h2和h5, 因此输出的计算不再依赖于h2或h5,并且它们各自的梯度在执行反向传播时也会消失。 这样,输出层的计算不能过度依赖于的任何一个元素。
    李沐动手学深度学习V2-Dropout丢弃法笔记以及代码实现_第1张图片
  8. 将丢弃法Dropout应用于每个隐藏层的输出(在激活函数之后), 并且可以为每一层分别设置暂退概率: 常见的技巧是在靠近输入层的地方设置较低的丢弃概率,远离输入层的地方设置较高的丢弃概率。 下面代码的模型将第一个和第二个隐藏层的Dropout概率分别设置为0.2和0.5, 并且Dropout只在训练期间有效。通常Dropout概率设置为0.1,0.2,0.5,0.8,0.9,1这几个数
  9. 下面是手动实现Dropout层和使用Pytorch框架实现的Dropout层
import torch
from d2l.torch import d2l
from torch import nn
from torch.nn import Linear

#该函数以dropout的概率丢弃张量输入X中的元素,重新缩放剩余部分:将剩余部分除以(1.0-dropou)。
def dropout_layer(X,dropout):
    #dropout范围在[0,1]之间
    assert 0<=dropout<=1
    #dropout = 1指把输出层所有元素都丢掉
    if dropout == 1:
        return torch.zeros_like(X)
    # dropout = 0指把输出层所有元素都保留,不丢掉
    if dropout ==0:
        return X
    #zero_one_X = torch.randn(X.shape)按照X尺寸维数大小按照正态分布随机生成0到1之间的元素所组成的矩阵,然后与dropout比较大小得到的bool值True,False,然后转换成浮点数,对应1,0值
    zero_one_X = torch.randn(X.shape)
    #print("zero_one_X = ",zero_one_X)
    mask = (zero_one_X > dropout).float()
    # mask = (torch.rand(X.shape) > dropout).float()#与上面两行代码等价
    #print("mask :",mask)
    #mask矩阵和X矩阵对应元素相乘再除以(1-dropout),保证使用dropout后保证每一层使用dropout后的输出层元素期望均值不变
    return mask * X /(1-dropout) #在Dropout模型实现过程中Dropout掉的元素其实是把这个元素变为0,然后继续输入到下一层中,输出层的维数仍然没有改变,仍然为256维
X = torch.arange(16,dtype=torch.float32).reshape(2,8)

#测试dropout_layer()函数
def test_dropout():
    print("X: ", X)
    print("dropout = 0", dropout_layer(X, dropout=0))
    print("dropout = 0.2", dropout_layer(X, dropout=0.2))
    print("dropout = 0.5", dropout_layer(X, dropout=0.5))
    print("dropout = 1", dropout_layer(X, dropout=1))
test_dropout()

num_inputs = 784
num_outputs = 10
num_hiddens1 = 256
num_hiddens2 = 256
dropout_1 = 0.2
dropout_2 = 0.5

class model(nn.Module):
    def __init__(self,num_inputs,num_outputs,num_hiddens1,num_hiddens2,is_training = True):
        super(model, self).__init__()
        self.num_inputs = num_inputs
        self.num_outputs = num_outputs
        self.is_training = is_training
        self.linear1 = nn.Linear(num_inputs,num_hiddens1,bias=True)
        self.linear2 = nn.Linear(num_hiddens1,num_hiddens2,bias=True)
        self.linear3 = nn.Linear(num_hiddens2,num_outputs,bias=True)
        self.relu = nn.ReLU()

    def forward(self,X):
        X = X.reshape(-1,self.num_inputs)
        l1 = self.linear1(X)
        H1 = self.relu(l1)
        #is_training 为true时表明数据集此时为训练集,需要使用dropout,测试集测试时不使用dropout
        if self.is_training:
            H1 = dropout_layer(H1,dropout=dropout_1)
        l2 = self.linear2(H1)
        H2 = self.relu(l2)
        if self.is_training:
            H2 = dropout_layer(H2,dropout=dropout_2)
        out = self.linear3(H2)
        return out
def network_train(net):
    num_epoch = 10
    lr = 0.5
    batch_size = 256
    train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size=batch_size)
    #分类用CrossEntropyLoss()损失函数
    loss = nn.CrossEntropyLoss(reduction='none')
    #使用SGD梯度下降优化算法
    trainer = torch.optim.SGD(net.parameters(), lr=lr)
    d2l.train_ch3(net, train_iter, test_iter, loss, num_epoch, trainer)

#从零到一代码层实现dropout
def dropout_scratch():
    net = model(num_inputs, num_outputs, num_hiddens1, num_hiddens2, is_training=True)
    print("net : ", net)
    network_train(net)


#调用pytorch框架简洁实现
def dropout_concise():
    net = nn.Sequential(nn.Flatten(),
        nn.Linear(num_inputs,num_hiddens1,bias=True),
        nn.ReLU(),
        #使用pytorch框架简洁实现即直接在ReLU()后面加入dropout()层
        nn.Dropout(dropout_1),#在Dropout模型实现过程中Dropout掉的元素其实是把这个元素变为0,然后继续输入到下一层中,输出层的维数仍然没有改变,仍然为256维
        nn.Linear(num_hiddens1,num_hiddens2,bias=True),
        nn.ReLU(),
        nn.Dropout(dropout_2),
        nn.Linear(num_hiddens2,num_outputs)
    )
    #初始化每一个线性层的参数weights,使所有初始weights都在均值0,标准差0.01的正态分布中
    net.apply(init_weights)
    network_train(net)


def init_weights(model):
    if(type(model) == nn.Linear):
        nn.init.normal_(model.weight,std = 0.01)

#dropout_scratch()
dropout_concise()
  1. 权重衰减和Dropout在同一个模型中可以同时使用解决模型过拟合的问题,一个控制模型权重参数大小,一个控制模型的维数(宽窄)

你可能感兴趣的:(李沐动手学深度学习笔记,python,计算机视觉,人工智能,深度学习)