概述模型训练过程中loss 下降并不等于模型真的好。一个模型可能在训练集上表现很好但对新数据预测很差这就是过拟合。评估的目的是判断模型在未见数据上的效果。分类任务常见评估内容训练集指标模型是否学会当前训练数据。验证集指标用于调参、选模型、早停。测试集指标用于最终报告模型泛化效果。Accuracy预测正确比例。混淆矩阵查看每个类别错在哪里。读完本文你应该能区分训练集、验证集、测试集手写 Accuracy封装评估函数并知道什么时候该看哪些指标。数据集划分训练集、验证集、测试集三类数据的职责不同数据集用途是否参与参数更新训练集训练模型参数是验证集调超参数、选择模型否测试集最终评估泛化效果否典型流程训练集用于 loss.backward 和 optimizer.step 验证集每轮训练后评估决定是否调整模型 测试集所有选择完成后只评估一次不要用测试集反复调参否则测试集就不再是客观评估。Accuracy最基础的分类指标Accuracy 的定义Accuracy预测正确样本数总样本数 Accuracy \frac{预测正确样本数}{总样本数}Accuracy总样本数预测正确样本数​Paddle 代码importpaddledefaccuracy(logits,labels):predpaddle.argmax(logits,axis1)correctpredlabelsreturnpaddle.mean(correct.astype(float32))其中logits: [batch_size, num_classes] labels: [batch_size] pred: [batch_size]对于[N, C]的 logitsaxis1是类别维。batch 平均与样本加权平均很多入门代码这样算平均准确率total_accfloat(acc.numpy())batch_count1avg_acctotal_acc/batch_count这叫 batch 平均。如果每个 batch 大小一致它和样本平均基本一致。但最后一个 batch 可能较小更严格的做法是按样本数加权defevaluate_accuracy(model,loader):model.eval()correct_total0sample_total0withpaddle.no_grad():forbatch_x,batch_yinloader:logitsmodel(batch_x)predpaddle.argmax(logits,axis1)correctpaddle.sum((predbatch_y).astype(int64))correct_totalint(correct.numpy())sample_totalbatch_y.shape[0]returncorrect_total/sample_total正式报告指标时建议使用样本加权方式。评估函数同时返回 loss 和 accuracy常用评估函数importpaddle.nn.functionalasFdefevaluate(model,loader):model.eval()loss_total0.0correct_total0sample_total0withpaddle.no_grad():forbatch_x,batch_yinloader:logitsmodel(batch_x)lossF.cross_entropy(logits,batch_y,reductionsum)predpaddle.argmax(logits,axis1)correctpaddle.sum((predbatch_y).astype(int64))loss_totalfloat(loss.numpy())correct_totalint(correct.numpy())sample_totalbatch_y.shape[0]returnloss_total/sample_total,correct_total/sample_total这里使用reductionsum再除以总样本数避免最后一个 batch 大小不同导致平均失真。model.eval 与 no_grad评估时应使用model.eval()withpaddle.no_grad():logitsmodel(batch_x)原因model.eval()切换 Dropout、BatchNorm 等层的行为。paddle.no_grad()不记录梯度节省内存和计算。评估阶段不应更新参数。即使当前模型只有Linear和ReLU也建议养成这个习惯。验证集用于训练过程中的模型选择训练循环中常见写法best_val_acc0.0forepochinrange(num_epochs):train_loss,train_acctrain_one_epoch(model,train_loader,optimizer)val_loss,val_accevaluate(model,val_loader)ifval_accbest_val_acc:best_val_accval_acc paddle.save(model.state_dict(),best_model.pdparams)print(epoch,train_loss,train_acc,val_loss,val_acc)验证集用于判断是否过拟合。选择最佳 epoch。调整学习率、模型大小、正则化策略。决定是否早停。测试集只做最终评估测试集应该尽量少用。一个良好的流程是训练集训练多个候选模型 验证集选择最佳模型和超参数 加载最佳模型 测试集评估一次 报告测试指标示例model.set_state_dict(paddle.load(best_model.pdparams))test_loss,test_accevaluate(model,test_loader)print(test_loss:,test_loss,test_acc:,test_acc)如果你根据测试集结果反复调模型测试集就相当于被“训练过程看见了”最终指标会偏乐观。混淆矩阵知道错在哪个类别Accuracy 只告诉你总体对不对混淆矩阵能告诉你类别之间如何混淆。二分类混淆矩阵预测 0 预测 1 真实 0 TN FP 真实 1 FN TP简单实现defconfusion_matrix(model,loader,num_classes):matrixpaddle.zeros([num_classes,num_classes],dtypeint64)model.eval()withpaddle.no_grad():forbatch_x,batch_yinloader:logitsmodel(batch_x)predpaddle.argmax(logits,axis1)fortrue_label,pred_labelinzip(batch_y.numpy(),pred.numpy()):matrix[int(true_label),int(pred_label)]1returnmatrix行表示真实类别列表示预测类别。混淆矩阵适合排查哪个类别最难识别。是否严重偏向某个类别。类别不均衡是否影响模型。Top-K Accuracy多类别任务常见指标当类别很多时Top-1 不一定足够。Top-K Accuracy 判断真实类别是否出现在前 K 个预测中。deftopk_accuracy(logits,labels,k5):_,indicespaddle.topk(logits,kk,axis1)labelslabels.reshape([-1,1])correctpaddle.any(indiceslabels,axis1)returnpaddle.mean(correct.astype(float32))适用场景图像分类类别很多。推荐候选排序。检索任务。二分类通常不需要 Top-K。评估日志如何判断模型状态常见现象训练集验证集判断loss 下降acc 上升loss 下降acc 上升正常学习acc 很高acc 明显低可能过拟合acc 不上升acc 不上升可能欠拟合或训练错误loss 变 NaN指标异常数值不稳定如果训练集和验证集都差优先排查数据和标签是否正确。模型输出 shape 是否正确。loss 是否接收 logits。学习率是否合适。如果训练集好、验证集差再考虑正则化、数据增强、减小模型等方法。常见错误错误一验证阶段忘记 eval应写model.eval()尤其是含Dropout、BatchNorm的模型。错误二验证阶段仍然 backward验证阶段不更新参数不调用loss.backward()optimizer.step()错误三Accuracy 的 axis 写错对于[N, C]logitspredpaddle.argmax(logits,axis1)错误四用测试集调参测试集只用于最终评估不应反复用于模型选择。错误五最后一个 batch 影响平均指标正式指标建议按样本数加权而不是简单 batch 平均。总结评估决定模型是否真的可用评估不是训练后的附属步骤而是判断模型质量的核心环节训练集看模型是否学会训练数据。验证集用于调参和选择最佳模型。测试集用于最终泛化报告。Accuracy 是最基础分类指标。混淆矩阵能帮助定位类别级错误。评估阶段要使用model.eval()和paddle.no_grad()。如果只能记住一句话那就是训练 loss 只能说明模型正在优化验证集和测试集指标才说明模型是否真的泛化。