文章目录01 本篇要解决什么问题02 背景训练就是用样本约束参数03 核心原理把训练循环拆开理解1先手算一次梯度下降2反向传播负责链式求导3batch、step与epoch有什么关系4学习率和优化器决定怎么走5训练、验证、测试分别回答什么6保存最优模型要保存当时的数值7损失曲线怎么读先明确它来自哪里04 一个具体例子训练一个二维点分类器05 常见问题与自测06 本篇回顾与下一步01 本篇要解决什么问题训练循环不长但读懂它需要回答几个问题损失下降为什么能改变预测batch与epoch有什么关系训练集表现很好能不能说明模型已经学会了本篇先用一个能手算的例子解释梯度更新再完成一个合成数据二分类任务。重点是理解训练流程中每一步的作用。本篇关键词损失、梯度、学习率、mini-batch、验证集、过拟合。完成标志能手算一次更新并运行具有独立训练、验证、测试环节的脚本。练习约定默认CPU数据由程序生成不下载真实数据集。示例结果只说明这个合成任务上的表现。02 背景训练就是用样本约束参数模型用参数θ \thetaθ把输入x xx映射成预测f θ ( x ) f_\theta(x)fθ(x)损失函数衡量预测与目标y yy的差异。最基础的经验风险形式为J ( θ ) 1 N ∑ i 1 N ℓ ( f θ ( x i ) , y i ) . J(\theta)\frac{1}{N}\sum_{i1}^{N}\ell(f_\theta(x_i),y_i).J(θ)N1i1∑Nℓ(fθ(xi),yi).训练希望找到让训练目标较小的参数。这个目标来自有限样本因此“训练误差小”与“新样本表现好”之间还隔着泛化问题。数据划分和验证过程就是为了观察这种差别。03 核心原理把训练循环拆开理解1先手算一次梯度下降设只有一个参数w ww输入x 2 x2x2目标y 3 y3y3预测为w x wxwx损失为L ( w ) ( 2 w − 3 ) 2 , d L d w 4 ( 2 w − 3 ) . L(w)(2w-3)^2,\qquad \frac{dL}{dw}4(2w-3).L(w)(2w−3)2,dwdL4(2w−3).初始化w 0 w0w0损失为9梯度为− 12 -12−12。若学习率η 0.1 \eta0.1η0.1w n e w w − η d L d w 1.2 , L ( w n e w ) 0.36. w_{\mathrm{new}}w-\eta\frac{dL}{dw}1.2, \qquad L(w_{\mathrm{new}})0.36.wneww−ηdwdL1.2,L(wnew)0.36.梯度描述局部变化趋势更新沿负梯度方向走一小步。这里一步就明显改善是因为问题简单、学习率合适复杂网络没有“每一步损失必然下降”的保证。2反向传播负责链式求导神经网络把多个函数串起来反向传播沿计算关系应用链式法则把最终损失对各层参数的导数求出来。前向传播计算预测和损失反向传播计算梯度优化器根据梯度更新参数。若某个量被转成普通Python数值后再重新包装成Tensor原来的计算关系不会自动恢复。模型输出参与损失计算的路径需要保持可求导。为了独立验证导数配套gradient_numpy.py用中心差分近似梯度再与解析结果比较。差分适合检查小例子不适合替代大模型的反向传播。3batch、step与epoch有什么关系batch是一批样本本篇每处理一批并更新一次参数算一个优化stepepoch表示训练集按当前采样方式完整遍历一轮。256个训练样本batch size为50且不丢弃尾批每轮有⌈ 256 / 50 ⌉ 6 \lceil256/50\rceil6⌈256/50⌉6个batch最后一批只有6个样本。如果使用梯度累积、多次采样或drop_lastTruebatch与优化step的关系就要重新计算。统计整轮平均损失时应按样本数加权。本篇分类任务每个样本一个损失采用batch_mean × batch_size累加后除以样本总数。若有忽略标签、逐像素损失等情况分母还应与实际有效元素及损失定义保持一致。4学习率和优化器决定怎么走SGD按当前梯度方向更新动量引入历史方向信息Adam结合梯度的一阶与二阶矩估计调整更新。它们都需要合理学习率也都可能训练失败不能把换优化器当成通用修复。学习率过大可能震荡或发散过小可能进展缓慢。先用小数据确认流程能拟合再扩大数据、调整学习率和正则化通常比一开始同时改变很多选项更容易定位问题。普通训练中每批先清梯度再反向传播和更新。若有意累积多个微批次梯度需要按目标平均方式缩放损失微批次大小不同时简单除以微批次数不一定等价于整个大批次的样本平均。5训练、验证、测试分别回答什么训练集用于计算梯度验证集用于选择轮次、超参数和阈值测试集在方案确定后做最终评价。测试集如果反复参与选择也会逐渐成为调参数据。本篇从同一个已知生成规则顺序抽取三组独立随机样本因此可以清楚区分用途。真实项目还要考虑同一患者、同一设备、同一视频或时间相邻样本之间的关联不能只靠随机打乱。数据划分与泄漏会在第34篇进一步展开。验证时通常配合model.eval()和torch.no_grad()避免训练状态与梯度记录影响评价流程。相关基础可参阅PyTorch优化教程。6保存最优模型要保存当时的数值本篇按验证损失最小选择权重并立即保存CPU副本。若只写best_state model.state_dict()留在内存字典中的Tensor仍可能引用后续会变化的状态应使用深拷贝或复制Tensor或者当时直接序列化保存。这个权重文件用于最终推理。若要中断后精确接续训练还应保存优化器、调度器、轮次及相关随机状态不能把“加载权重”直接等同于“完整恢复训练”。7损失曲线怎么读先明确它来自哪里训练损失下降而验证损失持续上升可能提示过拟合也要检查数据分布和预处理是否一致。两者都不下降先检查标签、损失输入、梯度和学习率。指标异常好还要排查数据泄漏。固定随机种子便于比较但不意味着不同硬件、版本和算子实现能逐位一致。图中的曲线来自明确定义的单参数数学例子不是实际分类训练日志。图左侧为L ( w ) ( 2 w − 3 ) 2 L(w)(2w-3)^2L(w)(2w−3)2的计算结果右侧说明三类数据的职责。04 一个具体例子训练一个二维点分类器先看配套examples/gradient_numpy.py它检查解析梯度与有限差分的一致性并通过100次更新拟合y 2 x 0.5 y2x0.5y2x0.5。它只需要NumPy。python examples/gradient_numpy.py接下来把下面完整代码保存为examples/train_classifier.py。二维点满足x 1 0.5 x 2 0 x_10.5x_20x10.5x20时标记为1否则为0模型输出两个类别的原始分数。A small, complete train/validation/test pipeline on synthetic 2-D points.importargparseimportjsonfrompathlibimportPathimporttorchfromtorchimportnnfromtorch.utils.dataimportDataLoader,TensorDatasetdefmake_dataset(n,generator):xtorch.randn(n,2,generatorgenerator)y(x[:,0]0.5*x[:,1]0).long()returnTensorDataset(x,y)defevaluate(model,loader,device):model.eval()total_loss,correct,count0.0,0,0withtorch.no_grad():forx,yinloader:x,yx.to(device),y.to(device)logitsmodel(x)total_lossnn.functional.cross_entropy(logits,y,reductionsum).item()correct(logits.argmax(dim1)y).sum().item()county.numel()return{loss:total_loss/count,accuracy:correct/count}defmain():parserargparse.ArgumentParser(description__doc__)parser.add_argument(--device,choices[cpu,cuda],defaultcpu)parser.add_argument(--epochs,typeint,default20)parser.add_argument(--output,typePath,defaultPath(artifacts/classifier))argsparser.parse_args()ifargs.epochs1:parser.error(--epochs must be positive)ifargs.devicecudaandnottorch.cuda.is_available():parser.error(CUDA requested but unavailable)torch.manual_seed(42)generatortorch.Generator().manual_seed(123)train_datamake_dataset(256,generator)val_datamake_dataset(96,generator)test_datamake_dataset(96,generator)train_loaderDataLoader(train_data,batch_size50,shuffleTrue,num_workers0,generatortorch.Generator().manual_seed(456))val_loaderDataLoader(val_data,batch_size50,num_workers0)test_loaderDataLoader(test_data,batch_size50,num_workers0)devicetorch.device(args.device)modelnn.Sequential(nn.Linear(2,16),nn.ReLU(),nn.Linear(16,2)).to(device)optimizertorch.optim.Adam(model.parameters(),lr0.02)args.output.mkdir(parentsTrue,exist_okTrue)checkpointargs.output/best_weights.ptbest_val_lossfloat(inf)best_epochNonehistory[]forepochinrange(1,args.epochs1):model.train()train_loss,count0.0,0forx,yintrain_loader:x,yx.to(device),y.to(device)optimizer.zero_grad(set_to_noneTrue)logitsmodel(x)lossnn.functional.cross_entropy(logits,y)ifnottorch.isfinite(loss).item():raiseRuntimeError(Non-finite training loss)loss.backward()optimizer.step()train_lossloss.item()*y.numel()county.numel()valevaluate(model,val_loader,device)row{epoch:epoch,train_loss:train_loss/count,val_loss:val[loss],val_accuracy:val[accuracy]}history.append(row)print(json.dumps(row))ifval[loss]best_val_loss:best_val_loss,best_epochval[loss],epoch cpu_state{k:v.detach().cpu().clone()fork,vinmodel.state_dict().items()}torch.save(cpu_state,checkpoint)model.load_state_dict(torch.load(checkpoint,map_locationdevice,weights_onlyTrue))# Evaluate the test set once, after choosing the checkpoint using validation only.testevaluate(model,test_loader,device)report{seed:42,data_seed:123,torch:torch.__version__,device:str(device),best_epoch:best_epoch,best_val_loss:best_val_loss,test:test,history:history,note:synthetic example; not a real-world benchmark}(args.output/metrics.json).write_text(json.dumps(report,indent2),encodingutf-8)print(test:,test)if__name____main__:main()从项目根目录执行PowerShell与Bash均适用python examples/train_classifier.py--device cpu--epochs 20脚本逐轮输出训练损失、验证损失和验证准确率按验证损失保存权重最后加载所选权重并评价一次测试集。结果写入artifacts/classifier/metrics.json真实数值以你的运行结果为准。观察时先确认文件生成、数值有限和流程正确再看任务表现。合成任务很简单即使准确率较高也不能推导真实图像任务同样容易。本文没有预设或编造一组分类训练成绩。05 常见问题与自测问题1损失下降是不是准确率每一步都会提高不会。损失通常是连续量准确率取决于离散类别判断两者变化不必同步。问题2训练集准确率很高测试集很低先检查什么检查划分、预处理、标签映射和训练/评估状态再分析过拟合与分布差异不能直接归因于模型太小。问题3为什么不同大小的batch不能直接平均损失均值那会给小批次与大批次相同权重。本篇按每批样本数加权得到整轮的逐样本平均。问题4验证集表现最好的一轮一定是最后一轮吗不一定因此保存验证指标最优的权重。最终使用哪种选择规则应在实验前明确。问题5固定seed之后所有机器结果必须相同吗不能这样保证。还涉及框架版本、硬件、非确定性算子及数据加载过程复现时需要一起记录。06 本篇回顾与下一步训练的核心是用可求导目标约束参数并用独立评价观察泛化。完整流程既包括更新参数也包括指标统计、选择权重和保存结果。中文常见英文或写法梯度下降Gradient Descent反向传播Backpropagation学习率Learning Rate过拟合Overfitting检查点Checkpoint下一篇认识常见模型结构重点看每类结构如何组织信息以及输出怎样匹配分类、分割和重建等任务。参考与延伸阅读PyTorch自动求导入门PyTorch优化器文档scikit-learn数据泄漏与常见陷阱PyTorch可复现性说明
阅读完成 · 觉得有帮助?