新闻详情

新闻详情

首页 / 资讯中心 / 详情

MindSpore Transformers 训练监控:TensorBoard 接入与调优实践

发布时间:2026/9/26 12:45:37来源:尧图网络
MindSpore Transformers 训练监控:TensorBoard 接入与调优实践
1. 为什么训练监控这件事值得单独拿出来聊搞深度学习训练的人都有一个共识模型跑起来之后最怕的不是报错而是“静悄悄地烂掉”。Loss 不降、梯度爆炸、学习率调度出错、数据管道堵塞——这些问题不会让程序崩溃但会让你白白烧掉几十个小时的算力最后得到一个废模型。我见过太多人代码写完直接python train.py一跑然后去干别的几个小时后回来看结果发现 loss 从第三步就开始 NaN 了。MindSpore Transformers社区里常简称 MindFormers是 MindSpore 生态里专门做大模型训练推理的高层套件封装了 LLaMA、GPT、Bloom、GLM 等主流架构的预训练、微调和推理流程。它的run_mindformer.py或者train.py入口脚本用起来确实方便但默认的日志输出就是控制台刷屏你只能看到一行行的 loss 数值往下滚想对比两次实验的收敛曲线想看看学习率是不是按 cosine schedule 在走想知道梯度范数有没有异常尖峰光靠终端日志基本抓瞎。TensorBoard就是解决这个问题的。它把训练过程中的标量loss、学习率、吞吐量、直方图权重分布、梯度分布、计算图、甚至图像和文本都记录下来通过一个 Web 界面可视化。MindSpore 从 1.6 版本开始就内置了mindspore.train.callback.SummaryCollector和TensorBoard相关的 callback和 MindSpore Transformers 的 Trainer 体系可以无缝对接。这篇文章面向的是正在用或准备用 MindSpore Transformers 跑大模型训练的同学不管你是刚入门想搞清楚怎么把 TensorBoard 接进去还是已经跑了一段时间想优化监控粒度、排查训练异常下面这些内容应该都能帮到你。我会从整体设计思路讲到具体代码实现再到实际踩过的坑和排查技巧尽量把每个环节的“为什么”说清楚。2. 整体设计思路监控体系该怎么搭2.1 监控到底要监控什么很多人一提到 TensorBoard 就只想到 loss 曲线这其实浪费了 TensorBoard 80% 的能力。一个完整的训练监控体系至少应该覆盖以下几个维度监控维度具体指标记录方式排查价值收敛性loss、perplexityscalar判断模型是否在学习优化器状态学习率、梯度范数、权重范数scalar发现梯度爆炸/消失数据管道吞吐量、队列填充率scalar定位数据瓶颈参数分布权重直方图、梯度直方图histogram发现参数退化硬件利用显存占用、计算利用率scalar优化资源配置文本输出生成样本text直观感受模型效果在 MindSpore Transformers 的场景下前四项是必须的第五项可以通过 MindSpore 的 profiler 配合第六项在微调阶段特别有用——每隔几百步让模型生成一段文本直接看输出质量的变化比盯着 loss 数字直观得多。2.2 为什么选 TensorBoard 而不是其他方案训练监控的工具其实不少WandB、MLflow、SwanLab 都有人用。但在 MindSpore 生态里TensorBoard 有几个不可替代的优势第一原生支持。MindSpore 的mindspore.train.callback模块直接提供了SummaryCollector不需要额外安装第三方适配库。你只需要在 callback 列表里加一个对象就行零侵入。第二离线可用。很多训练集群是不连外网的WandB 这类需要联网同步的工具直接用不了。TensorBoard 完全本地运行日志写到磁盘开个端口就能看。第三轻量。TensorBoard 的日志格式就是 protobuf 序列化的 event file写入开销极小对训练吞吐的影响基本可以忽略。相比之下有些监控工具会在训练主进程里做大量序列化和网络传输反而成为瓶颈。第四生态成熟。你想看的任何曲线类型TensorBoard 几乎都支持。而且和 VS Code 的集成也很好装个 TensorBoard 插件就能在编辑器里直接看不用切浏览器。当然 TensorBoard 也有短板——多实验对比不如 WandB 方便团队协作共享不如云端方案。但对于个人开发者和中小团队来说它是最务实的选择。2.3 在 MindSpore Transformers 里的接入点MindSpore Transformers 的训练流程本质上还是基于 MindSpore 的Model.train()接口只是在外层封装了配置解析、分布式初始化、数据集构建等逻辑。所以接入 TensorBoard 的核心就是在Model.train()的callbacks参数里传入SummaryCollector。但这里有个细节需要注意MindSpore Transformers 自己已经定义了一套 callback 体系在mindformers/core/callback/callback.py里包括MFLossMonitor、CheckpointMointor、SummaryMonitor等。其中SummaryMonitor就是对SummaryCollector的封装。所以你有两条路可以走路线 A直接用 MindSpore Transformers 内置的SummaryMonitor通过配置文件控制开关和参数。路线 B自己写一个 callback继承Callback基类在step_end或epoch_end里手动调用SummaryRecord记录自定义指标。路线 A 适合大多数场景开箱即用路线 B 适合你需要记录一些框架默认不采集的指标比如自定义的评估指标或者中间层的激活值统计。3. 核心细节解析SummaryCollector 与 SummaryRecord 的用法3.1 SummaryCollector 的关键参数SummaryCollector是 MindSpore 提供的高层封装你只需要把它加到 callbacks 列表里它就会自动帮你采集常用的训练指标。它的构造函数有几个关键参数理解它们才能用好from mindspore.train.callback import SummaryCollector summary_collector SummaryCollector( summary_dir./summary_log, # 日志输出目录 collect_freq10, # 采集频率每10个step采集一次 collect_specified_data{ # 指定采集哪些数据 collect_metric: True, # 采集loss等指标 collect_train_lineage: True, # 采集训练溯源信息 collect_graph: False, # 是否采集计算图大模型建议关掉 collect_dataset_graph: False,# 是否采集数据集图 histogram_regular: .*weight.*, # 权重直方图的正则匹配 collect_landscape: False, # 是否采集loss landscape }, keep_default_actionFalse, # 是否保留默认采集行为 )这里有几个参数值得展开说collect_freq默认是 10意思是每 10 个 step 记录一次。对于大模型训练来说一个 step 可能要几秒甚至几十秒10 步就是几分钟才有一个数据点曲线会非常稀疏。我一般会设成 1 或者 5具体取决于你的 step 耗时。如果单步超过 10 秒设成 1 也无所谓因为写入开销相对于计算时间可以忽略。collect_graph这个参数要特别小心。开启之后它会尝试把整个计算图序列化到日志里对于小模型没问题但大模型的图可能有几千个节点序列化一次要几十秒甚至更久而且生成的日志文件会非常大。除非你确实需要可视化网络结构否则建议关掉。histogram_regular这个正则表达式决定了哪些参数会被记录直方图。默认是None表示不记录任何直方图。如果你想监控权重分布可以设成.*weight.*或者更精确的.*layers.\d.*weight.*。但要注意直方图记录的开销比 scalar 大得多因为每次都要把整个张量的值分布统计出来。建议只在调试阶段开启正式训练时关掉。keep_default_action这个参数控制是否保留 MindSpore 默认的采集行为。如果你传了collect_specified_data默认行为会被覆盖。设成False表示完全按照你的指定来设成True表示在你指定的基础上保留默认行为。我一般设False避免采集一些不需要的数据。3.2 SummaryRecord 的手动记录方式当你需要记录框架默认不采集的指标时就需要用SummaryRecord。它的用法比SummaryCollector更底层但更灵活from mindspore.train.summary import SummaryRecord class CustomMonitor(Callback): def __init__(self, summary_dir): super().__init__() self.summary_record SummaryRecord(summary_dir) def step_end(self, run_context): cb_params run_context.original_args() # 记录自定义指标 self.summary_record.add_value(scalar, custom_metric, Tensor(cb_params.custom_value, mstype.float32)) self.summary_record.record(cb_params.cur_step_num) def end(self, run_context): self.summary_record.close()这里的关键点是add_value和record的配合。add_value把数据加到缓冲区record把缓冲区的内容写入磁盘并打上 step 标签。注意record的 step 参数必须是递增的否则 TensorBoard 会显示异常。还有一个容易踩的坑SummaryRecord必须在训练结束时调用close()否则缓冲区里的数据可能不会写入磁盘。如果你用SummaryCollector它会在end回调里自动关闭但手动用SummaryRecord就要自己管理生命周期。3.3 在 MindSpore Transformers 配置里开启监控MindSpore Transformers 的配置文件通常是 YAML 格式里有一个callbacks段落你可以在这里配置SummaryMonitorcallbacks: - type: MFLossMonitor per_print_times: 10 - type: SummaryMonitor summary_dir: ./summary_log collect_freq: 5 collect_specified_data: collect_metric: True collect_graph: False histogram_regular: .*weight.* keep_default_action: False - type: CheckpointMointor prefix: mindformers save_checkpoint_steps: 1000 integrated_save: True这样配置之后训练启动时就会自动创建SummaryMonitor并开始记录。你不需要改任何训练代码只需要改配置文件。这也是 MindSpore Transformers 设计得比较好的地方——监控和训练逻辑解耦。但要注意SummaryMonitor的summary_dir如果和CheckpointMointor的输出目录混在一起日志文件会很多不好管理。建议单独建一个目录比如./summary_log/exp_001每次实验用不同的子目录方便对比。4. 实操过程从零接入 TensorBoard 监控4.1 环境准备与依赖检查在开始之前确认你的环境满足以下条件# 检查 MindSpore 版本建议 2.0 以上 python -c import mindspore; print(mindspore.__version__) # 检查 MindSpore Transformers 版本 python -c import mindformers; print(mindformers.__version__) # 安装 TensorBoard如果还没装 pip install tensorboard # 验证 TensorBoard 可用 tensorboard --versionMindSpore 2.0 之后的版本对 TensorBoard 的支持已经比较稳定了但如果你用的是 1.x 版本可能会遇到一些 API 不兼容的问题。我建议至少用 2.0 以上。另外TensorBoard 的版本也有讲究。2.10 之后的版本对 event file 的解析做了一些优化加载大日志文件的速度明显更快。如果你发现 TensorBoard 打开很慢先升级一下版本。4.2 最小可运行示例先给一个最简单的接入示例让你快速看到效果。假设你用的是 MindSpore Transformers 的run_mindformer.py入口python run_mindformer.py \ --config configs/llama/run_llama_7b.yaml \ --run_mode train \ --train_dataset /path/to/dataset \ --summary_dir ./summary_log/exp_001然后在配置文件里加上SummaryMonitor的配置参考上一节的 YAML 示例。训练启动后你会在./summary_log/exp_001目录下看到类似这样的文件summary_log/exp_001/ ├── events.out.tfevents.1700000000.hostname.12345.0 └── events.out.tfevents.1700000000.hostname.12345.1这些就是 TensorBoard 的 event file。启动 TensorBoardtensorboard --logdir ./summary_log --port 6006 --host 0.0.0.0然后在浏览器打开http://localhost:6006就能看到 loss 曲线了。4.3 自定义监控指标的完整实现框架默认采集的指标有限通常只有 loss 和学习率。如果你想监控梯度范数、权重范数、吞吐量等指标就需要自己写 callback。下面是一个完整的实现示例import time import numpy as np from mindspore import Tensor from mindspore.common import dtype as mstype from mindspore.train.callback import Callback from mindspore.train.summary import SummaryRecord class EnhancedMonitor(Callback): 增强版训练监控记录梯度范数、权重范数、吞吐量等指标 def __init__(self, summary_dir, collect_freq10, log_freq100): super().__init__() self.summary_record SummaryRecord(summary_dir) self.collect_freq collect_freq self.log_freq log_freq self.step_start_time None self.last_log_time None self.last_log_step 0 def step_begin(self, run_context): self.step_start_time time.time() def step_end(self, run_context): cb_params run_context.original_args() step cb_params.cur_step_num # 计算单步耗时和吞吐量 step_time time.time() - self.step_start_time if step % self.collect_freq 0: # 记录单步耗时 self.summary_record.add_value( scalar, perf/step_time, Tensor(step_time, mstype.float32) ) # 计算并记录吞吐量samples/sec batch_size cb_params.batch_num throughput batch_size / step_time if step_time 0 else 0 self.summary_record.add_value( scalar, perf/throughput, Tensor(throughput, mstype.float32) ) # 记录学习率如果优化器有动态学习率 if hasattr(cb_params.train_network, optimizer): lr cb_params.train_network.optimizer.learning_rate if isinstance(lr, Tensor): self.summary_record.add_value( scalar, train/learning_rate, lr ) # 记录梯度范数需要遍历网络参数 try: grad_norm self._compute_grad_norm(cb_params.train_network) self.summary_record.add_value( scalar, train/grad_norm, Tensor(grad_norm, mstype.float32) ) except Exception as e: pass # 某些网络结构可能不支持静默跳过 self.summary_record.record(step) # 定期打印到控制台 if step % self.log_freq 0: elapsed time.time() - self.last_log_time if self.last_log_time else 0 steps_done step - self.last_log_step avg_step_time elapsed / steps_done if steps_done 0 else 0 print(f[Step {step}] avg_step_time{avg_step_time:.3f}s, fthroughput{batch_size/avg_step_time:.1f} samples/s) self.last_log_time time.time() self.last_log_step step def _compute_grad_norm(self, network): 计算全局梯度范数 total_norm 0.0 for param in network.get_parameters(): if param.grad is not None: grad param.grad.asnumpy() total_norm np.sum(grad ** 2) return np.sqrt(total_norm) def end(self, run_context): self.summary_record.close() print(Training finished, summary log closed.)把这个 callback 加到训练流程里from mindformers import Trainer monitor EnhancedMonitor( summary_dir./summary_log/exp_001, collect_freq5, log_freq50 ) trainer Trainer( argsconfig, callbacks[monitor] ) trainer.train()这个实现里有几个细节值得注意梯度范数的计算开销。_compute_grad_norm会遍历所有参数并把梯度转成 numpy 数组对于 7B 模型来说这个操作可能要几百毫秒。所以我把它放在collect_freq的控制下不是每个 step 都算。如果你觉得还是太慢可以只对部分层的梯度做采样。异常处理。有些网络结构比如使用了自定义算子的可能不支持param.grad的访问所以用 try-except 包起来避免因为监控代码导致训练崩溃。吞吐量的计算方式。我用的是batch_size / step_time这里的batch_size是全局 batch size所有卡的 batch 之和。如果你用的是数据并行这个数值才是真实的吞吐量。4.4 多卡训练下的日志管理多卡训练时每个卡都会写自己的 event file如果都写到同一个目录TensorBoard 会把它们混在一起显示曲线会非常乱。正确的做法是每张卡写不同的子目录import mindspore.communication as comm def get_rank(): try: return comm.get_rank() except: return 0 rank get_rank() summary_dir f./summary_log/exp_001/rank_{rank}然后在 TensorBoard 里你可以选择只看某一张卡的曲线或者看所有卡的平均。但更常见的做法是只让 rank 0 写日志因为所有卡的 loss 在数据并行下应该是一样的梯度做了 all-reduce没必要重复记录。if rank 0: callbacks.append(EnhancedMonitor(summary_dir./summary_log/exp_001))但如果你用的是模型并行或者流水线并行不同卡的 loss 可能不一样这时候就需要每张卡都记录方便排查是哪张卡出了问题。5. 常见问题与排查技巧实录5.1 TensorBoard 打不开或者曲线不显示这是最常见的问题通常有以下几个原因原因一日志目录不对。TensorBoard 的--logdir参数指向的目录必须包含 event file或者包含 event file 的子目录。如果你指向的目录层级太深或太浅TensorBoard 可能找不到文件。我一般会把--logdir指向实验的根目录比如./summary_log然后 TensorBoard 会自动扫描所有子目录。原因二event file 没有正确关闭。如果训练异常中断SummaryRecord没有调用close()缓冲区里的数据可能没有写入磁盘。这时候 event file 是存在的但内容是空的或者不完整的。解决办法是在训练脚本里加 try-finallytry: trainer.train() finally: monitor.summary_record.close()原因三端口被占用。TensorBoard 默认用 6006 端口如果被占用了会启动失败。换一个端口就行--port 6007。原因四防火墙或网络配置。如果你在远程服务器上跑训练本地浏览器访问不了需要确认服务器的端口是否对外开放。我一般用 SSH 端口转发ssh -L 6006:localhost:6006 userserver然后在本地浏览器访问localhost:6006。5.2 日志文件过大导致磁盘爆满TensorBoard 的 event file 会随着训练持续增长如果训练几周日志文件可能达到几十 GB。我遇到过好几次因为日志写满磁盘导致训练崩溃的情况。控制日志大小的几个方法降低采集频率。collect_freq从 1 改成 10 或者 50日志大小会成比例减小。关闭直方图。直方图的数据量比 scalar 大一个数量级如果不是必须关掉它。定期清理旧日志。在训练脚本里加一个清理逻辑只保留最近 N 个 event fileimport os import glob def cleanup_old_logs(log_dir, keep_last5): files sorted(glob.glob(os.path.join(log_dir, events.out.tfevents.*))) for f in files[:-keep_last]: os.remove(f)使用单独的磁盘分区。如果条件允许把日志写到单独的磁盘分区避免影响训练数据的读写。5.3 曲线抖动严重看不出趋势Loss 曲线抖动是正常的尤其是 batch size 比较小的时候。但如果抖动到完全看不出趋势可能是以下原因学习率太大。这是最常见的原因。检查一下学习率配置看看是不是 warmup 阶段太短或者初始学习率太高。数据没有 shuffle。如果数据集没有打乱模型可能会在连续相似的样本上过拟合导致 loss 剧烈波动。梯度裁剪没生效。大模型训练一般都需要梯度裁剪如果裁剪阈值设得太大或者没开梯度爆炸会导致 loss 尖峰。在 TensorBoard 里你可以用平滑功能右上角的 Smoothing 滑块来观察趋势。但要注意平滑只是视觉上的不能替代对原始数据的分析。我一般会把平滑系数设在 0.6 左右既能看清趋势又不会掩盖异常尖峰。5.4 常见问题速查表问题现象可能原因排查方法解决方案TensorBoard 无数据日志目录错误检查目录下是否有 event file修正 --logdir 路径曲线不更新SummaryRecord 未 flush检查训练是否还在运行确认 record 调用频率日志文件为空未调用 close()检查训练是否异常退出加 try-finally 确保关闭磁盘爆满采集频率过高du -sh 查看日志大小降低 collect_freq曲线抖动大学习率过大对比不同学习率实验调小学习率或加 warmup多卡曲线混乱日志目录未区分检查是否所有卡写同一目录按 rank 分目录或只让 rank0 写打开速度慢日志文件过大查看 event file 大小清理旧日志或降低采集频率直方图不显示histogram_regular 未配置检查配置项设置正确的正则表达式5.5 几个我踩过的坑坑一在step_end里做太重的计算。我一开始把梯度范数的计算放在每个 step 都执行结果训练速度直接降了 30%。后来改成每 10 步算一次影响就很小了。监控代码本身也是代码也会消耗计算资源一定要控制开销。坑二忘了在分布式环境下同步。多卡训练时如果每张卡都写日志TensorBoard 会把不同卡的 loss 曲线叠在一起看起来像是模型在剧烈震荡。实际上每张卡的 loss 都是平滑的只是数值有微小差异。解决办法就是只让 rank 0 写或者按 rank 分目录。坑三TensorBoard 的 step 不连续。如果你在训练中途重启step 会从 0 重新开始TensorBoard 会把新旧数据混在一起曲线会出现回折。解决办法是在重启时换一个新的 summary_dir或者在 record 时用一个全局递增的 step 计数器。坑四在 VS Code 里看 TensorBoard 卡顿。VS Code 的 TensorBoard 插件在日志文件很大时会非常卡甚至崩溃。我的做法是调试阶段用 VS Code 看正式训练用命令行启动 TensorBoard 在浏览器看。VS Code 插件适合快速查看小规模实验。6. 进阶技巧让监控真正服务于调优6.1 用 TensorBoard 做实验对比TensorBoard 的--logdir可以指向一个包含多个实验子目录的父目录这样在界面上可以同时显示多个实验的曲线方便对比。目录结构建议这样组织summary_log/ ├── exp_001_lr1e-4/ │ └── events.out.tfevents... ├── exp_002_lr5e-5/ │ └── events.out.tfevents... └── exp_003_lr1e-4_warmup1000/ └── events.out.tfevents...在 TensorBoard 界面上你可以勾选不同的实验对比它们的 loss 曲线。我一般会在实验目录名里带上关键超参数比如学习率、batch size、warmup 步数这样一眼就能看出哪个配置更好。6.2 记录生成样本观察模型质量Loss 下降不代表模型生成质量一定好。有时候 loss 降得很漂亮但生成出来的文本全是重复的。所以在微调阶段我建议每隔几百步让模型生成一段样本记录到 TensorBoard 的 text 面板里def generate_sample(model, tokenizer, prompt, max_length50): inputs tokenizer(prompt, return_tensorsms) outputs model.generate(**inputs, max_lengthmax_length) return tokenizer.decode(outputs[0], skip_special_tokensTrue) # 在 callback 里定期调用 if step % 500 0: sample generate_sample(model, tokenizer, Once upon a time) summary_record.add_value(text, generated_sample, sample)这样你可以在 TensorBoard 的 Text 标签页里看到不同 step 的生成结果直观感受模型输出的变化。这个技巧在调试生成模型时特别有用比盯着 loss 数字强多了。6.3 监控数据管道性能大模型训练中数据管道经常成为瓶颈。如果 GPU 利用率只有 50%很可能是数据加载跟不上。在 TensorBoard 里记录数据加载时间class DataPipelineMonitor(Callback): def __init__(self, summary_dir): super().__init__() self.summary_record SummaryRecord(summary_dir) self.data_time 0.0 self.compute_time 0.0 def step_begin(self, run_context): self.step_begin_time time.time() def step_end(self, run_context): step_time time.time() - self.step_begin_time # 假设数据加载时间可以通过 dataset 的某些属性获取 # 这里用估算值演示 self.summary_record.add_value(scalar, perf/step_time, Tensor(step_time, mstype.float32)) self.summary_record.record(run_context.original_args().cur_step_num)如果发现 step_time 波动很大而且和数据集的样本长度分布相关那基本可以确定是数据管道的问题。解决办法包括增加数据加载的并行度、使用更高效的数据格式如 MindRecord、预取更多 batch 等。6.4 用直方图发现参数退化权重直方图可以帮你发现一些隐蔽的问题。比如权重全部趋近于零可能是正则化太强或者学习率太小。权重出现极端值可能是梯度爆炸需要检查梯度裁剪。某一层的权重分布和其他层差异巨大可能是初始化有问题或者该层的梯度更新异常。在 TensorBoard 的 Histograms 面板里你可以看到每一层权重的分布随训练步数的变化。我一般会重点关注 embedding 层和最后的输出层这两层最容易出问题。但要注意直方图记录的开销比较大建议只在调试阶段开启正式训练时关掉。如果确实需要长期监控可以降低采集频率比如每 1000 步记录一次。6.5 结合 VS Code 提升调试效率VS Code 的 TensorBoard 插件可以让你在编辑器里直接查看曲线不用切换窗口。安装方法很简单在扩展市场搜索 TensorBoard 安装即可。然后在命令面板里运行 TensorBoard: Launch选择日志目录就行。但 VS Code 插件有个限制它只能看 scalar不支持直方图和计算图。所以我的工作流是日常调试用 VS Code 快速看 loss 曲线需要深入分析时再启动完整的 TensorBoard。另外VS Code 的 MindSpore 插件也值得装一下它提供了代码补全、语法检查、调试支持等功能。虽然不如 PyTorch 的生态那么完善但基本够用。7. 一些个人体会监控这件事很多人觉得是“锦上添花”训练能跑就行看什么曲线。但我自己的经验是没有监控的训练就是在赌博。你永远不知道模型是在学习还是在退化是在收敛还是在震荡。尤其是大模型训练一次实验可能就是几十个小时的 GPU 时间如果因为一个低级错误导致白跑损失太大了。TensorBoard 接入的成本其实很低改几行配置就行。但它带来的价值是巨大的——你能看到 loss 的每一次波动能对比不同超参数的效果能在训练早期就发现异常。我现在的习惯是任何超过 1 小时的训练必须接 TensorBoard否则不开跑。还有一个建议养成记录实验配置的习惯。在 summary_dir 里放一个 config.json把这次实验的所有超参数都写进去。过了一个月回头看曲线你还能知道当时用的是什么学习率、什么 batch size。不然面对一堆 exp_001、exp_002 的目录根本记不清哪个是哪个。最后分享一个小技巧如果你用的是 Slurm 或者 Kubernetes 这类集群调度系统可以在训练脚本里自动启动 TensorBoard 并把端口映射出来。这样训练一开始你就能通过浏览器访问监控面板不用手动登录服务器去启动。具体做法是在脚本开头加一段# 在后台启动 TensorBoard tensorboard --logdir ./summary_log --port 6006 --host 0.0.0.0 TENSORBOARD_PID$! # 训练结束后自动关闭 trap kill $TENSORBOARD_PID EXIT这样训练和监控就完全自动化了你只需要打开浏览器就行。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

C语言指针核心原理与实战:从内存地址到函数指针全解析 2026/9/26 14:13:57

C语言指针核心原理与实战:从内存地址到函数指针全解析

指针这个概念,第一次出现在C语言教材里的时候,就劝退了不少人。说来也怪,明明就一句话——指针就是存地址的变量——但真用起来,很多人还是被它绕得晕头转向。我当年学到这里也一样,一度看到 *p 就头皮发麻。但等你真…

阅读更多 →
Agent-harness组内协议设计:多Agent协作的消息模型与排障实战 2026/9/26 14:13:57

Agent-harness组内协议设计:多Agent协作的消息模型与排障实战

组内协议这四个字,我前后琢磨了将近一个月,才算真正把它从“概念”变成了“代码”。刚接触 Agent-harness 的时候,我犯过所有新手都会犯的错误:以为重点在 Agent 本身,网上教程也几乎清一色在教怎么让单个 Agent 调工具…

阅读更多 →
编译原理课设实战:SLR(1)小型编译程序从源码到四元式生成 2026/9/26 14:13:57

编译原理课设实战:SLR(1)小型编译程序从源码到四元式生成

简介:这份资源面向学习编译原理、需要完成课程设计的高校学生,围绕SLR(1)分析法实现一个小型编译程序,解决从高级语言源程序到四元式程序翻译的实践问题。资源包共14个文件,约22KB,包含C语言源码、测试用例数据文件、汇…

阅读更多 →
DeskcommCRM部署复盘:如何让销售团队真正用起来 2026/9/26 14:13:57

DeskcommCRM部署复盘:如何让销售团队真正用起来

做客户管理软件这几年,我换过三套CRM,从免费的开源工具到付费的SaaS平台都用过。老实说,大多数CRM项目最后都死在同一个地方:销售不愿意录数据,管理层看不到真实进度,系统变成了一个昂贵的记录本。直到我们…

阅读更多 →
5G NR参考信号SRS与CSI-RS:配置、触发与避坑指南 2026/9/26 14:13:57

5G NR参考信号SRS与CSI-RS:配置、触发与避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
多智能体协作系统实战:架构设计、群体涌现与工程落地 2026/9/26 14:13:50

多智能体协作系统实战:架构设计、群体涌现与工程落地

1. 从单体到群体:为什么我们需要重新思考智能系统的架构1.1 单体智能的天花板在哪里过去两年,我参与过不少基于大语言模型的应用项目,从最早的简单问答机器人,到后来的RAG检索增强系统,再到带工具调用的Agent。说实话&…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉