# 时序作为模态的多模态模型 · 设计规格 > **日期**:2026-06-29 > **状态**:已通过设计评审,待写实现计划 > **背景**:基于 `MTSAD-技术深度调研报告.md`,沿用 ChatTS「时序作为新模态」路线,在消费级硬件上做可复现的实验性落地 > **目标读者**:算法工程师(实现者)、技术决策者(评审者) --- ## 1. 目标与约束 ### 1.1 目标 构建一个把**多变量时序视为独立模态**、与文本/事件模态联合注入小型 LLM 的多模态模型,端到端任务是**时序问答与推理**(ChatTS 路线):以多变量时序为输入,支持自然语言问答、根因分析、异常解释等推理任务。 ### 1.2 硬约束 | 约束 | 取值 | 影响 | |------|------|------| | 算力 | **单张 3060 12GB 消费级显卡** | 骨干 ≤0.5B;依赖 LoRA/QLoRA + 短上下文 + 小批量;TS 编码器单独轻量训练 | | 模态范围 | 数值序列 + 变量属性 + 时间戳 + 事件 | 投影层需支持 TS token 与多类文本 token 并存;面向 AIOps 时序+事件联合推理 | | 数据 | **合成数据为主** | 需要 CPU 离线合成管线;评测锚定真实 benchmark 防止合成过拟合 | | 模型尺寸 | ≤0.5B(可更小) | 选用 Qwen2.5-0.5B-Instruct 作为骨干 | ### 1.3 非目标(YAGNI) - 不做从零预训练 LLM(成本不允许,且非本实验目的) - 不做多卡分布式训练(单卡约束) - 不追求学术 SOTA 排名,追求「在 12GB 上跑通、可复现、时序模态确有增益」的可验证结论 - 不做端侧部署优化(先验证方法) --- ## 2. 整体架构 ### 2.1 数据流 ``` 多变量时序 [T×C] │ Patchify (patch=P, stride=S, 通道独立) ▼ Patches [(T/P)×d] ──► TS Encoder (2层Transformer) ──► Projector (Linear→LLM hidden) │ ▼ TS Tokens [(T/P)×h] 变量属性 / 时间戳文本 / 事件标记 / 指令问题 ──► Tokenize ──► 文本/事件 Tokens │ [属性][时间戳][TS tokens][事件][问题] 拼接 ▼ LLM Backbone (Qwen2.5-0.5B, LoRA) ▼ 自然语言回答 (+ 可选 JSON 异常区间) ``` ### 2.2 关键设计决策 | 项 | 选择 | 理由 | |----|------|------| | 骨干 LLM | Qwen2.5-0.5B-Instruct | 0.5B 中英均衡、有 Instruct 版、社区生态成熟;BF16 约 1GB,12GB 余量充足 | | TS Encoder | 2 层 Transformer,d=256,4 头 | 够表达局部时序结构;参数约 4M,可与投影层一起全参训练 | | Patch | P=8, stride=4(重叠),通道独立 | 重叠 patch 保局部连续;通道独立避免 C 增大失配;T=512 → 128 个 TS token | | Projector | Linear(256→896) + LayerNorm | 把 TS 表示映射到 LLM 隐藏维(Qwen2.5-0.5B hidden=896),作为可学习 soft token 注入 | | LLM 微调 | LoRA r=16 (q/v_proj) + 冻结其余 | 12GB 关键约束;可训练参数约 2-3M | | 上下文 | ≤1024 token(128 TS + ~500 文本/事件) | 12GB 显存友好;T=512 时间步足够覆盖 AIOps 局部窗口 | | 输入拼接顺序 | `[属性][时间戳][TS tokens][事件][问题]` | 属性先给语义,时序居中,事件定位在对应时间,问题在末尾便于回答 | ### 2.3 与候选方案的对比(为什么选 Patch-Project + 轻量编码器) - **方案 A(本设计)Patch-Project + 轻量编码器**:时序切 patch → 小编码器 → 线性投影成独立 TS token。真正的"时序作为模态",12GB 可训,patch 捕捉局部结构、变长友好。需训练编码器+投影层(已在显存预算内)。 - **方案 B 时序 Tokenization(Chronos 风格)**:数值量化成离散 token、扩展词表。最"时序即语言"但量化丢精度、异常细节易损;逐点 token 序列长,12GB 上下文吃紧。放弃。 - **方案 C Reprogramming(Time-LLM 风格)**:冻结 LLM 用文本原型重映射。参数最省但受限于已有文本嵌入流形、表达力弱,时序算不上"真新模态",复杂推理/事件联合弱。放弃。 --- ## 3. 数据与合成管线 ### 3.1 总体管线(全 CPU 离线) ``` ① 属性采样 → ② 时序生成 → ③ 自动标注 → ④ 指令生成(Evol-Instruct) → ⑤ 回答生成 ``` 产物为 JSONL,每条含:`series` / `attributes` / `timestamps` / `events` / `instruction` / `answer` / `labels`。 ### 3.2 合成时序的成分模型 每条时序由可配置成分叠加,覆盖 AIOps 常见形态: | 成分 | 实现 | 覆盖场景 | |------|------|----------| | 趋势 trend | 分段线性 / log / 阶跃 | 容量增长、版本切换 | | 周期 seasonal | 多周期正弦叠加(日/周) | 流量昼夜规律 | | 基线水平 | 常数 + 缓慢漂移 | 稳态负载 | | 噪声 | 高斯 + 重尾(Student-t) | 真实传感器抖动 | | 异常注入 | 尖刺/水平偏移/方差膨胀/缺失段/缓慢漂移 | 对应 MTSAD 报告异常类型谱 | | 事件耦合 | 在指定 t 注入阶跃,并生成对应事件文本 | 部署/扩容 → 指标跳变 | | 缺失/不规则 | 随机丢弃 5-10% 点 | 真实采集缺陷 | **核心红利**:异常段、事件时间戳、各成分参数全部作为 ground-truth 自动记录——免费且精确的标签。 ### 3.3 指令任务类型(Evol-Instruct 扩展) | 类别 | 示例问题 | 对齐目的 | |------|----------|----------| | 描述/统计 | "这段时序的均值/趋势是什么?" | 基础数值→文本对齐 | | 异常检测 | "哪些时段出现异常?类型?" | 核心任务,带段标签 | | 根因/解释 | "t=320 后为何突增?" | 结合事件做因果推理 | | 预测 | "未来 32 步走势?" | 时序外推能力 | | 比较 | "变量 A 和 B 谁更稳定?" | 跨通道关系建模 | | 事件关联 | "这次异常和部署事件有关吗?" | 时序+事件模态融合 | ### 3.4 规模(12GB 友好) - 对齐预训练阶段:**~50 万条**合成三元组(CPU 生成,约 1-2 天可跑完) - 指令微调阶段:从 50 万中 **Evol-Instruct 演化出 ~10 万条**高质量多轮对话 - 评测集:**固定 2,000 条** held-out 合成 + 公开 benchmark 抽样 - 每条时序 T=512, C∈[3,12],单条约 2-4KB,总量约 2-3GB,训练时流式加载 ### 3.5 评测用的真实锚点 合成数据训练,但评测锚定真实分布,避免"合成上 SOTA、真实上崩盘": | 用途 | 数据 | 处理 | |------|------|------| | 真零样本问答评测 | SMD / MSL / SMAP / SWaT 窗口 | 用 LLM 把异常段转成"问答对"做评测(不参与训练) | | 异常检测指标 | 同上 + PSM | 模型输出文本中的异常区间 → 解析为二值分数 | | 对照基线 | — | ChatTS / Time-LLM / 纯 LLM(数值喂文本)同口径对比 | --- ## 4. 训练流程与阶段 ### 4.1 三阶段 **阶段 ① 时序-文本对齐预训练**(~50 万条合成三元组) - 可训练:TS Encoder + Projector(全参,~4.2M) - 冻结:LLM 主体 - 目标:让 TS token 在 LLM 表示空间"能被读懂" - 损失:回答 token 的 LM loss(仅回答段计 loss)+ 对比损失(扰动时序→回答应变) - ~2-3 epoch **阶段 ② 指令微调 SFT**(~10 万条 Evol-Instruct 多轮) - 可训练:TS Encoder + Projector + LoRA(r=16),~7M - 冻结:LLM 其余权重 - 目标:建立指令遵循 + 推理 + 异常/事件关联 - 损失:SFT LM loss,对回答做 mask - ~3 epoch **阶段 ③ 评测与可选 DPO**(2k held-out + 真实 benchmark) - 评测:问答准确率 + 异常检测指标 - 可选:DPO 用正确/错误回答对偏好优化 - 可选:真实数据少量微调做领域适配 ### 4.2 显存预算(12GB 3060) | 项 | 阶段① 对齐预训练 | 阶段② SFT | |----|------------------|-----------| | 可训练参数 | TS Encoder(4M)+Projector(0.2M) ≈ **4.2M** | + LoRA(2-3M) ≈ **7M** | | LLM 状态 | BF16 冻结(~1GB 权重) | BF16 + LoRA 适配器 | | 优化器 | AdamW(仅训 4.2M,显存极省) | AdamW + LoRA | | 批量 | per_device=8, grad_accum=4 → eff 32 | per_device=4, grad_accum=8 → eff 32 | | 上下文 | 512 token | 1024 token | | 梯度检查点 | 开 | 开 | | 混合精度 | BF16(3060 支持) | BF16 | | 预估峰值显存 | **~4-5GB** | **~9-10GB** | | 单 epoch 时长(估) | ~6-10 小时 | ~8-12 小时 | ### 4.3 关键工程要点 - **阶段① 省显存的核心**:LLM 冻结 → 不需要存 LLM 的优化器状态和梯度,12GB 绰绰有余,甚至能加大批量 - **阶段② 才上 LoRA**:仅给 LLM 加 r=16 的 q/v_proj 适配器,可训练参数 ~2-3M,配合梯度检查点压在 10GB 内 - **分阶段 checkpoint**:阶段①产物 = "TS Encoder+Projector";阶段②在此之上叠加 LoRA,互不污染、可回滚 - **损失 masking**:仅对回答段 token 计算 LM loss,prompt(属性/时序/事件/问题)段不计 - **断点续训**:每 2000 step 存 checkpoint,JSONL 流式加载支持任意 step 续 ### 4.4 防止"时序模态塌缩"的训练技巧 | 风险 | 对策 | |------|------| | LLM 忽略 TS token,只看文本答题 | 构造"必须看时序才能答"的样本(如具体数值/段位置),并在阶段①用对比损失:扰动时序→回答应变 | | TS Encoder 过拟合合成分布 | 成分参数随机化 + 多套合成配置 + 阶段②引入真实 benchmark 改写样本 | | 异常稀有导致模型回避 | 合成时强制每条至少含 1 类异常,指令中异常类任务占比 ≥40% | | 回答格式不稳定 | 回答模板约束输出 JSON 区间(如 `{"segments":[[320,360]],"type":"spike"}`),便于评测解析 | --- ## 5. 评估方法 ### 5.1 三条评测支柱 **A · 时序问答准确率** - 主:LLM-as-judge(GPT-4o 评分 0-5) - 辅:规则解析 JSON 区间精确匹配 - 6 类指令任务分别报分 - held-out 合成 2k + 真实改写 **B · 异常检测指标**(严守 MTSAD 报告评估纪律) - 主:**VUS-PR**(阈值无关) - Affiliation-F1(λ=0.1/0.5/1.0) - AUC-PR、Point-F1(无 PA) - **PA-F1 仅对照、不得作主指标** **C · 泛化与消融** - 跨数据集:SMD→MSL/SWaT - 模态消融:去掉事件/属性/时序 - trivial 基线对照(Random/Constant) - 同口径对比 ChatTS/Time-LLM/纯 LLM ### 5.2 异常检测:从自然语言回答 → 数值分数 | 步骤 | 做法 | |------|------| | 1. 约束输出格式 | 训练时要求回答含 `{"segments":[[s,e],...],"type":...,"score":...}` | | 2. 解析区间 | 正则/JSON 解析模型回答中的异常段 | | 3. 生成逐点分数 | 段内点赋 1.0,段外 0.0;可叠加模型自报置信度 score | | 4. 算指标 | 用 `tsb_uad` / 自实现 VUS-PR、Aff-F1、AUC-PR、Point-F1 | | 5. 鲁棒性兜底 | 解析失败 → 分数全 0(计为漏报),单独统计解析成功率 | ### 5.3 问答评测:LLM-judge + 规则双轨 | 轨 | 适用任务 | 方法 | |----|----------|------| | 规则解析(客观) | 异常检测、统计描述、预测 | JSON 区间/数值容差比对,可重复、零成本 | | LLM-judge(主观) | 根因解释、事件关联、比较 | GPT-4o 对 (问题,时序摘要,参考答案,模型答案) 打 0-5 分 + 理由 | | 交叉校验 | 全部 | 两类不一致的样本人工抽检,定位系统性偏差 | ### 5.4 必报指标与报告规范 **必报(每数据集×每任务):** - 异常检测:VUS-PR(主)、Affiliation-F1(多λ)、AUC-PR、Point-F1(无PA) - 问答:LLM-judge 均分、规则解析准确率、解析成功率 - 泛化:跨数据集 F1/VUS-PR 衰减比例 - 消融:去掉各模态后的指标变化 **禁止:** 仅报 PA-F1 / 单数据集称 SOTA / 不报 trivial 基线 / 不标是否用 PA。 ### 5.5 对照基线(同口径同评测脚本) - **纯 LLM 数值喂文本**:把时序数值直接拼成文本喂 Qwen2.5-0.5B —— 检验"TS 模态"是否真带来增益 - **Time-LLM 风格重映射**:同样 0.5B 骨干,对比"重映射 vs 我们的新模态" - **ChatTS**(若可复现):对比同类多模态时序 LLM - **Trivial**:Random / Constant / "全报异常" —— 确保不是评估虚高 --- ## 6. 工程落地与代码结构 ### 6.1 项目布局 ``` ts-as-modality/ ├── README.md ├── pyproject.toml # 依赖:torch, transformers, peft, accelerate, datasets ├── configs/ │ ├── ts_encoder.yaml # TS Encoder/Projector 超参 │ ├── stage1_align.yaml # 对齐预训练 │ ├── stage2_sft.yaml # 指令微调 │ └── eval.yaml ├── src/tsmm/ │ ├── __init__.py │ ├── data/ │ │ ├── synthesis.py # 成分模型 + 异常注入 + 事件耦合 │ │ ├── attributes.py # 属性词表采样 │ │ ├── instruct.py # Evol-Instruct 指令/回答生成 │ │ ├── collator.py # 拼接 [属性][时间戳][TS tok][事件][问题]→ token流 │ │ └── real_bench.py # SMD/MSL/SMAP/SWaT/PSM 加载 + 问答改写 │ ├── model/ │ │ ├── ts_encoder.py # Patchify + 2层TF + Projector │ │ ├── projector.py # Linear→LLM hidden │ │ ├── multimodal.py # 组装 TS token + 文本 token 进 LLM │ │ └── wrapper.py # 训练/推理统一封装(含 LoRA 挂载) │ ├── train/ │ │ ├── stage1.py # 冻结LLM,训 Encoder+Projector │ │ ├── stage2.py # 加 LoRA SFT │ │ └── losses.py # LM loss mask + 对比损失 │ ├── eval/ │ │ ├── parse_answer.py # 文本→JSON 区间→逐点分数 │ │ ├── ts_metrics.py # VUS-PR / Aff-F1 / AUC-PR / Point-F1 │ │ ├── qa_judge.py # 规则解析 + LLM-judge │ │ └── baselines.py # 纯LLM/Time-LLM/ChatTS/trivial 同口径 │ └── utils/ ├── scripts/ │ ├── gen_synthetic.py # 离线生成 50万 + 10万 JSONL │ ├── train_stage1.sh │ ├── train_stage2.sh │ └── run_eval.sh ├── data/ # 生成产物(git-ignored) ├── checkpoints/ # 分阶段 ckpt(git-ignored) └── tests/ # 各模块单元测试 ``` ### 6.2 技术栈 | 层 | 选型 | 理由 | |----|------|------| | 骨架 | Qwen2.5-0.5B-Instruct (HF Transformers) | 0.5B、中英、Instruct 版现成 | | 微调 | PEFT (LoRA) + Accelerate | 12GB 标配组合 | | 数据 | datasets 流式 + JSONL | 2-3GB 无需全载内存 | | 合成 | NumPy + tqdm,纯 CPU 多进程 | 不占显存,可后台跑 | | 评估 | tsb_uad(VUS-PR)+ 自实现 Aff-F1 | 对齐报告推荐实现 | | LLM-judge | OpenAI/GPT-4o API(评测时才调) | 仅评测用,不进训练 | | 实验追踪 | TensorBoard / wandb(可选) | 轻量 | ### 6.3 交付里程碑 | 里程碑 | 内容 | 验证点 | |--------|------|--------| | M1 · 数据管线 | 合成生成 + 真实 benchmark 加载,产出 1k 样本可视检 | 成分/异常/事件正确,JSONL schema 合规 | | M2 · 模型可跑通 | TS Encoder+Projector+多模态拼接,单 batch 前向+反向在 3060 不 OOM | 形状对、显存<12GB、loss 下降 | | M3 · 阶段① 对齐训练 | 50万条 2-3 epoch,TS token 不被忽略 | 扰动时序→回答变化 | | M4 · 阶段② SFT | 10万条 3 epoch + LoRA,6 类任务能遵循指令 | held-out 问答可用 | | M5 · 完整评测 | VUS-PR/Aff-F1/问答分,4 类基线同口径对比 | 超纯LLM基线、非PA虚高 | ### 6.4 风险与对策 | 风险 | 概率 | 对策 | |------|------|------| | 12GB 仍 OOM(阶段②) | 中 | 降批量/上下文、开 CPU offload 优化器、退回阶段①-only 报告 | | 合成→真实泛化差距大 | 高 | 阶段②掺真实改写样本;评测以真实 benchmark 为准 | | LLM 忽略 TS token | 中 | 对比损失 + "必看时序"样本 + 消融实验定位 | | 回答 JSON 解析失败率高 | 中 | 训练强化格式约束 + 解析兜底 + 单独报成功率 | | GPT-4o judge 成本 | 低 | 仅评测 2k 样本调用;可换开源 judge 做 sanity | ### 6.5 整体成功标准(可验证) 1. 全流程在单张 3060 12GB 跑通,阶段②峰值显存 ≤ 11GB 2. 真实 benchmark(SMD/MSL/SMAP/SWaT)VUS-PR **显著优于纯 LLM 数值喂文本基线** 3. 时序消融后指标明显下降,证明"时序模态"确有贡献 4. 6 类问答任务 LLM-judge 均分 > 纯 LLM 基线 5. 评测脚本可复现,含 trivial 基线对照、标注是否用 PA --- ## 7. 开放问题(实现阶段再定) - TS Encoder 层数/d 是否需在小规模上 sweep(2 层是否够) - Patch P=8/stride=4 是否最优,是否需对比 P=16 - 对比损失的具体形式(InfoNCE vs 扰动一致性)与权重 - DPO 是否纳入首版(建议首版先不做,M5 后视效果决定) - 真实 benchmark 改写问答的数量与质量校验流程 --- > 本规格定义了「长什么样、吃什么数据、怎么训、怎么评、怎么落地」。下一步进入实现计划(writing-plans)。