ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Pytorch训练可视化利器WandB:从安装到实战监控全攻略

Pytorch训练可视化利器WandB:从安装到实战监控全攻略 训练深度学习模型的时候最怕什么不是模型效果差而是训了一整天你只能对着终端里滚动的loss数值发呆。loss到底是收敛了还是震荡了第100个epoch之后是不是已经开始过拟合学习率衰减是不是压错了节奏梯度爆炸是不是从第50步就埋下了隐患这些问题单靠盯着print输出基本等于闭着眼睛开车。Pytorch用户习惯了手写训练循环print出来的信息一多终端屏直接乱成一锅粥。这时候训练过程可视化就是刚需。我以前最早用TensorBoard后来换到WandBWeights Biases一句话总结TensorBoard是被动看板WandB是主动直播。这篇内容面向正在用Pytorch写训练代码、想看清训练过程、想管理好每次实验的朋友。我会从安装、最简接入、进阶玩法到常见报错全部捋一遍并把实际跑实验踩过的坑都写出来。在整套Pytorch可视化系列里训练过程监控绝对是最实用的一环。1. 训练过程可视化到底在解决什么问题1.1 深度学习训练的“黑盒”困境深度学习的训练本质上是一个迭代优化过程你定义好模型结构、损失函数、优化器把数据喂进去让梯度带着参数往损失更小的方向挪。这个过程少则几百步多则几十万步。问题在于我们几乎看不到每一步模型内部发生了什么只能通过一些间接指标去推测它的健康状态。如果把训练比作养花你每天浇水施肥但埋在上里的根系是看不到的。你能看到的只有叶子颜色loss曲线和株高精度指标这些表象。一旦根系出了问题等叶子发黄往往就晚了。训练也是一样早期发现异常和等训练结束再复盘成本完全是两个量级。我在实际项目中见过太多这样的案例有人在服务器上启动实验睡一觉起来发现loss已经变成NaN整个训练白跑。也有人好不容易把模型训到90%以上的准确率但换一组超参数重训时忘了当时用的是哪份配置复现实验只能靠翻聊天记录。可视化的第一个价值是实时监控让你在训练过程中及时察觉异常第二个价值是实验管理让每次实验的配置、指标、产物都有据可查。不管你是做图像分类、目标检测、语义分割还是强化学习、Seq2Seq、Transformer只要是用Pytorch在写训练循环可视化监控这件事都跑不掉。1.2 用这些指标判断模型是否健康训练过程最常看的指标有Loss曲线判断收敛趋势和收敛速度Accuracy、Precision、Recall等评价指标学习率的变化轨迹梯度的范数判断是否梯度消失或爆炸参数权重的分布观察训练过程是否异常验证集曲线与训练集曲线的差距判断过拟合这些指标如果松散的print出来很难看出趋势。更关键的是你没法把曲线和具体的超参数一一对应。同样的loss曲线背后可能是batch_size不同、learning rate不同、数据增强方式不同。可视化工具的真正价值在于把指标和配置绑定到一起方便做归因分析。这正是WandB做得最顺手的地方。它不只是记录数值还把每次实验的配置、代码状态、环境信息、产物都归档到一个统一的实验看板中。2. WandB选型为什么不用TensorBoard2.1 WandB核心能力一览WandB是Weights Biases的缩写定位是机器学习实验跟踪平台。2017年发布目前在学术和工业界都用得非常广泛。我最初对它的认知是“一个云端的TensorBoard”但用久了发现它的核心价值不只是可视化而是“实验生命周期管理”。主要能力包括训练指标实时曲线超参数自动追踪与表格对比模型结构与参数监控图像、音频、文本等样本可视化多轮实验对比分析团队共享与协作自动生成实验报告与Sweep联动进行超参数自动搜索我对这个工具的定位很直白如果你还在靠Excel表格管理实验结果WandB就是那些表格的现代化替代品并且自带图表和分享能力。2.2 与TensorBoard的对比为了让你快速看清两者的差异我把这几年实际使用的感受整理成了一个对比表对比项TensorBoardWandB部署方式本地webserver云端服务也支持私有化部署数据存储本地日志文件云端或本地存储实验对比需手动组织日志自动归档跨实验对比极方便共享协作需要共享日志文件链接分享权限可控超参数检索能力弱能力强支持过滤与分组与Pytorch集成需要手动写SummaryWriter三行代码即可接入离线能力天然离线支持offline模式但核心体验在云端我之所以从TensorBoard切到WandB最直接的原因是它解决了我的“历史包袱”。以前用TensorBoard每个实验的logs目录我都要手动管理时间一长哪份日志对应哪个模型完全对不上。更麻烦的是换了机器之后本地的event文件散落到各处几乎不可追溯。用到WandB之后每次实验的工程名、配置、loss曲线、最终指标都会自动归档到同一个project下网页端打开就能查。这感觉就像有了一个统一的历史仓库彻底告别了“我的logs文件夹里都是什么鬼”的困境。3. 环境准备与安装3.1 确保Pytorch环境可用先说一个前提WandB本身不依赖Pytorch也能单独使用但既然我们的场景是Pytorch训练过程可视化还是得先保证Pytorch环境是通的。从我接触到的反馈看很多人在这个环节就被卡住了。新建一个干净的conda环境是比较稳妥的做法conda create -n wandb_demo python3.9 conda activate wandb_demo然后根据本机是否具备NVIDIA GPU来安装Pytorch。如果只是先跑通流程CPU版本完全够用如果有NVIDIA显卡先确认驱动支持的CUDA版本nvidia-smi这里有个常见的误解很多人看到nvidia-smi显示的CUDA Version: 12.2就以为必须安装CUDA 12.2版本的Pytorch。其实nvidia-smi显示的是驱动支持的最高CUDA版本Pytorch要求的CUDA运行时版本只要不高于这个数字就行。比如驱动支持到12.2装cu121的Pytorch完全没问题。比较稳妥的安装方式# CPU版本 pip install torch torchvision --index-url https://download.pytorch.org/whl/cpu # CUDA 12.1版本驱动较新的机器 pip install torch torchvision --index-url https://download.pytorch.org/whl/cu121 # 用默认源安装通常也带CUDA支持 pip install torch torchvision装完后在Python里验证一下import torch print(torch.__version__) print(torch.cuda.is_available())如果torch.cuda.is_available()返回False而你的机器又确实有NVIDIA显卡就优先检查驱动版本与Pytorch的CUDA版本匹配情况。这是整个环境搭建阶段最容易被绊倒的位置。3.2 安装并登录WandBWandB的安装过程非常轻量本质上就是一个Python包加命令行工具pip install wandb安装完成之后需要执行登录wandb login首次登录会提示你打开浏览器访问WandB官网拿到API Key并粘贴回来。如果没有浏览器环境的服务器也可以先在网页端生成API Key再直接复制回终端运行wandb login your-api-key有点要特别注意API Key属于私人凭证不要在公共仓库、分享文档里明文出现。我见过有人把key直接写进训练脚本提交到Git仓库结果被别人扒下来乱刷额度这是真实发生过的事故。登录成功之后数据会自动关联到你的个人账号。后续每次运行WandB相关脚本训练日志都会上传到这个账号对应的项目空间里。3.3 常见安装报错及处理我把安装阶段遇到的几个高频报错列一下No module named wandb包没装上或装错环境。确认当前用的是哪个conda环境重装即可。wandb: Network error或者登录超时这类问题通常出在服务器无法直连WandB云端可以优先使用离线模式后面会详细说。TypeError: __init__() got an unexpected keyword argument lambda多半是环境里的wandb和tensorflow等包版本冲突升级wandb版本一般能解决。还有个容易被忽略的点如果你的项目里同时装了老版本的pytorch-lightning和wandb在导入日志器时可能会有兼容性问题优先把两侧都升到新版本再排查。4. 快速上手三条核心代码完成日志记录4.1 init、log和configWandB在Pytorch里的用法极简核心就三个APIwandb.init()初始化一次实验wandb.config记录超参数配置wandb.log()记录训练过程中的指标曲线这三个API的组合能覆盖90%的训练过程可视化需求。先看wandb.init()import wandb run wandb.init( projectpytorch-visualization-demo, namerun-baseline, config{ epochs: 50, batch_size: 64, learning_rate: 0.001, optimizer: adam, } )project是项目名整个团队或者整个方向可以共用一个。name是本次实验的名字。如果不填WandB会自动生成一个随机名。我个人建议每次实验都显式给name尤其在批量跑实验的时候否则看板里一堆nifty-mountain-3这种名字完全对不上用途。config是超参数字典WandB会自动归档。后续在网页端可以按不同超参数分组、筛选、对比曲线。我也建议养成一个习惯一启动就把所有关键配置塞进config不要等训练跑完再回忆到时候只会漏。然后是wandb.log()for epoch in range(epochs): train_loss 0.0 for images, labels in train_loader: optimizer.zero_grad() outputs model(images) loss criterion(outputs, labels) loss.backward() optimizer.step() train_loss loss.item() avg_loss train_loss / len(train_loader) wandb.log({train_loss: avg_loss, epoch: epoch})每调用一次wandb.log()曲线图里就会多一个点。你可以同时记录多个指标比如{train_loss: avg_loss, val_acc: val_acc, lr: current_lr}。WandB完全支持按step或者按epoch打点横坐标可以自定义。4.2 一个最小可运行样例把上面两块拼在一起就是一个能本地跑起来的训练可视化示例。我写了一个用MNIST数据集的极简版本非常适合第一次上手import torch import torch.nn as nn from torch.utils.data import DataLoader from torchvision import datasets, transforms import wandb def main(): wandb.init( projectwandb-demo, namemnist-baseline, config{ epochs: 5, batch_size: 64, learning_rate: 0.001, } ) config wandb.config transform transforms.Compose([ transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081,)) ]) train_dataset datasets.MNIST(root./data, trainTrue, downloadTrue, transformtransform) test_dataset datasets.MNIST(root./data, trainFalse, transformtransform) train_loader DataLoader(train_dataset, batch_sizeconfig.batch_size, shuffleTrue) test_loader DataLoader(test_dataset, batch_sizeconfig.batch_size, shuffleFalse) model nn.Sequential( nn.Flatten(), nn.Linear(28 * 28, 128), nn.ReLU(), nn.Linear(128, 10), ) criterion nn.CrossEntropyLoss() optimizer torch.optim.Adam(model.parameters(), lrconfig.learning_rate) for epoch in range(config.epochs): model.train() train_loss 0 for images, labels in train_loader: optimizer.zero_grad() outputs model(images) loss criterion(outputs, labels) loss.backward() optimizer.step() train_loss loss.item() model.eval() correct 0 total 0 with torch.no_grad(): for images, labels in test_loader: outputs model(images) _, predicted torch.max(outputs, 1) total labels.size(0) correct (predicted labels).sum().item() val_acc correct / total wandb.log({ train_loss: train_loss / len(train_loader), val_acc: val_acc, epoch: epoch, }) print(fEpoch {epoch}: loss{train_loss / len(train_loader):.4f}, acc{val_acc:.4f}) wandb.finish() if __name__ __main__: main()跑完这段代码打开WandB项目页面就能看到train_loss和val_acc两条曲线实验的超参数、环境信息、运行时间都会自动归档。不要小看这些基础功能很多真实项目的调参过程正是从这一步开始变得清晰起来的。5. 进阶玩法把训练过程完整“直播”出来前面介绍的曲线记录只是入门。实际上WandB对Pytorch的支持远不止loss曲线。我日常工作里最常用的进阶能力下面逐一过一遍。5.1 用watch追踪模型参数与梯度训练过程中的参数分布和梯度范数是判断训练稳定性的重要参考。WandB提供了一个非常方便的函数wandb.watch(model, logall, log_freq100)调用一次WandB就会自动记录模型每一层的参数值分布、梯度值分布和梯度范数。log可选值gradients只记录梯度parameters只记录参数all两者都记录log_freq表示多少步记录一次。训练比较短时设置得小一点比如100长时间训练则设置大一点不然存储压力会变大。这个功能对排查梯度消失和梯度爆炸非常有用。我曾经训练一个Transformer结构的小模型loss在最初几百步始终不降。盯着固定步数的梯度直方图看一眼就发现参数更新的幅度比正常情况小了好几个数量级。顺着排查发现是layer norm的初始化参数没调好。如果没有这种直观的可视化光靠打印几千个浮点值根本定位不到问题。5.2 记录预测结果与图像训练视觉模型时除了看曲线很多人还想看看模型到底预测得怎么样。特别是目标检测和分割任务把预测框和真实框叠在一起画出来比任何数值都直观。WandB上传图像非常方便wandb.log({ predictions: [ wandb.Image( image, captionepoch_1_batch_2, boxes{ predictions: { box_data: [ {position: [x_min, y_min, x_max, y_max], class_id: 0, box_caption: cat}, ], class_labels: {0: cat, 1: dog} } } ) ] })分类任务也可以直接可视化一批样本和对应的预测结果sample_images next(iter(train_loader))[0][:16] sample_labels next(iter(train_loader))[1][:16] preds model(sample_images).argmax(dim1) wandb.log({ 样本预测: [wandb.Image(img, captionf真实:{label}, 预测:{pred}) for img, label, pred in zip(sample_images, sample_labels, preds)] })上传之后在网页端可以直接点击查看每张图片的预测细节。这个功能在调试模型对特定类别的识别效果时格外好用。5.3 记录自定义图表如果需要更灵活的分析图表WandB还提供了wandb.plot接口可以生成散点图、折线图、柱状图等。比如我习惯在实验结束后绘制一个“各类别准确率”的柱状图classes [plane, car, bird, cat, deer, dog, frog, horse, ship, truck] acc_by_class compute_class_acc(model, val_loader, num_classes10) data [[label, acc] for label, acc in zip(classes, acc_by_class)] table wandb.Table(datadata, columns[class, accuracy]) wandb.log({class_acc_bar: wandb.plot.bar(table, class, accuracy, title各类别准确率)})类似的还有散点图、折线图等。当你需要分析一些难以用标准指标表达的现象时这些自定义图表接口就是额外性价比工具。5.4 用sweep做超参数搜索WandB的Sweep功能是自动化超参数搜索它会自动生成一组组超参数依次或并行提交实验并把每次实验的指标汇总到一张表里。这个功能可以和Pytorch脚本无缝配合属于进阶中的进阶。wandb sweep sweep.yaml一个简单的随机搜索配置program: train.py method: random metric: name: val_acc goal: maximize parameters: learning_rate: distribution: log_uniform min: 0.0001 max: 0.01 batch_size: values: [32, 64, 128]Sweep功能在我的调参场景里用得非常多。它能把“改参数-等训练-看曲线-再改参数”的循环交给机器省下大量体力活。6. 实战案例用WandB监控一个完整的Pytorch训练流程理论聊再多不如直接看一个完整例子。这一节我把自己平时调模型时常用的一套监控模板整理出来覆盖训练、验证、模型watch、梯度日志、图像可视化几个层面。这个模板可以直接改改数据路径和模型结构用到自己的项目里。6.1 案例背景假设我们要在CIFAR-10上训练一个简单的CNN模型目标是观察不同学习率对收敛速度的影响。两次不同学习率的实验放进同一个project然后用WandB的对比功能分析差异。这里用一个小型CNN结构故意简化目的是让节奏更清楚。实际上换成ResNet、ViT等结构监控模式完全一致。6.2 核心代码实现import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader import wandb class SimpleCNN(nn.Module): def __init__(self): super().__init__() self.features nn.Sequential( nn.Conv2d(3, 32, 3, padding1), nn.ReLU(), nn.MaxPool2d(2), nn.Conv2d(32, 64, 3, padding1), nn.ReLU(), nn.MaxPool2d(2), nn.Conv2d(64, 128, 3, padding1), nn.ReLU(), nn.MaxPool2d(2), ) self.classifier nn.Sequential( nn.Flatten(), nn.Linear(128 * 4 * 4, 256), nn.ReLU(), nn.Linear(256, 10), ) def forward(self, x): return self.classifier(self.features(x)) def train_one_epoch(model, loader, optimizer, criterion, device): model.train() total_loss 0.0 total_correct 0 total_samples 0 for images, labels in loader: images, labels images.to(device), labels.to(device) optimizer.zero_grad() outputs model(images) loss criterion(outputs, labels) loss.backward() optimizer.step() total_loss loss.item() * images.size(0) _, preds torch.max(outputs, dim1) total_correct (preds labels).sum().item() total_samples images.size(0) return total_loss / total_samples, total_correct / total_samples def evaluate(model, loader, criterion, device): model.eval() total_loss 0.0 total_correct 0 total_samples 0 with torch.no_grad(): for images, labels in loader: images, labels images.to(device), labels.to(device) outputs model(images) loss criterion(outputs, labels) total_loss loss.item() * images.size(0) _, preds torch.max(outputs, dim1) total_correct (preds labels).sum().item() total_samples images.size(0) return total_loss / total_samples, total_correct / total_samples def main(): wandb.init( projectcifar10-wandb-demo, config{ learning_rate: 0.001, batch_size: 128, epochs: 20, } ) config wandb.config # 如果通过sweep调度运行sweep注入的超参数会覆盖这里的默认值 device torch.device(cuda if torch.cuda.is_available() else cpu) transform transforms.Compose([ transforms.RandomHorizontalFlip(), transforms.RandomCrop(32, padding4), transforms.ToTensor(), transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2470, 0.2435, 0.2616)), ]) train_dataset datasets.CIFAR10(root./data, trainTrue, downloadTrue, transformtransform) val_dataset datasets.CIFAR10(root./data, trainFalse, downloadTrue, transformtransforms.ToTensor()) train_loader DataLoader(train_dataset, batch_sizeconfig.batch_size, shuffleTrue, num_workers2) val_loader DataLoader(val_dataset, batch_sizeconfig.batch_size, shuffleFalse, num_workers2) model SimpleCNN().to(device) criterion nn.CrossEntropyLoss() optimizer optim.Adam(model.parameters(), lrconfig.learning_rate) wandb.watch(model, logall, log_freq200) for epoch in range(config.epochs): train_loss, train_acc train_one_epoch(model, train_loader, optimizer, criterion, device) val_loss, val_acc evaluate(model, val_loader, criterion, device) lr_now optimizer.param_groups[0][lr] wandb.log({ epoch: epoch, train_loss: train_loss, train_acc: train_acc, val_loss: val_loss, val_acc: val_acc, lr: lr_now, }) if epoch % 5 0: sample_images, sample_labels next(iter(val_loader)) sample_images, sample_labels sample_images[:16], sample_labels[:16] logits model(sample_images.to(device)) preds torch.max(logits, dim1)[1].cpu() wandb.log({ valid_samples: [ wandb.Image(img, captionflabel:{label}, pred:{pred}) for img, label, pred in zip(sample_images, sample_labels, preds) ] }) print(fEpoch {epoch}: train_loss{train_loss:.4f}, val_acc{val_acc:.4f}) wandb.finish()这套代码是我平时训练分类模型时监控模板的一个简化版。真实工程里我还会加上save_checkpoint逻辑这里为了聚焦可视化省略掉了。6.3 日志怎么在WandB看板中解读跑完实验后打开WandB的project页面左侧能看到Run列表。点击任何一次run就能查看对应的所有曲线和指标。我通常会按这几步去解读先看val_acc曲线有没有稳定上升趋势。如果训练集acc一直涨验证集acc停滞或下降说明过拟合已经开始了。再看train_loss和val_loss之间的间隔。间隔拉大往往代表泛化能力在恶化。切到梯度直方图面板看梯度数值量级是否正常有没有出现极端大或者极端小的分布。如果发现acc曲线剧烈震荡优先怀疑学习率设置过高。如果需要做两次实验的对比勾选两个run曲线会叠在同一张图上。这也是我在多轮调参时最依赖的功能。7. 踩坑与排查WandB使用过程中的高频问题7.1 wandb.login登录失败wandb.login()失败是我收到反馈最多的问题没有之一。典型表现是卡在输入API Key这一步或者返回401 unauthorized甚至登录成功了但上传数据时报权限不足。我总结了一套排查路径按顺序走一遍基本能定位确认API Key是否复制完整前后有没有多余空格确认账号权限。团队workspace里被限制的成员角色可能无法上传数据确认系统时间是否准确时间偏差太大会导致token校验失败在无浏览器环境的服务器上先在本机登录一次把生成的~/.netrc凭证同步过去我自己的习惯是用环境变量保存API Keyexport WANDB_API_KEYxxxx这样脚本里即使不执行wandb.login()只要环境变量有效程序也能自动完成身份校验。这个方式对远程服务器跑实验特别友好。7.2 上传卡顿与离线模式WandB官方是海外服务有些网络环境直连时确实会出现上传慢甚至失败的情况。这里分享我在受限网络环境下最常用的两个应对方案。第一个是离线模式。在脚本里强制开启export WANDB_MODEoffline或者写到训练脚本开头import os os.environ[WANDB_MODE] offline离线模式下WandB会把所有日志写入本地run目录。训练结束后再手动同步wandb sync run_dir这样训练过程不中断日志也不会丢适合网络环境不稳定的场景。第二个方案是团队内如果有条件可以评估WandB的私有化部署把日志存储完全放到内网。这个方案通常需要一定的平台搭建投入但对数据合规要求高的团队来说是长期更稳妥的路线。7.3 多进程或多GPU训练下的注意事项用WandB时有个简单原则一个进程一个run。多卡训练时如果用DataParallel或者DistributedDataParallel每个进程都可能调用wandb.init()。这里要小心多个进程各自初始化会产生一堆半成品run看板会非常乱。常用的处理方式是只在主进程初始化WandBif dist.get_rank() 0: run wandb.init(projectmy_project)或者在wandb.init()里使用group参数把同一批分布式实验归到一个group里。这样可以保留多进程各自的数据同时统一查看。7.4 与Pytorch版本兼容问题WandB作为独立库对Pytorch的版本兼容总体做得不错但我遇到过几次版本差异引发的诡异问题。在Pytorch 1.x和2.x混用的环境里如果wandb版本比较旧有时会报module torch has no attribute _six一类的错误。这通常是WandB太旧还在引用老接口把wandb升级到最新版即可pip install -U wandb还有一个高频场景在使用Pytorch Lightning时如果pytorch-lightning和wandb版本不匹配可能报MissingLoggerConfiguration或者AttributeError: WandbLogger object has no attribute name。优先排查两侧的版本兼容矩阵或者检查Logger初始化参数。另外很多项目到了训练后期会涉及模型导出比如Pytorch转ONNX做部署。这一步和WandB没有直接耦合但我习惯把模型版本号、导出参数也一并记录到WandB配置里。日后回溯“这个表现最好的模型到底是用哪个版本导出的”直接在实验看板里就能找到答案不用再去翻一堆命名混乱的onnx文件。8. 个人使用心得与建议8.1 什么场景下值得用WandB不是所有实验都需要WandB。工具用对了地方才有价值一开始就把自己绑定到某个平台上反而可能增加负担。这里总结一下我的判断标准如果你是初学者或者只跑一两个短实验TensorBoard甚至print就够用WandB的额外价值体现不明显如果你需要多次对比超参数、需要团队共享结果、需要长期归档实验记录WandB几乎是当前最合适的选择之一如果你的数据存在隐私合规要求不能上传到外部SaaS平台就要重点考察WandB的私有化部署能力或者干脆使用本地落盘的TensorBoard方案很多团队最终的选择是“混搭”日常调参、多方案对比、团队协作这类场景用WandB效率确实高到了最终交付、客户验收、合规审计这类需要离线留档的场景再用TensorBoard做一份完整的本地备份。这样的组合既享受了WandB的协作便利又保留了不依赖外部服务的完整记录是我见过生命力最强的折中方案。8.2 建立良好的实验记录习惯最终决定一个团队实验管理效率的往往不是工具本身而是使用习惯。这里分享几条我个人坚持了几个项目的习惯其一所有关键超参数必须在wandb.config中显式登记包括不常用的seed、数据增强参数、模型宽度倍数等。不要嫌多写全了以后排查问题会很方便。其二每修改一个关键模块就在run name上打上可辨识的标签。比如cnn_lr_1e-3_aug_simple、cnn_lr_1e-3_aug_strong。名字长一点没关系一眼能看出区别就行。其三定期清理看板里的垃圾run。跑几十次失败的实验之后看板会变得很乱。WandB支持在网页端批量归档run善用这个功能不然三个月后你连哪条曲线是谁的都对不上。其四训练结束时主动调用wandb.finish()并在网络允许的情况下同步好本地离线数据。不要让日志一直悬在offline状态等需要回溯的时候才想起来同步。最后分享一点个人体会可视化这件事越早做越好越做越省心。不要把它当成一个可有可无的锦上添花它是在训练还没结束的时候让你看清问题、修正方向的重要工具。希望这篇内容能帮你把训练过程监控这一关顺利跨过去。
返回列表