Pytorch:model.train、model.eval、with torch.no_grad

日萌社

 

人工智能AI:Keras PyTorch MXNet TensorFlow PaddlePaddle 深度学习实战(不定时更新)


1.model.train()
    在train模式下,dropout网络层会按照设定的参数p设置保留激活单元的概率(保留概率=p); 
    batchnorm层会继续计算数据的mean和var等参数并更新。

2.model.eval()
    在PyTorch中进行validation时,会使用model.eval()切换到测试模式。
    model.eval()主要用于通知dropout层和batchnorm层在train和val模式间切换。
    在val模式下,dropout层会让所有的激活单元都通过,而batchnorm层会停止计算和更新mean和var,直接使用在训练阶段已经学出的mean和var值。
    该模式不会影响各层的gradient计算行为,即gradient计算和存储与training模式一样,只是不进行反传(backprobagation)。

3.更推荐使用 with torch.no_grad()
    主要是用于停止autograd模块的工作,以起到加速和节省显存的作用,具体行为就是停止gradient计算,
    从而节省了GPU算力和显存,但是并不会影响dropout和batchnorm层的行为。

4.使用场景
    如果不在意显存大小和计算时间的话,仅仅使用model.eval()已足够得到正确的validation的结果;
    而with torch.no_grad()则是更进一步加速和节省gpu空间(因为不用计算和存储gradient),从而可以更快计算,也可以跑更大的batch来测试。
1.optimizer优化器torch.optim、scheduler优化器步长自动调节器torch.optim.lr_scheduler
        #优化器
        optimizer = torch.optim.SGD(model.parameters(), lr=0.1)
        optimizer = torch.optim.Adam(model.parameters(),lr=0.01)
        optimizer.step()
        
        #优化器步长自动调节方法, 用来自动衰减学习率
        scheduler = torch.optim.lr_scheduler.StepLR(optimizer, 1, gamma=0.9)
        scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=EPOCHS)
        #每个epoch结束时,调用优化器步长调节方法, 用来衰减学习率
        scheduler.step()
        
2.pytorch中的多种训练模型写法
    1.第一种写法:
            #遍历epoch次数
            for epoch in range(N_EPOCHS):
                data = DataLoader(train_data, batch_size=BATCH_SIZE, shuffle=True, collate_fn=generate_batch, drop_last=True)
                #遍历每个批量大小的数据
                for i, (input, label) in enumerate(data):
                    #第一种方式:在开始遍历每个批量大小的数据的一开始就设置,实际只要放置在loss.backward()之前即可
                    optimizer.zero_grad() 
                    output = model(input)
                    #交叉熵Cross Entropy用法第一种写法:nn.LogSoftmax + nn.NLLLoss = 交叉熵Cross Entropy
                    softmax = nn.LogSoftmax(dim=-1)
                    output = softmax(input)
                    criterion = nn.NLLLoss()
                    loss = criterion(output, label)
                    #第二种方式:放在反向传播求所有参数梯度(loss.backward())之前
                    #optimizer.zero_grad()  
                    loss.backward()
                    optimizer.step()
                #每个epoch结束时,调用优化器步长调节方法, 用来衰减学习率
                scheduler.step()
    
    2.第二种写法:
            #遍历epoch次数
            for epoch in range(N_EPOCHS):
                data = DataLoader(train_data, batch_size=BATCH_SIZE, shuffle=True, collate_fn=generate_batch, drop_last=True)
                #遍历每个批量大小的数据
                for i, (input, label) in enumerate(data):
                    #第一种方式:在开始遍历每个批量大小的数据的一开始就设置,实际只要放置在loss.backward()之前即可
                    optimizer.zero_grad() 
                    output = model(input)
                    #交叉熵Cross Entropy用法第二种写法:F.log_softmax + F.nll_loss = 交叉熵Cross Entropy
                    output = F.log_softmax(output, dim=1)
                    loss = F.nll_loss(output, label)  
                    #第二种方式:放在反向传播求所有参数梯度(loss.backward())之前
                    #optimizer.zero_grad()  
                    loss.backward()
                    optimizer.step()
                #每个epoch结束时,调用优化器步长调节方法, 用来衰减学习率
                scheduler.step()
            
    3.第三种写法:
            #遍历epoch次数
            for epoch in range(N_EPOCHS):
                data = DataLoader(train_data, batch_size=BATCH_SIZE, shuffle=True, collate_fn=generate_batch, drop_last=True)
                #遍历每个批量大小的数据
                for i, (input, label) in enumerate(data):
                    #第一种方式:在开始遍历每个批量大小的数据的一开始就设置,实际只要放置在loss.backward()之前即可
                    optimizer.zero_grad() 
                    output = model(input)
                    #交叉熵Cross Entropy用法第三种写法:torch.nn.CrossEntropyLoss()(内置softmax,无需显式写softmax层)=交叉熵Cross Entropy
                    #CrossEntropyLoss内置softmax,无需显式写softmax层
                    criterion = torch.nn.CrossEntropyLoss()
                    loss = criterion(output, label)
                    #第二种方式:放在反向传播求所有参数梯度(loss.backward())之前
                    #optimizer.zero_grad()  
                    loss.backward()
                    optimizer.step()
                #每个epoch结束时,调用优化器步长调节方法, 用来衰减学习率
                scheduler.step()
                
    4.第四种写法:
            class 自定义类名model(nn.Module) #必须继承nn.Module
                def __init__(self, ...)
                def forward(self, ...)
 
            #遍历epoch次数
            for epoch in range(N_EPOCHS):
                data = DataLoader(train_data, batch_size=BATCH_SIZE, shuffle=True, collate_fn=generate_batch, drop_last=True)
                #遍历每个批量大小的数据
                for i, (input, label) in enumerate(data):
                    #使用继承了继承nn.Module的自定义类实例对象model调用zero_grad()
                    #在开始遍历每个批量大小的数据的一开始就设置,实际只要放置在loss.backward()之前即可
                    自定义类实例对象model.zero_grad()
		  output = 自定义类实例对象model(input)
                    #交叉熵Cross Entropy用法三种写法:
                    #   torch.nn.CrossEntropyLoss()(内置softmax,无需显式写softmax层) = 交叉熵Cross Entropy
                    #   F.log_softmax + F.nll_loss 或者 nn.LogSoftmax + nn.NLLLoss
                    #CrossEntropyLoss内置softmax,无需显式写softmax层
                    criterion = torch.nn.CrossEntropyLoss()
                    loss = criterion(output, label)
                    #放在反向传播求所有参数梯度(loss.backward())之前
                    #自定义类实例对象model.zero_grad()
                    loss.backward()
                    # 更新模型中所有的参数
                    for p in 自定义类实例对象model.parameters():
		      #add_:函数名末尾带有下划线代表变量原地修改值,并不需要返回修改好的新值
                        p.data.add_(-learning_rate, p.grad.data)

    5.第五种写法:
            class 自定义类名model(nn.Module) #必须继承nn.Module
                def __init__(self, ...)
                def forward(self, ...)

	   #优化器
	   optimizer = torch.optim.SGD(model.parameters(), lr=0.01)
	   #optimizer = torch.optim.Adam(rnn.parameters(), lr=0.01)

            #遍历epoch次数
            for epoch in range(N_EPOCHS):
                data = DataLoader(train_data, batch_size=BATCH_SIZE, shuffle=True, collate_fn=generate_batch, drop_last=True)
                #遍历每个批量大小的数据
                for i, (input, label) in enumerate(data):
                    #在开始遍历每个批量大小的数据的一开始就设置,实际只要放置在loss.backward()之前即可
                    optimizer.zero_grad() #第一种用法:使用优化器对象调用.zero_grad()
		  #自定义类实例对象model.zero_grad() #第二种用法:使用自定义类实例对象model调用.zero_grad()
                    output = model(input)
                    #交叉熵Cross Entropy用法三种写法:
                    #   torch.nn.CrossEntropyLoss()(内置softmax,无需显式写softmax层) = 交叉熵Cross Entropy
                    #   F.log_softmax + F.nll_loss 或者 nn.LogSoftmax + nn.NLLLoss
                    #CrossEntropyLoss内置softmax,无需显式写softmax层
                    criterion = torch.nn.CrossEntropyLoss()
                    loss = criterion(output, label)
                    #放在反向传播求所有参数梯度(loss.backward())之前
                    #自定义类实例对象model.zero_grad()
                    loss.backward()
                    # 更新模型中所有的参数
		  optimizer.step() #只能使用优化器对象调用.zero_grad()
    1.torch.nn.CrossEntropyLoss()(内置softmax,无需显式写softmax层)= 交叉熵Cross Entropy
    2.nn.LogSoftmax + nn.NLLLoss() = 交叉熵Cross Entropy
    3.F.log_softmax + F.nll_loss() = 交叉熵Cross Entropy
    4.也可以 F.log_softmax + nn.NLLLoss() 一起使用
    ------------------------------------
    1.out = F.log_softmax(input, dim=-1)
    2.softmax = nn.LogSoftmax(dim=-1) 
      out = softmax(input)
    ------------------------------------
    1.criterion = torch.nn.CrossEntropyLoss()
      loss = criterion(output, target)
    2.criterion = nn.NLLLoss()
      loss = criterion(output, target)
    3.loss = F.nll_loss(output, target)

1.torch.nn.CrossEntropyLoss()(内置softmax,无需显式写softmax层)=交叉熵Cross Entropy
2.optimizer优化器 = torch.optim.SGD(model.parameters(), lr=学习率初始值)
3.学习率自动调整器scheduler = torch.optim.lr_scheduler.StepLR(optimizer, 1.0, gamma=0.95)
    class torch.optim.lr_scheduler.StepLR(optimizer, step_size, gamma=0.1, last_epoch=-1)
        optimizer(Optimizer对象)--优化器
        step_size(整数类型): 调整学习率的步长,每过step_size次,更新一次学习率。每执行一次scheduler.step()为一个step
        gamma(float 类型):学习率下降的乘数因子
        last_epoch(int类型):最后一次epoch的索引,默认为-1.

# 模型初始化后, 接下来进行损失函数和优化方法的选择.
# 关于损失函数, 我们使用nn自带的交叉熵损失
criterion = nn.CrossEntropyLoss()
# 学习率初始值定为5.0
lr = 2.0
# 优化器选择torch自带的SGD随机梯度下降方法, 并把lr传入其中
optimizer = torch.optim.SGD(model.parameters(), lr=lr)
# 定义学习率调整方法, 使用torch自带的lr_scheduler, 将优化器传入其中.
scheduler = torch.optim.lr_scheduler.StepLR(optimizer, 1.0, gamma=0.95)
        训练模式:
        for epoch in range(1, epochs + 1):
            model.train() #开启训练模式
            total_loss = 0
            #循环遍历出每一个批量大小的输入数据
            for 批量输入数据input in dataset:
                optimizer.zero_grad() #每个批量开始训练前先把优化器初始梯度置为0梯度
                output = model(input) #将数据装入model得到输出
                loss = criterion(output, targets) # 将输出和目标数据传入损失函数对象
                loss.backward() # 损失进行反向传播
                # 使用nn自带的clip_grad_norm_方法进行梯度规范化, 防止出现梯度消失或爆炸
                #梯度裁剪:限定梯度值在-0.5到0.5之间
                torch.nn.utils.clip_grad_norm_(model.parameters(), 0.5)
                optimizer.step() # 模型参数进行更新
                total_loss += loss.item() # 将每个批量数据的损失相加获得总的损失
            scheduler.step() #每个epoch都会对优化方法的学习率做调整
        预测值 output.view(-1, ntokens)
            [35, 20, 28785] 即 [句子最大长度, 批量大小, 语料不重复词汇总数] 
            变成 [35*20, 28785] 即 [句子最大长度*批量大小, 语料不重复词汇总数] 
            
        目标值 targets
            [句子最大长度*批量大小] 即 [句子最大长度*批量大小] 
            
        criterion(output.view(-1, ntokens), targets)
            对输出形状扁平化, 变为全部词汇的概率分布。
            1.criterion([句子最大长度*批量大小, 语料不重复词汇总数], [句子最大长度*批量大小])
              criterion([700, 28785], [700])
            2.700:代表700个元素值,每个元素值均为单词映射成对应的在词汇表中的索引值
              28785:代表语料不重复词汇总数,即词汇表大小,此处实际为28785个类别的概率值
            3.比较方法:
                output和targets各有700个单词对应的在词汇表中的索引值,
                那么output中700个单词索引中的每个单词索引均对应一个28785个类别的概率值,
                因此实际获取的是每个单词索引值对应的28785个类别中的最大概率值的下标值,
                如果下标值等于targets中该单词索引值的话,那么预测成功。
    评估模式:
    for epoch in range(1, epochs + 1):
        model.eval() #开启评估模式
        total_loss = 0
        with torch.no_grad():
            #循环遍历出每一个批量大小的输入数据
            for 批量输入数据input in dataset:
                output = model(input) #将数据装入model得到输出
                loss = criterion(output, targets) # 将输出和目标数据传入损失函数对象
                total_loss += loss.item()         # 将每个批量数据的损失相加获得总的损失
1.model.train()
    在train模式下,dropout网络层会按照设定的参数p设置保留激活单元的概率(保留概率=p); 
    batchnorm层会继续计算数据的mean和var等参数并更新。

2.model.eval()
    在PyTorch中进行validation时,会使用model.eval()切换到测试模式。
    model.eval()主要用于通知dropout层和batchnorm层在train和val模式间切换。
    在val模式下,dropout层会让所有的激活单元都通过,而batchnorm层会停止计算和更新mean和var,直接使用在训练阶段已经学出的mean和var值。
    该模式不会影响各层的gradient计算行为,即gradient计算和存储与training模式一样,只是不进行反传(backprobagation)。

3.更推荐使用 with torch.zero_grad()
    主要是用于停止autograd模块的工作,以起到加速和节省显存的作用,具体行为就是停止gradient计算,
    从而节省了GPU算力和显存,但是并不会影响dropout和batchnorm层的行为。

4.使用场景
    如果不在意显存大小和计算时间的话,仅仅使用model.eval()已足够得到正确的validation的结果;
    而with torch.zero_grad()则是更进一步加速和节省gpu空间(因为不用计算和存储gradient),从而可以更快计算,也可以跑更大的batch来测试。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

あずにゃん

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值