Megatron Timer Predictor——训练 Straggler 在线检测与定位系统
Megatron Timer Predictor——训练 Straggler 在线检测与定位系统
本文记录我设计并落地的 Megatron Timer Predictor(mt-detector):一个针对 Megatron-LM 大规模分布式训练中性能落后节点(Straggler)问题的检测与定位系统。它从 ClickHouse 读 Megatron Timer 已落盘的全 rank 时序指标,经"6 种聚类算法 + 跨算法投票"识别异常 rank,再针对流水线并行(PP)场景做通信异常检测 + 交叉验证定位网络拥塞节点,多进程并发把分析压到 30 秒内。
说明:项目名里 “Predictor/预测” 是个 misnomer——系统做的是当前态检测/分类(哪些 rank 现在慢),不做时序外推或"未来哪步会慢"的预测。下文"预测"一律按"检测/标记当前异常 rank"理解。
背景知识:Megatron Timer 怎么采时序、为什么跨 rank all-gather 取 max,见本人《Megatron Timers 源码精读》篇。本篇讲的是这些时序数据被采集层写入 ClickHouse 之后,怎么自动找出谁是 straggler、为什么慢、慢在哪一段。
一、问题:Straggler 是分布式训练的隐形杀手
大模型训练动辄几百到几千张 GPU,靠 NCCL/Megatron 的集合通信把各卡同步起来。木桶效应:训练每个 step 的推进速度由最慢的那张卡决定——它没算完,all-reduce 等它;它没把梯度同步完,下一步卡住。这张慢卡就是 straggler。
straggler 的危害:
- 吞吐塌方:1000 张卡里 1 张慢 20%,整个集群吞吐掉 20%——上千卡折算成钱和算力是天文数字。
- 难发现:straggler 不是死机(死机 NCCL 会直接 hang/报错),而是"还能跑但比别卡慢",日志里不报错、metrics 平均值看着正常,被均值掩盖。
- 难定位:慢的原因五花八门——GPU 硬件降频/故障、显存 ECC 错误触发重算、NVLink 拓扑错位跨 NUMA、网卡拥塞丢包、某个 op 的 kernel 异常、数据加载抖动……要能区分"计算慢"还是"通信慢"、定位到具体卡和具体段。
传统运维手段不够:
nvidia-smi看 util/温度:粗粒度,util 高也可能正卡在访存,看不出谁落后。- 看 loss/吞吐:是结果不是原因,发现时已经亏了几个小时。
- 看 NCCL 报错:只覆盖死链路,慢但不死的 straggler 不报。
所以需要一个基于训练运行时真实时序、自动、准、快的检测定位系统。这就是 Megatron Timer Predictor 的目标:
- 检测:哪个 rank 是 straggler(异常检测)。
- 归因:它慢在计算还是通信、慢在哪个阶段、是不是网络拥塞节点。
- 快:30 秒内出分析结果,能接进运维告警闭环。
- 准:以运维后确认的故障/换卡样本为评估基准,目标准确率 >90%(少误报少漏报)。
二、数据来源:ClickHouse 里的 Megatron Timer 全 rank 时序
系统的"信号源"不是直接调 megatron/core/timers.py,而是已由采集层写入 ClickHouse 的 megatron_metrics 表。Megatron Timer 每步跨 rank all-gather 出一张 [world_size, num_timers] 矩阵(每行一个 rank,每列一个 timer),采集层把它按行展开写进 ClickHouse,本项目再去查。
2.1 表与字段
1 | CREATE TABLE dev.megatron_metrics ( |
本项目读三类 metric_name:
| metric_name | 含义 | 典型 subname |
|---|---|---|
megatron_timers |
各 timer 的时长(数组) | interval-time(整步)、forward-compute、backward-compute、forward-send、forward-recv、backward-send、backward-recv、forward-send-backward-recv、backward-send-forward-recv、self-attention-linear-qkv 等 |
megatron_timers_trace |
trace 事件(start/end 配对) | 各通信段 phase |
megatron_parallel_group_rank |
并行组 rank | pp(自动探测 PP size) |
每个 rank 一个 timer 的耗时取 metric_values 数组里的元素(如 interval-time 的 metric_values[1] 即整步秒数)。
2.2 为什么这套数据适合做异常检测
- 粒度对:timer 切到 forward-compute/backward-compute/通信段,能直接看出"慢在哪一段"——不像 nvidia-smi 只给一个 util。
- 跨 rank 可比:all-gather 后每个 rank 都有完整矩阵,天然带 rank 维度做对比。
- 已 sync 过滤:Timer 内部
cuda.synchronize保证数据可信(详见 Timer 篇),不会被异步 launch 污染。 - 落盘可查:写入 ClickHouse 后,检测服务与训练进程解耦,可离线/在线反复分析。
2.3 特征构建:per-(subname, rank) 四元组
聚类输入不是单步的原始耗时,而是对每个 (subname, rank) 跨一个 iteration 区间聚合出的四元组:
1 | [Min, Max, Range, Mean] # 该 rank 在该 subname 上、跨区间所有 iter 的 最小/最大/极差/均值 |
额外预处理(predicter/Cluster/fastslow_common.py):
- 丢弃前 10 个 iteration:起步阶段抖动大,不参与。
- 过滤覆盖不全的 subname:不是所有 rank 都打了某 timer(值为 0)的 subname 剔除。
- 过滤相对 spread 太小的 subname:
min_subname_rel_range=0.03,极差/均值 < 3% 的 subname 区分度不够,跳过。 - robust scale 归一化:用 median/MAD 或 IQR 做 robust 缩放(不同 subname 量级差大:forward-compute 几百 ms、send 几 ms),让各维度可比。不是 z-score——z-score 受异常值拉动,robust 更稳。
- PP≥2 时限定 compute 白名单:有流水线并行时,聚类只用计算类 subname,通信类另走通信检测。
注:滑动中位数这一步不在聚类预处理里,而在在线触发那一层——用来判定"某 iter 是否算慢"(见第三节),两者别混淆。
2.4 标签:什么是"异常"
无监督为主(真实生产里 straggler 标签稀缺),但有"事后确认真故障"的样本作为评估基准(运维记录的 GPU 故障卡/换卡事件)。准确率口径 = 检出的异常 rank 与运维确认的故障/落后节点一致的比例(目标 >90%,属评估口径而非代码内置数值)。
三、在线触发:从轮询到启动分析
检测不是每个 step 都跑一遍重聚类,而是在线轮询 + 条件触发 batch 分析两段式(monitor/)。
3.1 轮询与慢迭代判定
DataMonitor 以 check_interval(生产 30s / 模拟 5s)轮询 ClickHouse 的 get_latest_iterations,发现新 iteration 就分析上一iter:
- 读该 iter 的
interval-time时长(秒)。 - 慢判定:
growth_rate = (current - median)/median,当growth_rate > slowdown_threshold*100(默认slowdown_threshold=0.25,即 25%)判为慢。 - 滚动中位数:baseline 只纳入"正常"iter(时长比当前中位数
ratio < 1.1的才进 baseline),保留最近history_size=5个,避免慢 iter 自身污染中位数。 - hang 判定:
hang_threshold=60s内无新 iter → 状态hanging。
3.2 触发分析
当连续 5 个慢 iter(或慢历史 ≥5 且上次结果为空)时,状态置 predicting,起一个线程跑 _run_straggler_analysis:
- 用慢 iter 区间拼
--iterations start-end。 - 用 job 注册时间到现在拼
--start/--end时间界(这条是 commit014d164 "修复在线检测中的问题"加的,防止 batch 分析拉到 job 注册前的旧数据)。 - 子进程执行
python3 predicter/prediction.py --job-id … --algorithm all --iterations … --start … --end …。 - 分析完读最新的
predicter/prediction_results/prediction_<ts>/summary.txt,正则取anomaly_ranks:/anomaly_nodes:,状态置detected。
所以"30 秒"是分析阶段的耗时,触发条件是"连续 5 个慢 iter",不是每 step 都 30 秒。
四、检测核心:6 种聚类算法 + 跨算法投票
4.1 为什么用聚类做异常检测
正常 rank 耗时聚集在"正常簇"里,straggler 是偏离的 rank。这本质是个无监督异常检测问题。但没有单一算法通吃所有形态:基于距离的(KMeans)、基于密度的(DBSCAN)、基于分布/隶属度的(GMM/Fuzzy)、层次结构(Agglomerative)、密度峰值(Mean Shift)各有盲区。所以上多种互补算法,各自给每个 rank 一个 fast/slow 标签,再投票融合——单算法盲区被其它补。
4.2 集成的 6 种算法(实际实现)
| 算法 | 模型 | 检测准则 | 文件 |
|---|---|---|---|
| KMeans | sklearn KMeans(n_clusters=2) |
聚成 2 簇,均值最高的簇=slow;>2 簇时二级 KMeans 收敛 | Cluster/kmeans.py |
| DBSCAN | sklearn DBSCAN,eps 自适应(k-distance 膝点 × 多尺度) |
noise 与非 noise 归并后,均值最高簇=slow | Cluster/dbscan.py |
| GMM | GaussianMixture(n_components=2),协方差类型网格搜索 |
argmax 隶属度分簇,均值最高簇=slow |
Cluster/gmm.py |
| Agglomerative(层次) | AgglomerativeClustering(n_clusters=2),linkage/metric 网格 |
均值最高簇=slow | Cluster/hierarchical.py |
| Mean Shift | sklearn MeanShift,bandwidth=分位数估计×倍数 |
自动簇数,二级 KMeans 收敛后均值最高簇=slow | Cluster/mean_shift.py |
| Fuzzy C-Means(模糊) | 手写 FCM,隶属度矩阵 U | argmax 隶属度分簇,均值最高簇=slow;网格搜 m/seed |
Cluster/fuzzy.py |
关键认知:六个算法的判定准则统一是"落入慢簇(各 timer 均值最高的那个簇)",不是"离质心距离大"、不是"概率低于阈值"、不是"离群点 label=-1"。这样把异构算法的输出规约成同一语义的 fast/slow 二值标签,才能跨算法投票。每个算法内部都做超参"调优"(silhouette / Calinski-Harabasz / Davies-Bouldin 选最优)。
4.3 三层投票融合(实际机制)
第一层——算法内、跨 subname 加权多数(fastslow_common.py:vote_rank_labels):
每个算法对每个 subname 都把 rank 聚成 fast/slow,然后跨该 rank 参与的所有 subname 投票:
1 | label = "slow" if slow_votes * 2 >= total else "fast" # 加权多数 |
其中 self-attention-linear-qkv 权重为 3(它是计算耗时的强信号),其余 subname 权重 1。再加一道 original_total_subnames 门槛:slow 票数需 ≥ 该 rank 覆盖的原始 subname 数的一半,否则强制 fast,防"只参与了少数 subname 就被判慢"。PP≥2 时还用 top-10 慢 iter 做 1.3× 收窄(某 rank 在慢 iter 里均值 < 最快 rank 的 1.3× 就回退 fast)。
每个算法最终输出一张 fast_slow_summary.csv(kind=rank, key=rankN, label=slow/fast, slow_votes, total_subnames)。
第二层——跨算法、取最高票(prediction.py:generate_summary_file 活性版本):
6 个算法各跑一遍(各自一个进程),汇总每个 rank 被多少个算法标 slow:
1 | rank_counter = Counter(slow_ranks_from_each_algo) |
即最终 cluster 异常 rank = 跨 6 算法得票最多的 rank。这是计数取 max,不是固定阈值(如"≥4/6")——固定阈值那条规则只存在于被覆盖的死代码里,线上不生效。
第三层——cluster 与 communication 的节点并集(见第五节):
1 | all_anomaly_ranks = cluster_anomaly_ranks # 只来自聚类 |
写入 summary.txt 的 anomaly_ranks: / anomaly_nodes:。
这样设计的好处:算法内 subname 多数投票抗"单 subname 抖动";跨算法取最高票抗"单算法系统性偏差"(如 DBSCAN 对 eps 敏感、KMeans 对初始化敏感时,其它算法的票能纠偏)。没有"加权打分 + 权重学习 + 标签回填重训"那套——线上是固定的计数取 max,简单可靠。
4.4 为什么是这 6 个的组合
选算法刻意覆盖多类原理:基于距离(KMeans)、基于密度(DBSCAN)、基于分布/隶属度(GMM/Fuzzy)、层次结构(Agglomerative)、密度峰值(Mean Shift)。原理越分散,盲区越不重叠,ensemble 增益越大。纯堆同类算法(比如 6 个都是 KMeans 变种)投票增益小。
五、归因:通信异常检测 + 交叉验证定位网络拥塞
光说"rank 53 是 straggler"还不够,运维要知道慢在计算还是通信、是不是某段网络拥塞。这里针对 Megatron 流水线并行(PP)场景设计了通信异常检测模块和交叉验证(predicter/Communication/)。PP=1 时跳过整个通信检测;PP≥2 才跑。
5.1 流水线并行的通信特征
PP 把模型按层切成 P 段,段间用 P2P send/recv 传激活。Megatron 的通信段被打成 megatron_timers_trace(start/end 配对算时长)和 megatron_timers 的 forward-send/forward-recv/backward-send/backward-recv/forward-send-backward-recv/backward-send-forward-recv 等 subname。
5.2 通信异常检测(communication_predict.py / IBWDetector)
对区间内每个 iteration跑一遍(≤4 并行),5 个 trace 子检测器覆盖 5 条通信段:
- 把 trace 行转成 start/end 事件,按 PP group 分组,比较每组首个 timer 值;
- 某 group 首值 >
min(各 group 首值) × threshold即判该 group 异常(文件默认 1.5,CLI 默认 1.3); detect_sudden_increases标连续值跳变 > 2.0×;- baseline 检测:
baseline = min{ 非零 group 最小值, ½·PP0 的 fsbr, ½·末 PP 的 bsfr },worker 异常 =avg_last_value > 2.0 × baseline。
5.3 交叉验证定位拥塞节点(apply_cross_validation_rules)
通信段慢有二义性:send 端发得慢?recv 端收得慢?两端之间的网络拥塞? 用多信号互证消解:
- 计算 vs 通信分离:把 rank 的 timer 拆成计算段(forward-compute/backward-compute)和通信段(send/recv)。
- 某 rank 计算段正常、通信段异常 → 倾向网络/通信问题。
- 某 rank 计算段也异常 → 倾向该卡硬件/算力问题(降频、ECC、kernel 异常)。
- send/recv 端点互证:
forward-send异常 ⇒ 该 worker 发送拥塞 或 下游 worker 接收拥塞;forward-recv异常 ⇒ 该 worker 接收拥塞或上游发送拥塞;- 结合 PP group 归属判定两端点。
- PP group 一致性:某 worker 涉及的通信段都慢 → 该节点网络问题;只单段慢 → 那段链路问题。
- 跨 iteration 并集:每个 iter 各自跑通信检测,结果在
generate_summary_file里 union 成all_anomalous_workers(send 拥塞 ∪ recv 拥塞),覆盖整个慢 iter 区间。
注:代码里的归因粒度到 worker / node(rank→node 靠查 ClickHouse 的
node字段映射),不到 NVSwitch 域/IB 口的物理拓扑粒度。把异常 rank 映射到 node 是有的,再往下到具体交换机/网口要靠外部拓扑系统,本项目不内置。
交叉验证后输出结构化归因:
1 | straggler: rank 5 (node gpu-07) |
这把"谁慢"和"为什么慢、慢在哪"都给运维了。
5.4 PP=2 的兜底检查
PP=2 是最小 PP,通信段特征少,有专门的 run_pp2_fallback_check:随机抽 3 个 (fast, slow) iter 对,比 5 条通信 subname 的 per-worker 均值,slow iter 某 worker 均值 > 其 fast iter 均值 × 1.3 → “通信可能有异常”。给小 PP 场景兜个底。
六、性能优化:多进程并发,分析阶段 30 秒内
检测要接进运维告警闭环,必须快——触发后训练还在跑、运维在等。优化手段:
6.1 多进程并发
sklearn 底层有 GIL,且要避开 BLAS 多线程争抢,用进程不用线程:
- 算法并行:
run_cluster()用ProcessPoolExecutor,6 种算法各一个进程并行算(prediction.py)。 - 通信并行:
run_communication()对每个 iter 跑通信检测,≤4 个进程并行。 - 进程间只传小的 timer 聚合结果(四元组)和 fast/slow 标签,不传大对象,开销低。
6.2 计算层面的优化
- 向量化:归一化、距离计算全用 numpy/sklearn 向量化,避免 Python 循环。
- 早筛:
min_subname_rel_range等过滤跳过区分度不够的 subname,减少聚类样本。 - 超参调优有界:每个算法的网格搜索范围限定,避免在无效参数空间耗时间。
- 只对慢 iter 区间分析:不是全量 iter 重算,只分析触发时圈定的慢 iter 范围 + 时间界。
6.3 结果
- 分析阶段(6 算法并行 + 通信 per-iter 并行 + 跨算法投票 + 归因)压在 30 秒内。
- 触发前是 30s 轮询 + 连续 5 慢 iter 的条件,所以从"慢出现"到"出结果"约几分钟(取决于多快凑够 5 个慢 iter),分析本身 30 秒级。
七、系统形态与 API
7.1 形态
- 采集层:Megatron Timer 采集 → 写入 ClickHouse
megatron_metrics(生产用--log-level控制 Timer 开销)。 - 检测层:一个常驻 Flask 服务(
main.py起),DataMonitor轮询 + 触发predicter/prediction.py子进程做聚类+通信分析,结果写summary.txt。 - API 层:Flask 暴露状态查询/注册接口(见下)。
- 部署:Helm chart(
megatron-timer-predichterv0.1.0),1 replica,镜像cr.infini-ai.com/tsinghua-lenovo/megatron-timer-predicter:v0.1.0,ClickHouse 配置经 env 注入。 - 模拟器:
simulator/不是凭空合成,而是回放真实 source job(默认jo-dbyrjz4l337e3y6j)到新sim-<uuid>job id,按write_speed节奏重放,便于本地端到端测试(8 rank 来自 source)。
说明:本项目不依赖 Prometheus/Grafana/Kafka。代码里有个
GET /metrics路由但只是占位符,没有真实 Prometheus 指标导出;Timer 数据直接写 ClickHouse 满足吞吐,没引入 Kafka 链路。
7.2 Flask API(api/flask_server_routes.py)
| 方法 | 路径 | 作用 |
|---|---|---|
| GET | / |
健康/版本 |
| GET | /metrics |
占位(无真实 Prometheus) |
| GET | /jobs |
列出监控中的 job |
| GET | /detect/<job_id> |
注册 job 进入监控 |
| GET | /undetect/<job_id> |
取消监控 |
| GET | /<job_id> |
主状态/检测结果 |
GET /<job_id> 返回结构:
1 | { |
straggler_rank / straggler_node 即从 summary.txt 解析出的异常 rank/节点列表。
7.3 关键参数(main.py)
| 参数 | 默认 | 含义 |
|---|---|---|
--slowdown-threshold |
0.25 | 慢 iter 判定:比中位数增长 >25% |
--hang-threshold |
60s | 无新 iter 多久判 hang |
--history-size |
5 | 慢 iter 历史/触发所需连续慢 iter 数 |
--check-interval |
30s | 轮询间隔(模拟 5s) |
--simulate / --write-speed |
— | 回放模式 |
八、落地效果与踩的坑
8.1 效果(评估口径)
- 异常检测准确率目标 >90%:以运维后确认的故障/换卡样本为基准,检出异常 rank 与之一致的比例(评估口径,非代码内置数值)。
- 覆盖多形态异常:温和偏移(慢簇均值高)、突刺(通信段 2× baseline)都能检出。
- 30 秒级分析:触发后准实时出结果。
- 真实价值:帮运维团队快速定位 GPU 故障/网络拥塞节点,把"靠人肉看日志找慢卡"从数小时压到分钟级。
8.2 落地中踩的坑(面试可讲)
- timer 0 值/覆盖不全:不是所有 rank 都打了某 subname(值 0 或缺失),早期没过滤被当"特别快"误判,后来加 subname 覆盖率检查 +
original_total_subnames门槛。 - 起步抖动:前 10 个 iter 训练 warmup 抖动大,直接聚类噪声高,改成丢弃前 10 iter。
- 算法参数敏感:DBSCAN 的 eps、KMeans 的 k/seed 对结果影响大,线上用基于 k-distance 膝点/分位数的自适应参数 + 网格调优选最优 silhouette,而非固定值。
- 归一化方式:z-score 受异常值拉动,改用 robust scale(median/MAD、IQR);判定"慢簇"用"均值最高"而非"离质心远",更贴合"相对落后"语义。
- PP 段 P2P 二义性:单看一段 send/recv 分不清 send/recv/网络,交叉验证规则 + PP group 一致性才定位准。
- 在线检测拉旧数据:batch 分析若不卡时间界会拉到 job 注册前的旧数据,commit
014d164加--start/--end修复。 - 代码重复定义:prediction.py 有方法重复定义两份(Python 取最后一份活性),改的时候要改活性那份,曾踩过"改了不生效"的坑。
九、系统架构总览
1 | Megatron 训练进程(每 step) |
十、面试速答清单
Q1:这个项目解决什么问题?为什么重要?
大规模分布式训练的 straggler(慢卡)问题。straggler 不是死机(NCCL 不报错)但拖慢整个集群——木桶效应下 1 张慢 20% 的卡让上千卡吞吐掉 20%。它难发现(均值掩盖、不报错)、难定位(原因多样:硬件降频/ECC/拓扑/网卡/通信)。系统目标就是自动、准、快地检测+归因。
Q2:数据从哪来?为什么用它?
从 ClickHouse 的
megatron_metrics表读 Megatron Timer 已落盘的指标(metric_name=megatron_timers,subname=interval-time/forward-compute/forward-send…,metric_values 是时长数组)。好处:粒度切到 forward-compute/backward-compute/通信段能直接看慢在哪段;跨 rank 可比;Timer 内部 cuda.synchronize 保证数据可信;落盘后检测与训练解耦,可在线/离线反复分析。
Q3:为什么用 6 种聚类 + 投票而不是单一算法?
没有单一算法通吃所有异常形态:KMeans/Agglomerative 抓质心偏离、DBSCAN/MeanShift 抓密度异常、GMM/Fuzzy 抓分布/隶属度偏离。选 6 个刻意覆盖距离/密度/分布/层次/峰值多类原理、盲区不重叠,ensemble 增益大。关键是六个算法判定准则统一规约为"均值最高的簇=slow",才能跨算法投票。
Q4:投票融合具体怎么做?有权重学习吗?
三层:①算法内跨 subname 加权多数(slow 票×2≥total,self-attention-qkv 权重3)+ original_total_subnames 门槛;②跨 6 算法取被标 slow 次数最多的 rank 为最终异常 rank;③cluster 异常 rank 与通信异常 worker 的节点取并集输出。没有加权打分、没有权重学习、没有标签回填重训——线上是固定计数取 max,简单可靠。(固定 ≥4/6 阈值只在被覆盖的死代码里,不生效。)
Q5:通信异常怎么定位到网络拥塞节点?
PP≥2 时对每个慢 iter 跑通信检测:基于 megatron_timers_trace(start/end 算时长)+ megatron_timers 的 send/recv baseline,worker 均值 > 2×baseline 判异常;再用 apply_cross_validation_rules 消解 send/recv 二义——send 异常⇒该 worker 发送拥塞或下游接收拥塞,结合 PP group 归属定端点;某 worker 所有通信段都慢→节点网络问题,只单段慢→那段链路问题;跨慢 iter 取并集。归因粒度到 worker/node,不到 NVSwitch/IB 口(那要外部拓扑系统)。
Q6:30 秒怎么做到的?
多进程并发——6 种聚类算法各一进程并行(ProcessPoolExecutor),通信检测每 iter ≤4 并行;sklearn 有 GIL 用进程不用线程。加向量化、subname 早筛、只分析慢 iter 区间不全量重算。瓶颈从"串行+全量"降到"算法并行+区间限定",分析阶段压到 30 秒内。触发靠 30s 轮询 + 连续 5 慢 iter 条件。
Q7:准确率 >90% 怎么算的?怎么保证不误报?
以运维后确认的故障/换卡样本为评估基准,检出异常 rank 与之一致的比例(目标 >90%,评估口径)。控误报靠:算法内 subname 加权多数 + original_total_subnames 门槛、跨算法取最高票、robust scale 抗异常值拉动、慢 iter 区间限定。落地踩过 0 值/覆盖不全误判、起步抖动、参数敏感等坑,分别靠 subname 覆盖检查、丢前 10 iter、自适应参数解决。
Q8:落地产出是什么?怎么用?
Flask 服务:GET /detect/<job_id> 注册监控,GET /<job_id> 查状态(status/slowdown_check/hang_check),返回 straggler_rank/straggler_node。运维拿这个去查那张卡/那根线。Helm chart 部署,ClickHouse 配置 env 注入。模拟器回放真实 job 供本地测试。
十一、一句话总结
Megatron Timer Predictor = 从 ClickHouse 读 Megatron Timer 全 rank 时序(已落盘)→ 在线轮询(30s)发现连续 5 个慢 iter(>25%)触发 batch 分析 → 6 种互补聚类算法(KMeans/DBSCAN/GMM/Agglomerative/MeanShift/Fuzzy)各把 rank 分 fast/slow(慢簇=均值最高)、算法内跨 subname 加权多数 + 跨算法取最高票 → PP≥2 时通信检测(trace+baseline 2×)+ send/recv 交叉验证定位网络拥塞 → 多进程并发把分析压到 30 秒 → Flask API 输出 straggler_rank/node。 它把"分布式训练谁慢、为什么慢"这件原本靠人肉看日志的事,变成了在线触发、自动、可归因的运维闭环。
参考资料
- 项目:
mt-detector(Megatron Timer Predicter) - Megatron-Core
timers.py/p2p_communication.py(数据源与 PP 通信打点,背景见《Megatron Timers 源码精读》) - sklearn: KMeans / DBSCAN / GaussianMixture / AgglomerativeClustering / MeanShift;手写 Fuzzy C-Means
- ClickHouse MergeTree + Array/Object 列式存储

