日萌社
人工智能AI:Keras PyTorch MXNet TensorFlow PaddlePaddle 深度学习实战(不定时更新)
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来测试。