本章介绍训练过程中的损失函数、梯度下降、模型评估
(1)损失函数
# 采用交叉熵 损失函数
criterion = paddle.nn.loss.CrossEntropyLoss()
loss = criterion(probs, labels)
交叉熵
- 交叉熵能够衡量同一个随机变量中的两个不同概率分布的差异程度,在机器学习中就表示为真实概率分布与预测概率分布之间的差异。
- 交叉熵的值越小,模型预测效果就越好。
- 交叉熵经常搭配softmax使用,将输出的结果进行处理,使其多个分类的预测值和为1,再通过交叉熵来计算损失。
PaddlePaddle中将softmax操作、交叉熵损失函数的计算过程进行合并,从而提供了数值上更稳定的计算。
input (Tensor) – 维度为 [N1,N2,…,Nk,C][N1,N2,…,Nk,C] 的多维Tensor,其中最后一维C是类别数目。数据类型为float32或float64。
label (Tensor) – 输入input对应的标签值。若soft_label=False,要求label维度为 [N1,N2,…,Nk][N1,N2,…,Nk] 或 [N1,N2,…,Nk,1][N1,N2,…,Nk,1] ,数据类型为’int32’, ‘int64’, ‘float32’, ‘float64’,且值必须大于等于0且小于C;若soft_label=True,要求label的维度、数据类型与input相同,且每个样本各软标签的总和为1。
返回:表示交叉熵结果的Tensor,数据类型与input相同。若soft_label=False,则返回值维度与label维度相同;若soft_label=True,则返回值维度为 [N1,N2,…,Nk,1][N1,N2,…,Nk,1] 。
将前向计算后得到的probs和labels作为损失函数的输入,得出loss为:
(2)计算准确率
# 评估的时候采用准确率指标
metric = paddle.metric.Accuracy()
correct = metric.compute(probs, labels)
metric.update(correct)
acc = metric.accumulate()
(3)输出训练指标
# 每间隔 10 step 输出训练指标
if global_step % 10 == 0:
print(
"global step %d, epoch: %d, batch: %d, loss: %.5f, accu: %.5f, speed: %.2f step/s"
% (global_step, epoch, step, loss, acc,
10 / (time.time() - tic_train)))
tic_train = time.time()
(4)反向传播
定义优化器:AdamW
optimizer = paddle.optimizer.AdamW(
learning_rate=lr_scheduler,
parameters=model.parameters(),
weight_decay=0.0,
apply_decay_param_fun=lambda x: x in decay_params)
-
learning_rate:学习率
lr_scheduler = LinearDecayWithWarmup(5E-5, num_training_steps, 0.0)
创建一个学习速率调度器,它可以线性地提高学习速率,从0到给定的’ learning_rate ',在这个热身阶段之后的学习速率
将从基础学习率线性下降到0。
-
apply_decay_param_fun:传入函数时,只有可以使 apply_decay_param_fun(Tensor.name)==True的Tensor会进行weight decay更新。只有在想要指定特定需要进行weight decay更新的参数时使用。默认值为None。
weight decay:L2正则化的目的就是为了让权重衰减到更小的值,在一定程度上减少模型过拟合的问题,所以权重衰减也叫L2正则化。
decay_params = [ p.name for n, p in model.named_parameters() if not any(nd in n for nd in ["bias", "norm"]) ]
对损失函数求导后,更新梯度和学习率,最后清除第一轮Batch模型中所有优化参数的梯度。
loss.backward()
optimizer.step()
lr_scheduler.step()
optimizer.clear_grad()
(5)评估损失
在验证集中评估损失、准确率
def evaluate(model, criterion, metric, data_loader, phase="dev"):
model.eval()
metric.reset()
losses = []
for batch in data_loader:
input_ids, token_type_ids, labels = batch
probs = model(input_ids=input_ids, token_type_ids=token_type_ids)
loss = criterion(probs, labels)
losses.append(loss.numpy())
correct = metric.compute(probs, labels)
metric.update(correct)
accu = metric.accumulate()
print("eval {} loss: {:.5}, accu: {:.5}".format(phase,
np.mean(losses), accu))
model.train()
metric.reset()
在训练过程中,每隔10steps就打印验证集中的评估结果
if global_step % 10 == 0:
evaluate(model, criterion, metric, dev_data_loader, "dev")