From c160718934cb67b846852fd296b15b368895451d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E5=AE=97=E5=B9=B3?= Date: Mon, 29 Jun 2026 22:29:31 +0800 Subject: [PATCH] chore(ts-as-modality): scaffold OpenSpec change & adopt reviewed design - OpenSpec change: proposal/design/tasks + 3 delta specs (ts-synthesis, ts-multimodal-model, ts-evaluation; 21 requirements) - comet state initialized (phase=build), plan recorded - adopt existing reviewed design doc as Design Doc (+ comet frontmatter) - existing implementation plan (+ comet frontmatter) - workspace .gitignore --- .gitignore | 1 + .../plans/2026-06-29-ts-as-modality-plan.md | 6 + .../specs/2026-06-29-ts-as-modality-design.md | 6 + openspec/changes/ts-as-modality/.comet.yaml | 22 + .../.comet/handoff/brainstorm-summary.md | 41 ++ .../.comet/handoff/design-context.json | 16 + .../.comet/handoff/design-context.md | 438 ++++++++++++++++++ .../changes/ts-as-modality/.openspec.yaml | 2 + openspec/changes/ts-as-modality/design.md | 88 ++++ openspec/changes/ts-as-modality/proposal.md | 33 ++ .../specs/ts-evaluation/spec.md | 61 +++ .../specs/ts-multimodal-model/spec.md | 73 +++ .../ts-as-modality/specs/ts-synthesis/spec.md | 77 +++ openspec/changes/ts-as-modality/tasks.md | 45 ++ 14 files changed, 909 insertions(+) create mode 100644 openspec/changes/ts-as-modality/.comet.yaml create mode 100644 openspec/changes/ts-as-modality/.comet/handoff/brainstorm-summary.md create mode 100644 openspec/changes/ts-as-modality/.comet/handoff/design-context.json create mode 100644 openspec/changes/ts-as-modality/.comet/handoff/design-context.md create mode 100644 openspec/changes/ts-as-modality/.openspec.yaml create mode 100644 openspec/changes/ts-as-modality/design.md create mode 100644 openspec/changes/ts-as-modality/proposal.md create mode 100644 openspec/changes/ts-as-modality/specs/ts-evaluation/spec.md create mode 100644 openspec/changes/ts-as-modality/specs/ts-multimodal-model/spec.md create mode 100644 openspec/changes/ts-as-modality/specs/ts-synthesis/spec.md create mode 100644 openspec/changes/ts-as-modality/tasks.md diff --git a/.gitignore b/.gitignore index 57767dc..63268e9 100644 --- a/.gitignore +++ b/.gitignore @@ -87,6 +87,7 @@ coverage/ .pi/logs/ # Claude Code local runtime +.claude/settings.local.json .claude/sessions/ .claude/cache/ .claude/logs/ diff --git a/docs/superpowers/plans/2026-06-29-ts-as-modality-plan.md b/docs/superpowers/plans/2026-06-29-ts-as-modality-plan.md index 566ba92..491181a 100644 --- a/docs/superpowers/plans/2026-06-29-ts-as-modality-plan.md +++ b/docs/superpowers/plans/2026-06-29-ts-as-modality-plan.md @@ -1,3 +1,9 @@ +--- +change: ts-as-modality +design-doc: docs/superpowers/specs/2026-06-29-ts-as-modality-design.md +base-ref: 7a5a1d033fb1ac20af25a17a571b2791694bd923 +--- + # 时序作为模态的多模态模型 · 实现计划 > **对应规格**:`docs/superpowers/specs/2026-06-29-ts-as-modality-design.md` diff --git a/docs/superpowers/specs/2026-06-29-ts-as-modality-design.md b/docs/superpowers/specs/2026-06-29-ts-as-modality-design.md index d6c9e86..f9043ef 100644 --- a/docs/superpowers/specs/2026-06-29-ts-as-modality-design.md +++ b/docs/superpowers/specs/2026-06-29-ts-as-modality-design.md @@ -1,3 +1,9 @@ +--- +comet_change: ts-as-modality +role: technical-design +canonical_spec: openspec +--- + # 时序作为模态的多模态模型 · 设计规格 > **日期**:2026-06-29 diff --git a/openspec/changes/ts-as-modality/.comet.yaml b/openspec/changes/ts-as-modality/.comet.yaml new file mode 100644 index 0000000..6f19598 --- /dev/null +++ b/openspec/changes/ts-as-modality/.comet.yaml @@ -0,0 +1,22 @@ +workflow: full +phase: build +context_compression: off +build_mode: executing-plans +build_pause: null +subagent_dispatch: null +tdd_mode: tdd +review_mode: standard +isolation: branch +verify_mode: null +auto_transition: true +base_ref: 7a5a1d033fb1ac20af25a17a571b2791694bd923 +design_doc: docs/superpowers/specs/2026-06-29-ts-as-modality-design.md +plan: docs/superpowers/plans/2026-06-29-ts-as-modality-plan.md +verify_result: pending +verification_report: null +branch_status: pending +created_at: 2026-06-29 +verified_at: null +archived: false +handoff_context: openspec/changes/ts-as-modality/.comet/handoff/design-context.json +handoff_hash: 067d854db86de682b8c5e173888ab9b0d890244bf938aef24512ec8287789be7 diff --git a/openspec/changes/ts-as-modality/.comet/handoff/brainstorm-summary.md b/openspec/changes/ts-as-modality/.comet/handoff/brainstorm-summary.md new file mode 100644 index 0000000..fabee2a --- /dev/null +++ b/openspec/changes/ts-as-modality/.comet/handoff/brainstorm-summary.md @@ -0,0 +1,41 @@ +# Brainstorm Summary + +- Change: ts-as-modality +- Date: 2026-06-29 + +## 确认的技术方案 + +采纳既有、已评审 Design Doc `docs/superpowers/specs/2026-06-29-ts-as-modality-design.md` 为本次 change 的 Design Doc(comet-design 前置条件「无 Design Doc」被既有文件违反,实质性深度设计已完成,无需重新 brainstorm 出重复文档)。 + +核心技术方案(源自 Design Doc): +- 路线:ChatTS「时序作为新模态」—— Patch-Project + 轻量编码器(优于 Chronos 时序 Tokenization、Time-LLM Reprogramming) +- 骨干:Qwen2.5-0.5B-Instruct(hidden=896) +- TS Encoder:Patchify(P=8, stride=4, 通道独立) + 2 层 Transformer(d=256, 4 头, ~4M) +- Projector:Linear(256→896) + LayerNorm +- 多模态拼接顺序:`[属性][时间戳][TS token][事件][问题]` +- 两阶段训练:①冻结 LLM 训 Encoder+Projector(~4.2M,省显存关键)→ ②叠加 LoRA r=16(q/v_proj) SFT(~7M) +- 数据:CPU 离线合成为主(50万对齐 + 10万 SFT + 2k held-out),真实 benchmark(SMD/MSL/SMAP/SWaT/PSM) 仅锚定评测 +- 评测:VUS-PR 为主(严守 MTSAD 纪律,PA-F1 仅对照),LLM-judge + 规则解析双轨,4 类同口径基线 + +## 关键取舍与风险 + +- [对比损失默认] 采用「扰动一致性 + λ=0.1」作为默认,做成可配置;若 M3「TS-token 有效性检验」(扰动后回答变化率 >50%)失败再换 InfoNCE。 +- [DPO] 首版不做,M5 后视效果决定。 +- [高风险·合成→真实泛化] 阶段②掺真实 benchmark 改写样本;评测以真实 benchmark 为准。 +- [中风险·阶段② 12GB OOM] 降批量/ctx、CPU offload、adamw_8bit、退回阶段①-only 报告。 +- [中风险·LLM 忽略 TS token] 对比损失 + 必看时序样本 + 消融定位。 +- [中风险·JSON 解析失败] 训练强化格式约束 + 解析兜底(失败→全 0 计漏报)+ 单独报解析成功率。 + +开放问题(TS Encoder 层/d、Patch P、对比损失形式、DPO、真实改写数量)均延后为 build 阶段经验/流程项,不阻塞设计。 + +## 测试策略 + +- 单元测试:各模块(attributes/synthesis/instruct/ts_encoder/projector/multimodal/collator/losses/parse/ts_metrics)给定 seed 确定性 + 形状/参数量校验 +- 冒烟路径:`gen_synthetic.py --n 200` → T2.1-T2.4 单 batch → stage1/stage2 `--max_steps 50` → run_eval.sh 产报告骨架,确认端到端通后再放大 +- 里程碑出口验证:M1-M5 每阶段有可执行完成判据 +- 评测:异常检测 VUS-PR/Aff-F1/AUC-PR/Point-F1(无PA) + PA-F1(对照);问答 LLM-judge + 规则解析;含 trivial 基线对照防虚高 +- 可验证成功标准(§6.5):阶段②峰值显存 ≤11GB;真实 benchmark VUS-PR 显著优于纯 LLM 基线;时序消融后指标下降;问答均分超基线;评测可复现 + +## Spec Patch + +无。4 项高风险均有对应 delta spec 验收场景闭环;成功标准由 tasks M5.6 出口验证承载,不另开第二份需求 spec。 diff --git a/openspec/changes/ts-as-modality/.comet/handoff/design-context.json b/openspec/changes/ts-as-modality/.comet/handoff/design-context.json new file mode 100644 index 0000000..b5a69da --- /dev/null +++ b/openspec/changes/ts-as-modality/.comet/handoff/design-context.json @@ -0,0 +1,16 @@ +{ + "change": "ts-as-modality", + "phase": "design", + "mode": "compact", + "canonical_spec": "openspec", + "generated_by": "comet-handoff.sh", + "context_hash": "067d854db86de682b8c5e173888ab9b0d890244bf938aef24512ec8287789be7", + "files": [ + { "path": "openspec/changes/ts-as-modality/proposal.md", "sha256": "d29658df95f49b889a7f06e6985776ba944f2476eca8e06f074787e823408f4e" }, + { "path": "openspec/changes/ts-as-modality/design.md", "sha256": "5b920360b1303fde23795a3388c34a11c0c562daa340de12980ff86a1d199f7b" }, + { "path": "openspec/changes/ts-as-modality/tasks.md", "sha256": "8e13037661b54a1579cc1c9c81ff2676aee777ca25303ef54c944ce91e852726" }, + { "path": "openspec/changes/ts-as-modality/specs/ts-evaluation/spec.md", "sha256": "1c986559a6b44900bff452e4cbbb0272c1ee321de2fddacedc6e096c4e5381fb" }, + { "path": "openspec/changes/ts-as-modality/specs/ts-multimodal-model/spec.md", "sha256": "f40631b2e8dac3772f6081623d2175460ca5355a8818d6cb3c28a94f148d56a3" }, + { "path": "openspec/changes/ts-as-modality/specs/ts-synthesis/spec.md", "sha256": "330043d178e344f1f1e87d1262f25ed33b2216eb6e16f2658d4f29a779d8b60b" } + ] +} diff --git a/openspec/changes/ts-as-modality/.comet/handoff/design-context.md b/openspec/changes/ts-as-modality/.comet/handoff/design-context.md new file mode 100644 index 0000000..6b67bfa --- /dev/null +++ b/openspec/changes/ts-as-modality/.comet/handoff/design-context.md @@ -0,0 +1,438 @@ +# Comet Design Handoff + +- Change: ts-as-modality +- Phase: design +- Mode: compact +- Context hash: 067d854db86de682b8c5e173888ab9b0d890244bf938aef24512ec8287789be7 + +Generated-by: comet-handoff.sh + +OpenSpec remains the canonical capability spec. This handoff is a deterministic, source-traceable context pack, not an agent-authored summary. + +## openspec/changes/ts-as-modality/proposal.md + +- Source: openspec/changes/ts-as-modality/proposal.md +- Lines: 1-33 +- SHA256: d29658df95f49b889a7f06e6985776ba944f2476eca8e06f074787e823408f4e + +```md +## Why + +当前 AIOps 场景下,多变量时序的异常检测与解释仍依赖专用模型,缺乏「以自然语言对时序提问、做根因/事件关联推理」的统一能力。基于 `MTSAD-技术深度调研报告.md`,沿用 ChatTS「时序作为新模态」路线,我们希望在**单张 3060 12GB 消费级显卡**上做一个可复现的实验性落地,验证「把多变量时序视为独立模态、与文本/事件模态联合注入小型 LLM」这一方法在算力受限条件下是否切实可行、且「时序模态」是否真带来可量化的增益。现在做是因为:0.5B 级开源 LLM 与 PEFT/LoRA 工具链已足够成熟,使该实验在消费级硬件上首次成为可能。 + +## What Changes + +- **新增**:CPU 离线合成数据管线(成分模型 + 异常注入 + 事件耦合 + Evol-Instruct 指令/回答生成),产出对齐预训练与 SFT 用的 JSONL +- **新增**:真实 benchmark(SMD/MSL/SMAP/SWaT/PSM)窗口加载与「异常段→问答对」改写(仅评测用,不进训练) +- **新增**:TS Encoder(Patchify + 2 层 Transformer)+ Projector(Linear→LLM hidden),把时序编码为独立 soft token +- **新增**:多模态拼接器,按 `[属性][时间戳][TS token][事件][问题]` 顺序组装文本 token 与 TS token 注入 LLM +- **新增**:两阶段训练流程 —— 阶段①冻结 LLM 训 Encoder+Projector(对齐预训练);阶段②叠加 LoRA(r=16) 做指令微调 +- **新增**:评测套件 —— 文本回答→JSON 区间→逐点分数解析;VUS-PR(主)/Affiliation-F1/AUC-PR/Point-F1(无PA);LLM-judge + 规则解析双轨 +- **新增**:4 类同口径对照基线(纯 LLM 数值喂文本 / Time-LLM 风格重映射 / ChatTS(若可复现) / Trivial) +- 骨干选用 **Qwen2.5-0.5B-Instruct**,BF16 + LoRA + 梯度检查点,目标阶段②峰值显存 ≤11GB + +## Capabilities + +### New Capabilities +- `ts-synthesis`: CPU 离线合成数据管线——成分模型(趋势/周期/基线/噪声)、异常注入(尖刺/水平偏移/方差膨胀/缺失段/缓慢漂移)、事件耦合、缺失/不规则模拟、属性词表采样,以及 Evol-Instruct 多轮指令与回答生成;附带真实 benchmark 加载与问答改写 +- `ts-multimodal-model`: 时序作为模态的多模态模型——TS Encoder + Projector + 多模态拼接(TS token 与文本/事件 token 联合注入 LLM),含阶段①对齐预训练与阶段②LoRA SFT 的训练/推理统一封装 +- `ts-evaluation`: 时序问答与异常检测评测套件——回答解析(文本→JSON 区间→逐点分数)、阈值无关指标(VUS-PR 主/Affiliation-F1/AUC-PR/Point-F1 无 PA)、LLM-judge + 规则双轨、4 类同口径基线对照、可复现评测报告 + +### Modified Capabilities + + +## Impact + +- **新增代码**:独立 Python 项目 `ts-as-modality/`(`pyproject.toml` + `src/tsmm/{data,model,train,eval,utils}` + `scripts/` + `tests/` + `configs/`),与当前 spec/docs 工作区并列 +- **依赖**:torch、transformers、peft、accelerate、datasets、numpy、tqdm、pyyaml、pytest;评测依赖 `tsb_uad`(VUS-PR);LLM-judge 评测时调用 OpenAI/GPT-4o API +- **模型资产**:Qwen2.5-0.5B-Instruct 骨干(外部下载);阶段①/② checkpoint 与合成数据产物体积较大,需 git-ignore(`data/`、`checkpoints/`) +- **算力**:单张 3060 12GB;阶段①预估峰值 ~4-5GB,阶段②预估峰值 ~9-10GB;CPU 多进程用于离线合成 +- **存储**:合成数据约 2-3GB(流式加载),checkpoint 分阶段独立存放 +- **无 BREAKING 变更**:纯新增独立实验项目,不触碰现有任何代码/接口 +``` + +## openspec/changes/ts-as-modality/design.md + +- Source: openspec/changes/ts-as-modality/design.md +- Lines: 1-88 +- SHA256: 5b920360b1303fde23795a3388c34a11c0c562daa340de12980ff86a1d199f7b + +[TRUNCATED] + +```md +## Context + +本 change 在**单张 3060 12GB 消费级显卡**上做一个可复现的实验性落地:把**多变量时序视为独立模态**,与文本/事件模态联合注入小型 LLM(Qwen2.5-0.5B-Instruct),端到端任务是**时序问答与推理**(ChatTS 路线)。 + +背景与约束来自 `MTSAD-技术深度调研报告.md` 与 `docs/superpowers/specs/2026-06-29-ts-as-modality-design.md`(已通过设计评审)。核心约束: + +- **算力**:单卡 12GB → 骨干 ≤0.5B、依赖 LoRA/QLoRA + 短上下文 + 小批量 + 梯度检查点 +- **数据**:合成数据为主(CPU 离线生成)→ 评测锚定真实 benchmark,防合成过拟合 +- **目标**:不追学术 SOTA,追「12GB 跑通、可复现、时序模态确有增益」的可验证结论 + +## Goals / Non-Goals + +**Goals:** +- 全流程单卡 3060 12GB 跑通,阶段②峰值显存 ≤11GB +- TS Encoder + Projector 把时序编码为独立 soft token,使 LLM「能读懂」时序 +- 时序模态带来可量化增益:真实 benchmark VUS-PR 显著优于纯 LLM 数值喂文本基线;时序消融后指标明显下降 +- 6 类问答任务(描述/异常/根因/预测/比较/事件关联)LLM-judge 均分超纯 LLM 基线 +- 评测可复现:含 trivial 基线对照、标注是否用 PA、严守 MTSAD 报告评估纪律 + +**Non-Goals:** +- ❌ 不从零预训练 LLM(成本不允许,且非本实验目的) +- ❌ 不做多卡分布式训练(单卡约束) +- ❌ 不追求学术 SOTA 排名 +- ❌ 不做端侧部署优化(先验证方法) +- ❌ DPO 首版不做(M5 后视效果再决定) + +## Decisions + +### 决策 1:采用 Patch-Project + 轻量编码器,而非时序 Tokenization 或 Reprogramming + +时序切 patch(P=8, stride=4,通道独立)→ 2 层 Transformer 编码器(d=256, 4 头, ~4M)→ 线性投影(256→896)成独立 TS token,作为可学习 soft token 注入 LLM。 + +**对比的备选方案:** + +| 方案 | 含义 | 取舍 | +|------|------|------| +| **A(选用)Patch-Project + 轻量编码器** | patch→小编码器→线性投影成独立 TS token | 真正的"时序作为模态";12GB 可训;patch 捕捉局部结构、变长友好。代价:需训编码器+投影层(已在显存预算内) | +| B 时序 Tokenization(Chronos 风格) | 数值量化成离散 token、扩展词表 | 最"时序即语言",但量化丢精度、异常细节易损;逐点 token 序列长,12GB 上下文吃紧。放弃 | +| C Reprogramming(Time-LLM 风格) | 冻结 LLM 用文本原型重映射 | 参数最省,但受限于已有文本嵌入流形、表达力弱,时序算不上"真新模态",复杂推理/事件联合弱。放弃 | + +### 决策 2:骨干选 Qwen2.5-0.5B-Instruct + +0.5B 中英均衡、有现成 Instruct 版、社区生态成熟;BF16 约 1GB,12GB 余量充足(hidden=896)。 + +### 决策 3:两阶段训练,阶段①冻结 LLM + +- **阶段① 对齐预训练**:冻结 LLM,仅训 TS Encoder + Projector(~4.2M 全参)→ 不存 LLM 优化器状态/梯度,是 12GB 可行的关键省显存技巧 +- **阶段② SFT**:在此之上叠加 LoRA r=16(q/v_proj,~2-3M),LLM 其余冻结 + 梯度检查点 + +分阶段 checkpoint 互不污染、可回滚。损失仅对回答段 token 计 LM loss;阶段①叠加对比损失(扰动时序→回答应变)防止 LLM 忽略 TS token。 + +### 决策 4:输入拼接顺序 `[属性][时间戳][TS token][事件][问题]` + +属性先给语义,时序居中,事件定位在对应时间,问题在末尾便于回答。 + +### 决策 5:合成数据为主,真实 benchmark 仅用于评测锚定 + +合成管线全 CPU 离线,成分参数随机化;**核心红利**:异常段、事件时间戳、各成分参数全部作为 ground-truth 自动记录——免费且精确的标签。评测锚定 SMD/MSL/SMAP/SWaT/PSM 真实分布,避免「合成上 SOTA、真实上崩盘」。 + +### 决策 6:评测指标以 VUS-PR 为主,严守 MTSAD 报告纪律 + +- 主指标 **VUS-PR**(阈值无关);辅 Affiliation-F1(多 λ)、AUC-PR、Point-F1(无 PA) +- **PA-F1 仅作对照、不得作主指标**(防虚高) +- 问答用 LLM-judge + 规则解析双轨 +- 自然语言回答→约束 JSON 区间→逐点分数,便于数值化评测 + +### 决策 7:4 类同口径基线 + +纯 LLM 数值喂文本(检验 TS 模态是否真有增益)、Time-LLM 风格重映射、ChatTS(若可复现)、Trivial(Random/Constant/全报异常)。全部走同一套解析+指标脚本。 + +## Risks / Trade-offs + +- [12GB 阶段②仍 OOM] → 降批量/上下文、开 CPU offload 优化器、`adamw_8bit`、退回阶段①-only 报告 +- [合成→真实泛化差距大(高风险)] → 阶段②掺真实 benchmark 改写样本;评测以真实 benchmark 为准 +- [LLM 忽略 TS token] → 对比损失 + "必看时序"样本 + 消融实验定位 +- [回答 JSON 解析失败率高] → 训练强化格式约束 + 解析兜底(失败→全 0 计漏报)+ 单独报解析成功率 +- [GPT-4o judge 成本] → 仅评测 2k 样本调用;可换开源 judge 做 sanity +- [TS Encoder 过拟合合成分布] → 成分参数随机化 + 多套合成配置 + 阶段②引入真实改写样本 + +## Open Questions +``` + +Full source: openspec/changes/ts-as-modality/design.md + +## openspec/changes/ts-as-modality/tasks.md + +- Source: openspec/changes/ts-as-modality/tasks.md +- Lines: 1-45 +- SHA256: 8e13037661b54a1579cc1c9c81ff2676aee777ca25303ef54c944ce91e852726 + +```md +# Tasks · ts-as-modality + +> 源自 `docs/superpowers/plans/2026-06-29-ts-as-modality-plan.md`(M1→M5)。 +> 每个里程碑末尾的「出口验证」为该阶段完成判据;建议先跑「冒烟路径」确认端到端通,再放大到全量。 + +## 1. M1 · 数据管线 + +- [ ] 1.1 项目脚手架:创建 `pyproject.toml`(torch/transformers/peft/accelerate/datasets/numpy/tqdm/pyyaml/pytest)、`src/tsmm/` 模块骨架、`configs/`、`scripts/`、`tests/`,并建 `data/`、`checkpoints/` 加 `.gitignore`(验证:`python -c "import tsmm"` 不报错;`pytest tests/` 可跑) +- [ ] 1.2 属性词表与采样 `data/attributes.py`:定义变量名词表/单位/采样率档位,`sample_attributes(n_channels)` 返回结构化属性(验证:单测字段齐全、可复现) +- [ ] 1.3 成分模型与时序合成 `data/synthesis.py`:`generate_series`(趋势+周期+基线+噪声)、`inject_anomaly`(尖刺/水平偏移/方差膨胀/缺失段/缓慢漂移,返回逐点 labels+段元数据)、`couple_event`(t 处阶跃+事件文本)、`add_missing`(NaN 占位)(验证:给定 seed 确定;异常段与 labels 一致;事件处有阶跃) +- [ ] 1.4 指令与回答生成 `data/instruct.py`:6 类指令模板(描述/异常/根因/预测/比较/事件关联)+ Evol-Instruct 演化,`build_instruction` 产 JSON 区间/数值/文本回答(验证:异常类 JSON 可 `json.loads` 且段与 labels 吻合) +- [ ] 1.5 离线生成脚本 `scripts/gen_synthetic.py`:多进程产 `align.jsonl`(50万)/`sft.jsonl`(10万)/`eval_synth.jsonl`(2k held-out),支持 `--n/--out/--seed/--workers` + tqdm(验证:`--n 1000` 跑通,抽样 5 条 schema 合规) +- [ ] 1.6 真实 benchmark 加载 `data/real_bench.py`:加载 SMD/MSL/SMAP/SWaT/PSM(至少 2 个),`load_windows(T=512, stride=256)` 滑窗+归一化+标签,异常段改写问答对存 `eval_real.jsonl`(验证:窗口形状 `[N,T,C]`、标签 `[N,T]`、问答非空) +- [ ] 1.7 M1 出口验证:`gen_synthetic.py --n 1000` 产可视检合法 JSONL;`real_bench.py` 加载 ≥2 数据集;人工抽看 5 条合成样本确认成分/异常/事件正确 + +## 2. M2 · 模型可跑通 + +- [ ] 2.1 TS Encoder `model/ts_encoder.py`:`Patchify(patch=8, stride=4)` 通道独立切 patch 线性嵌入到 d=256;`TSEncoder(d=256, layers=2, heads=4)` 2 层 TF + 可学习位置编码;前向 `[B,T,C]`→`[B,n_patches,256]`(验证:输入 `[2,512,5]`→`[2,128,256]`,参数 ≈4M) +- [ ] 2.2 Projector `model/projector.py`:`Linear(256→896)+LayerNorm`(验证:输出 `[B,128,896]` 对齐 Qwen2.5-0.5B hidden) +- [ ] 2.3 多模态拼接 `model/multimodal.py`:Qwen tokenizer tokenize 文本部分,TS token 作 inputs_embeds 插入 `[属性][时间戳][TS tok][事件][问题]`,统一构造 inputs_embeds+attention_mask+labels(仅回答段非 -100)(验证:seq_len ≤1024,mask/labels 形状对) +- [ ] 2.4 训练/推理封装 `model/wrapper.py`:`MultimodalTSModel` 组合 Encoder+Projector+LLM+LoRA 挂载开关,`forward` 返 loss、`generate` 返文本,支持 `freeze_llm`(阶段①)/`enable_lora(r=16)`(阶段②)(验证:单 batch forward 3060 不 OOM;generate 能出文本) +- [ ] 2.5 Collator `data/collator.py`:JSONL→batch 张量,处理变长 C(padding+mask)与变长文本(padding+attention_mask)(验证:batch=4 张量形状一致无 NaN) +- [ ] 2.6 M2 出口验证:单 batch 前向+反向在 3060 跑通,loss 有限且下降趋势,阶段①模式峰值显存 ~5GB + +## 3. M3 · 阶段①对齐训练 + +- [ ] 3.1 损失函数 `train/losses.py`:`lm_loss`(仅回答段计 loss)、`contrastive_loss`(扰动时序→回答 embedding 变化,InfoNCE/扰动一致性),总 loss=`lm_loss+λ*contrastive_loss`(λ 默认 0.1)(验证:loss 标量可反传,对比损失对扰动敏感) +- [ ] 3.2 阶段①训练脚本 `train/stage1.py`+`scripts/train_stage1.sh`:加载 `align.jsonl` 流式,`freeze_llm=True` 仅训 Encoder+Projector(AdamW, lr=1e-4),bs=8/grad_accum=4/ctx=512/BF16/梯度检查点,每 2000 step 存 ckpt + TensorBoard(验证:`--max_steps 100` 冒烟不 OOM、loss 下降、峰值显存 ≤6GB) +- [ ] 3.3 TS-token 有效性检验:held-out 原时序 vs 扰动时序回答变化率 + 「必看时序」样本答对率对照纯 LLM(验证:扰动后变化率 >50%,必看时序答对率显著高于纯 LLM) +- [ ] 3.4 M3 出口验证:阶段① ckpt 产出;扰动检验通过;峰值显存 ≤6GB(失败回查对比损失权重/数据质量) + +## 4. M4 · 阶段②SFT + +- [ ] 4.1 阶段②训练脚本 `train/stage2.py`+`scripts/train_stage2.sh`:加载阶段① ckpt,`enable_lora(r=16)` on q/v_proj 其余冻结,加载 `sft.jsonl`,bs=4/grad_accum=8/ctx=1024/BF16/梯度检查点,每 2000 step 存含 LoRA ckpt(验证:`--max_steps 100` 冒烟不 OOM、loss 下降、峰值显存 ≤11GB) +- [ ] 4.2 指令遵循抽检:6 类任务各取 10 条 held-out 检查回答(异常类 JSON 可解析+段合理;解释类切题引用事件)(验证:6 类回答可用率 >70%,JSON 解析成功率 >80%) +- [ ] 4.3 M4 出口验证:阶段② ckpt 产出;6 类任务抽检达标;峰值显存 ≤11GB(OOM 则降 bs=2/grad_accum=16、`adamw_8bit`+CPU offload、ctx 降到 768) + +## 5. M5 · 完整评测 + +- [ ] 5.1 回答解析 `eval/parse_answer.py`:文本回答→JSON 异常段→逐点分数 `[T]`,失败→全 0+失败标记(验证:多格式可解析、失败有兜底) +- [ ] 5.2 异常检测指标 `eval/ts_metrics.py`:`tsb_uad` 算 VUS-PR(主),自实现 Affiliation-F1(多 λ)/AUC-PR/Point-F1(无PA),PA-F1 单独对照(验证:已知段算出合理值;trivial 全报异常 VUS-PR 不虚高) +- [ ] 5.3 问答评测 `eval/qa_judge.py`:规则解析轨(JSON/数值容差→准确率)+ LLM-judge 轨(GPT-4o 打 0-5 分),不一致样本导出抽检(验证:对 eval 集产出 6 类任务的 {规则准确率,judge 均分,解析成功率}) +- [ ] 5.4 对照基线 `eval/baselines.py`:纯 LLM 数值喂文本 / Time-LLM 风格重映射 / ChatTS(若可复现) / Trivial(Random/Constant/全报异常),全走同一套 parse+metrics(验证:4 类基线产出同口径指标表) +- [ ] 5.5 评测脚本与报告 `scripts/run_eval.sh`:跑 `eval_synth.jsonl`+`eval_real.jsonl`,产 `reports/eval-YYYYMMDD.md`(含每数据集×每任务全部必报指标、标注是否用 PA、含 trivial 对照)(验证:一键产出满足设计规格 §5.4 必报清单的完整报告) +- [ ] 5.6 M5 出口验证:报告满足设计规格 §6.5 成功标准——真实 benchmark VUS-PR 显著优于纯 LLM 基线;时序消融后指标明显下降;问答均分超基线;评测可复现含 trivial +``` + +## openspec/changes/ts-as-modality/specs/ts-evaluation/spec.md + +- Source: openspec/changes/ts-as-modality/specs/ts-evaluation/spec.md +- Lines: 1-61 +- SHA256: 1c986559a6b44900bff452e4cbbb0272c1ee321de2fddacedc6e096c4e5381fb + +```md +## ADDED Requirements + +### Requirement: 回答解析为逐点分数 + +系统 SHALL 从模型自然语言回答中提取 JSON 异常段并生成逐点分数(段内 1.0,段外 0.0),解析失败时回退为全 0(计为漏报)并记录失败标记。 + +#### Scenario: 多格式可解析 +- **WHEN** 输入含噪声/嵌套的多种回答格式 +- **THEN** 能正确解析出异常段并生成逐点分数 `[T]` + +#### Scenario: 解析失败有兜底 +- **WHEN** 回答无法解析 +- **THEN** 分数全 0 并记录失败标记(不计为成功) + +### Requirement: 阈值无关的异常检测指标 + +系统 SHALL 以 VUS-PR 为异常检测主指标,并辅以 Affiliation-F1(λ=0.1/0.5/1.0)、AUC-PR、Point-F1(无 PA);PA-F1 仅作对照、不得作为主指标。 + +#### Scenario: trivial 基线不虚高 +- **WHEN** 对「全报异常」trivial 基线计算 VUS-PR +- **THEN** VUS-PR 不虚高(避免评估作弊) + +#### Scenario: 对已知段算出合理值 +- **WHEN** 对已知异常段计算指标 +- **THEN** VUS-PR/Aff-F1/AUC-PR/Point-F1 均落在合理区间 + +### Requirement: 问答评测双轨 + +系统 SHALL 提供规则解析轨(JSON/数值容差比对,产准确率)与 LLM-judge 轨(对 `问题,时序摘要,参考答案,模型答案` 打 0-5 分),并对两轨不一致样本导出供人工抽检。 + +#### Scenario: 产出 6 类任务评测结果 +- **WHEN** 对评测集运行问答评测 +- **THEN** 对 6 类任务各产出 `{规则准确率, judge 均分, 解析成功率}` + +### Requirement: 同口径对照基线 + +系统 SHALL 提供 4 类同口径基线——纯 LLM 数值喂文本、Time-LLM 风格重映射、ChatTS(若不可复现则标注)、Trivial(Random/Constant/全报异常)——且全部走同一套解析+指标脚本。 + +#### Scenario: 4 类基线产出同口径指标 +- **WHEN** 运行基线评测 +- **THEN** 4 类基线均在同一套 `parse_answer`+`ts_metrics` 下产出指标表 + +### Requirement: 可复现评测报告 + +系统 SHALL 提供一键评测脚本,产出 markdown 报告,覆盖每数据集×每任务的 VUS-PR/Aff-F1/AUC-PR/Point-F1/PA-F1(对照)/问答分/解析成功率/消融/基线对比,并明确标注是否使用 PA、含 trivial 对照。 + +#### Scenario: 一键产出完整报告 +- **WHEN** 运行 `run_eval.sh` +- **THEN** 产出满足设计规格 §5.4 必报清单的完整 markdown 报告 + +### Requirement: 模态消融与泛化验证 + +系统 SHALL 支持模态消融(去掉事件/属性/时序)与跨数据集泛化验证(如 SMD→MSL/SWaT),以证明时序模态确有贡献并暴露合成→真实差距。 + +#### Scenario: 时序消融指标下降 +- **WHEN** 去掉时序模态后评测 +- **THEN** 关键指标(VUS-PR/问答分)明显低于完整模型,证明时序模态有贡献 + +#### Scenario: 真实 benchmark 显著优于纯 LLM 基线 +- **WHEN** 在真实 benchmark 上对比完整模型与纯 LLM 数值喂文本基线 +- **THEN** VUS-PR 显著优于纯 LLM 基线 +``` + +## openspec/changes/ts-as-modality/specs/ts-multimodal-model/spec.md + +- Source: openspec/changes/ts-as-modality/specs/ts-multimodal-model/spec.md +- Lines: 1-73 +- SHA256: f40631b2e8dac3772f6081623d2175460ca5355a8818d6cb3c28a94f148d56a3 + +```md +## ADDED Requirements + +### Requirement: TS Encoder 把时序编码为 patch 表示 + +系统 SHALL 通过通道独立的 Patchify(P=8, stride=4)将多变量时序切分为重叠 patch,并经 2 层 Transformer 编码器(d=256, 4 头)映射为时序 token 序列。 + +#### Scenario: 形状正确 +- **WHEN** 输入形状 `[B, T=512, C=5]` +- **THEN** 输出形状 `[B, 128, 256]`,且 TS Encoder 参数量约 4M + +#### Scenario: 通道独立 +- **WHEN** 通道数 C 变化(如 C=3 与 C=12) +- **THEN** 编码器仍正常工作(通道独立 patchify,不因 C 增大失配) + +### Requirement: Projector 映射到 LLM 隐藏维 + +系统 SHALL 提供线性投影层(256→896)+ LayerNorm,将 TS 表示映射到 Qwen2.5-0.5B 的隐藏维(896),作为可学习 soft token。 + +#### Scenario: 投影对齐 LLM hidden +- **WHEN** TS Encoder 输出 `[B, 128, 256]` +- **THEN** Projector 输出 `[B, 128, 896]`,与 LLM 隐藏维一致 + +### Requirement: 多模态拼接注入 LLM + +系统 SHALL 按 `[属性][时间戳][TS token][事件][问题]` 顺序组装文本 token 与 TS token,统一构造 `inputs_embeds`(文本走 `get_input_embeddings()`,TS 走 Projector 输出)+ `attention_mask` + `labels`(仅回答段非 -100),并约束总长度。 + +#### Scenario: 拼接长度受限 +- **WHEN** 组装一个样本 +- **THEN** 拼接后序列长度 ≤1024 token + +#### Scenario: 回答段 mask 正确 +- **WHEN** 构造 labels +- **THEN** prompt 段(属性/时序/事件/问题)token 的 label 为 -100,仅回答段非 -100 + +### Requirement: 训练/推理统一封装 + +系统 SHALL 提供统一封装,组合 TS Encoder + Projector + LLM + 可选 LoRA,`forward(batch)` 返回 loss、`generate(batch)` 返回文本,并支持阶段①(冻结 LLM)与阶段②(LoRA r=16 on q/v_proj)两种模式。 + +#### Scenario: 单卡前向反向不 OOM +- **WHEN** 在 3060 12GB 上以阶段①模式跑单 batch 前向+反向 +- **THEN** 不 OOM,loss 为有限值 + +#### Scenario: 可生成文本 +- **WHEN** 调用 `generate(batch)` +- **THEN** 返回文本(训练初期允许内容无意义,但流程通) + +### Requirement: 阶段①对齐预训练 + +系统 SHALL 支持阶段①训练:冻结 LLM 主体,仅训 TS Encoder + Projector(AdamW),上下文 ≤512、BF16、梯度检查点,并对回答段计 LM loss,叠加对比损失(扰动时序→回答应变)以防止 LLM 忽略 TS token。 + +#### Scenario: 冒烟跑通且省显存 +- **WHEN** 以 `--max_steps 100` 冒烟训练 +- **THEN** 不 OOM,loss 呈下降趋势,峰值显存 ≤6GB + +#### Scenario: TS token 被有效利用 +- **WHEN** 训练后对 held-out 样本比较原时序与扰动时序的回答 +- **THEN** 扰动后回答变化率 >50% + +### Requirement: 阶段②指令微调 SFT + +系统 SHALL 支持阶段②训练:加载阶段① checkpoint,叠加 LoRA r=16(q/v_proj)、LLM 其余冻结,上下文 ≤1024、BF16、梯度检查点,对回答段做 SFT LM loss。 + +#### Scenario: 冒烟跑通且压在显存内 +- **WHEN** 以 `--max_steps 100` 冒烟训练 +- **THEN** 不 OOM,loss 下降,峰值显存 ≤11GB + +### Requirement: 分阶段 checkpoint 与断点续训 + +系统 SHALL 为每个阶段独立存放 checkpoint(阶段① = Encoder+Projector;阶段②在此之上叠加 LoRA),支持断点续训(每 2000 step 存 ckpt,JSONL 流式加载支持任意 step 续)。 + +#### Scenario: 分阶段互不污染 +- **WHEN** 加载阶段② checkpoint +- **THEN** 其依赖的阶段① Encoder+Projector 权重与阶段② LoRA 适配器可分别回滚,互不污染 +``` + +## openspec/changes/ts-as-modality/specs/ts-synthesis/spec.md + +- Source: openspec/changes/ts-as-modality/specs/ts-synthesis/spec.md +- Lines: 1-77 +- SHA256: 330043d178e344f1f1e87d1262f25ed33b2216eb6e16f2658d4f29a779d8b60b + +```md +## ADDED Requirements + +### Requirement: 可复现的合成时序生成 + +系统 SHALL 提供 CPU 离线合成数据管线,通过可配置成分模型叠加生成多变量时序,且在给定随机种子下输出完全确定、可复现。 + +#### Scenario: 给定种子输出确定 +- **WHEN** 使用相同 seed 调用 `generate_series(T, C, seed)` 两次 +- **THEN** 两次输出的时序数组逐点相等 + +#### Scenario: 成分叠加覆盖典型形态 +- **WHEN** 生成一条时序 +- **THEN** 该时序由趋势/周期/基线/噪声(含高斯与重尾 Student-t)成分叠加而成,且各成分参数被记录为元数据 + +### Requirement: 异常注入与精确标签 + +系统 SHALL 支持向合成时序注入多类异常,并把异常段位置与逐点标签作为 ground-truth 自动记录,标签与异常位置一致。 + +#### Scenario: 注入异常并记录逐点标签 +- **WHEN** 调用 `inject_anomaly(series, types)` 注入尖刺/水平偏移/方差膨胀/缺失段/缓慢漂移中的任一类 +- **THEN** 返回 `(series, labels)`,其中 labels 为逐点 0/1,且 labels 中值为 1 的点与实际异常区间一致 + +#### Scenario: 异常稀有性兜底 +- **WHEN** 生成用于训练的样本 +- **THEN** 每条样本至少包含 1 类异常,保证异常类指令任务有正样本 + +### Requirement: 事件耦合 + +系统 SHALL 支持在指定时间点注入事件相关的阶跃变化,并生成对应的事件文本描述,以支撑时序+事件联合推理。 + +#### Scenario: 事件注入产生阶跃 +- **WHEN** 调用 `couple_event(series, t, kind)` 在时间 t 注入事件 +- **THEN** 时序在 t 处出现阶跃变化,并返回该事件的文本描述 + +### Requirement: 缺失与不规则采样模拟 + +系统 SHALL 支持随机丢弃部分时序点(用 NaN 占位),以模拟真实采集缺陷。 + +#### Scenario: 按比例丢弃点 +- **WHEN** 调用 `add_missing(series, rate=0.05~0.10)` +- **THEN** 约 5-10% 的点被置为 NaN 占位 + +### Requirement: 属性词表采样 + +系统 SHALL 提供变量名词表(CPU/内存/流量/延迟/温度/请求量等)、单位与采样率档位,并按通道数采样返回结构化属性。 + +#### Scenario: 采样属性字段齐全 +- **WHEN** 调用 `sample_attributes(n_channels)` +- **THEN** 返回长度为 n_channels 的列表,每项含 `name`、`unit`、`freq` 字段,且给定 seed 可复现 + +### Requirement: 多类指令与回答生成 + +系统 SHALL 支持 6 类指令任务(描述/统计、异常检测、根因/解释、预测、比较、事件关联),为每类生成指令,并产出可结构化解析的回答(异常类含 JSON 区间,统计类含数值,解释类含文本)。 + +#### Scenario: 异常类回答可被解析 +- **WHEN** 生成异常检测类的指令与回答 +- **THEN** 回答中的 JSON 可被 `json.loads` 解析,且其异常段与 labels 吻合 + +#### Scenario: 覆盖全部 6 类 +- **WHEN** 运行指令生成 +- **THEN** 6 类任务每类至少各产 1 条样本 + +### Requirement: 离线批量生成 JSONL + +系统 SHALL 提供离线脚本多进程生成 JSONL 数据集,每条记录含 `series`/`attributes`/`timestamps`/`events`/`instruction`/`answer`/`labels`,并支持条数、输出路径、种子、并发数参数。 + +#### Scenario: 小规模生成产出合法 schema +- **WHEN** 运行 `gen_synthetic.py --n 1000` +- **THEN** 抽样 5 条每条均含上述 7 个字段,schema 合规 + +### Requirement: 真实 benchmark 加载与问答改写 + +系统 SHALL 能加载真实多变量时序 benchmark 窗口(至少 SWaT 与 MSL/MSL 系列中的 2 个),做滑窗+归一化+异常标签对齐,并把异常段改写为问答对(仅评测用,不进训练)。 + +#### Scenario: 加载并滑窗 +- **WHEN** 调用 `load_windows(name, T=512, stride=256)` +- **THEN** 返回窗口形状 `[N, T, C]` 与标签形状 `[N, T]`,问答对非空 +``` + diff --git a/openspec/changes/ts-as-modality/.openspec.yaml b/openspec/changes/ts-as-modality/.openspec.yaml new file mode 100644 index 0000000..34f9314 --- /dev/null +++ b/openspec/changes/ts-as-modality/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-driven +created: 2026-06-29 diff --git a/openspec/changes/ts-as-modality/design.md b/openspec/changes/ts-as-modality/design.md new file mode 100644 index 0000000..79a70b8 --- /dev/null +++ b/openspec/changes/ts-as-modality/design.md @@ -0,0 +1,88 @@ +## Context + +本 change 在**单张 3060 12GB 消费级显卡**上做一个可复现的实验性落地:把**多变量时序视为独立模态**,与文本/事件模态联合注入小型 LLM(Qwen2.5-0.5B-Instruct),端到端任务是**时序问答与推理**(ChatTS 路线)。 + +背景与约束来自 `MTSAD-技术深度调研报告.md` 与 `docs/superpowers/specs/2026-06-29-ts-as-modality-design.md`(已通过设计评审)。核心约束: + +- **算力**:单卡 12GB → 骨干 ≤0.5B、依赖 LoRA/QLoRA + 短上下文 + 小批量 + 梯度检查点 +- **数据**:合成数据为主(CPU 离线生成)→ 评测锚定真实 benchmark,防合成过拟合 +- **目标**:不追学术 SOTA,追「12GB 跑通、可复现、时序模态确有增益」的可验证结论 + +## Goals / Non-Goals + +**Goals:** +- 全流程单卡 3060 12GB 跑通,阶段②峰值显存 ≤11GB +- TS Encoder + Projector 把时序编码为独立 soft token,使 LLM「能读懂」时序 +- 时序模态带来可量化增益:真实 benchmark VUS-PR 显著优于纯 LLM 数值喂文本基线;时序消融后指标明显下降 +- 6 类问答任务(描述/异常/根因/预测/比较/事件关联)LLM-judge 均分超纯 LLM 基线 +- 评测可复现:含 trivial 基线对照、标注是否用 PA、严守 MTSAD 报告评估纪律 + +**Non-Goals:** +- ❌ 不从零预训练 LLM(成本不允许,且非本实验目的) +- ❌ 不做多卡分布式训练(单卡约束) +- ❌ 不追求学术 SOTA 排名 +- ❌ 不做端侧部署优化(先验证方法) +- ❌ DPO 首版不做(M5 后视效果再决定) + +## Decisions + +### 决策 1:采用 Patch-Project + 轻量编码器,而非时序 Tokenization 或 Reprogramming + +时序切 patch(P=8, stride=4,通道独立)→ 2 层 Transformer 编码器(d=256, 4 头, ~4M)→ 线性投影(256→896)成独立 TS token,作为可学习 soft token 注入 LLM。 + +**对比的备选方案:** + +| 方案 | 含义 | 取舍 | +|------|------|------| +| **A(选用)Patch-Project + 轻量编码器** | patch→小编码器→线性投影成独立 TS token | 真正的"时序作为模态";12GB 可训;patch 捕捉局部结构、变长友好。代价:需训编码器+投影层(已在显存预算内) | +| B 时序 Tokenization(Chronos 风格) | 数值量化成离散 token、扩展词表 | 最"时序即语言",但量化丢精度、异常细节易损;逐点 token 序列长,12GB 上下文吃紧。放弃 | +| C Reprogramming(Time-LLM 风格) | 冻结 LLM 用文本原型重映射 | 参数最省,但受限于已有文本嵌入流形、表达力弱,时序算不上"真新模态",复杂推理/事件联合弱。放弃 | + +### 决策 2:骨干选 Qwen2.5-0.5B-Instruct + +0.5B 中英均衡、有现成 Instruct 版、社区生态成熟;BF16 约 1GB,12GB 余量充足(hidden=896)。 + +### 决策 3:两阶段训练,阶段①冻结 LLM + +- **阶段① 对齐预训练**:冻结 LLM,仅训 TS Encoder + Projector(~4.2M 全参)→ 不存 LLM 优化器状态/梯度,是 12GB 可行的关键省显存技巧 +- **阶段② SFT**:在此之上叠加 LoRA r=16(q/v_proj,~2-3M),LLM 其余冻结 + 梯度检查点 + +分阶段 checkpoint 互不污染、可回滚。损失仅对回答段 token 计 LM loss;阶段①叠加对比损失(扰动时序→回答应变)防止 LLM 忽略 TS token。 + +### 决策 4:输入拼接顺序 `[属性][时间戳][TS token][事件][问题]` + +属性先给语义,时序居中,事件定位在对应时间,问题在末尾便于回答。 + +### 决策 5:合成数据为主,真实 benchmark 仅用于评测锚定 + +合成管线全 CPU 离线,成分参数随机化;**核心红利**:异常段、事件时间戳、各成分参数全部作为 ground-truth 自动记录——免费且精确的标签。评测锚定 SMD/MSL/SMAP/SWaT/PSM 真实分布,避免「合成上 SOTA、真实上崩盘」。 + +### 决策 6:评测指标以 VUS-PR 为主,严守 MTSAD 报告纪律 + +- 主指标 **VUS-PR**(阈值无关);辅 Affiliation-F1(多 λ)、AUC-PR、Point-F1(无 PA) +- **PA-F1 仅作对照、不得作主指标**(防虚高) +- 问答用 LLM-judge + 规则解析双轨 +- 自然语言回答→约束 JSON 区间→逐点分数,便于数值化评测 + +### 决策 7:4 类同口径基线 + +纯 LLM 数值喂文本(检验 TS 模态是否真有增益)、Time-LLM 风格重映射、ChatTS(若可复现)、Trivial(Random/Constant/全报异常)。全部走同一套解析+指标脚本。 + +## Risks / Trade-offs + +- [12GB 阶段②仍 OOM] → 降批量/上下文、开 CPU offload 优化器、`adamw_8bit`、退回阶段①-only 报告 +- [合成→真实泛化差距大(高风险)] → 阶段②掺真实 benchmark 改写样本;评测以真实 benchmark 为准 +- [LLM 忽略 TS token] → 对比损失 + "必看时序"样本 + 消融实验定位 +- [回答 JSON 解析失败率高] → 训练强化格式约束 + 解析兜底(失败→全 0 计漏报)+ 单独报解析成功率 +- [GPT-4o judge 成本] → 仅评测 2k 样本调用;可换开源 judge 做 sanity +- [TS Encoder 过拟合合成分布] → 成分参数随机化 + 多套合成配置 + 阶段②引入真实改写样本 + +## Open Questions + +- TS Encoder 层数/d 是否需小规模 sweep(2 层是否够) +- Patch P=8/stride=4 是否最优,是否需对比 P=16 +- 对比损失具体形式(InfoNCE vs 扰动一致性)与权重 λ +- DPO 是否纳入首版(建议首版先不做,M5 后视效果决定) +- 真实 benchmark 改写问答的数量与质量校验流程 + +> 详细行为需求见 `specs/ts-synthesis/`、`specs/ts-multimodal-model/`、`specs/ts-evaluation/`;任务拆解见 `tasks.md`(M1→M5)。 diff --git a/openspec/changes/ts-as-modality/proposal.md b/openspec/changes/ts-as-modality/proposal.md new file mode 100644 index 0000000..52af8bb --- /dev/null +++ b/openspec/changes/ts-as-modality/proposal.md @@ -0,0 +1,33 @@ +## Why + +当前 AIOps 场景下,多变量时序的异常检测与解释仍依赖专用模型,缺乏「以自然语言对时序提问、做根因/事件关联推理」的统一能力。基于 `MTSAD-技术深度调研报告.md`,沿用 ChatTS「时序作为新模态」路线,我们希望在**单张 3060 12GB 消费级显卡**上做一个可复现的实验性落地,验证「把多变量时序视为独立模态、与文本/事件模态联合注入小型 LLM」这一方法在算力受限条件下是否切实可行、且「时序模态」是否真带来可量化的增益。现在做是因为:0.5B 级开源 LLM 与 PEFT/LoRA 工具链已足够成熟,使该实验在消费级硬件上首次成为可能。 + +## What Changes + +- **新增**:CPU 离线合成数据管线(成分模型 + 异常注入 + 事件耦合 + Evol-Instruct 指令/回答生成),产出对齐预训练与 SFT 用的 JSONL +- **新增**:真实 benchmark(SMD/MSL/SMAP/SWaT/PSM)窗口加载与「异常段→问答对」改写(仅评测用,不进训练) +- **新增**:TS Encoder(Patchify + 2 层 Transformer)+ Projector(Linear→LLM hidden),把时序编码为独立 soft token +- **新增**:多模态拼接器,按 `[属性][时间戳][TS token][事件][问题]` 顺序组装文本 token 与 TS token 注入 LLM +- **新增**:两阶段训练流程 —— 阶段①冻结 LLM 训 Encoder+Projector(对齐预训练);阶段②叠加 LoRA(r=16) 做指令微调 +- **新增**:评测套件 —— 文本回答→JSON 区间→逐点分数解析;VUS-PR(主)/Affiliation-F1/AUC-PR/Point-F1(无PA);LLM-judge + 规则解析双轨 +- **新增**:4 类同口径对照基线(纯 LLM 数值喂文本 / Time-LLM 风格重映射 / ChatTS(若可复现) / Trivial) +- 骨干选用 **Qwen2.5-0.5B-Instruct**,BF16 + LoRA + 梯度检查点,目标阶段②峰值显存 ≤11GB + +## Capabilities + +### New Capabilities +- `ts-synthesis`: CPU 离线合成数据管线——成分模型(趋势/周期/基线/噪声)、异常注入(尖刺/水平偏移/方差膨胀/缺失段/缓慢漂移)、事件耦合、缺失/不规则模拟、属性词表采样,以及 Evol-Instruct 多轮指令与回答生成;附带真实 benchmark 加载与问答改写 +- `ts-multimodal-model`: 时序作为模态的多模态模型——TS Encoder + Projector + 多模态拼接(TS token 与文本/事件 token 联合注入 LLM),含阶段①对齐预训练与阶段②LoRA SFT 的训练/推理统一封装 +- `ts-evaluation`: 时序问答与异常检测评测套件——回答解析(文本→JSON 区间→逐点分数)、阈值无关指标(VUS-PR 主/Affiliation-F1/AUC-PR/Point-F1 无 PA)、LLM-judge + 规则双轨、4 类同口径基线对照、可复现评测报告 + +### Modified Capabilities + + +## Impact + +- **新增代码**:独立 Python 项目 `ts-as-modality/`(`pyproject.toml` + `src/tsmm/{data,model,train,eval,utils}` + `scripts/` + `tests/` + `configs/`),与当前 spec/docs 工作区并列 +- **依赖**:torch、transformers、peft、accelerate、datasets、numpy、tqdm、pyyaml、pytest;评测依赖 `tsb_uad`(VUS-PR);LLM-judge 评测时调用 OpenAI/GPT-4o API +- **模型资产**:Qwen2.5-0.5B-Instruct 骨干(外部下载);阶段①/② checkpoint 与合成数据产物体积较大,需 git-ignore(`data/`、`checkpoints/`) +- **算力**:单张 3060 12GB;阶段①预估峰值 ~4-5GB,阶段②预估峰值 ~9-10GB;CPU 多进程用于离线合成 +- **存储**:合成数据约 2-3GB(流式加载),checkpoint 分阶段独立存放 +- **无 BREAKING 变更**:纯新增独立实验项目,不触碰现有任何代码/接口 diff --git a/openspec/changes/ts-as-modality/specs/ts-evaluation/spec.md b/openspec/changes/ts-as-modality/specs/ts-evaluation/spec.md new file mode 100644 index 0000000..3e74caf --- /dev/null +++ b/openspec/changes/ts-as-modality/specs/ts-evaluation/spec.md @@ -0,0 +1,61 @@ +## ADDED Requirements + +### Requirement: 回答解析为逐点分数 + +系统 SHALL 从模型自然语言回答中提取 JSON 异常段并生成逐点分数(段内 1.0,段外 0.0),解析失败时回退为全 0(计为漏报)并记录失败标记。 + +#### Scenario: 多格式可解析 +- **WHEN** 输入含噪声/嵌套的多种回答格式 +- **THEN** 能正确解析出异常段并生成逐点分数 `[T]` + +#### Scenario: 解析失败有兜底 +- **WHEN** 回答无法解析 +- **THEN** 分数全 0 并记录失败标记(不计为成功) + +### Requirement: 阈值无关的异常检测指标 + +系统 SHALL 以 VUS-PR 为异常检测主指标,并辅以 Affiliation-F1(λ=0.1/0.5/1.0)、AUC-PR、Point-F1(无 PA);PA-F1 仅作对照、不得作为主指标。 + +#### Scenario: trivial 基线不虚高 +- **WHEN** 对「全报异常」trivial 基线计算 VUS-PR +- **THEN** VUS-PR 不虚高(避免评估作弊) + +#### Scenario: 对已知段算出合理值 +- **WHEN** 对已知异常段计算指标 +- **THEN** VUS-PR/Aff-F1/AUC-PR/Point-F1 均落在合理区间 + +### Requirement: 问答评测双轨 + +系统 SHALL 提供规则解析轨(JSON/数值容差比对,产准确率)与 LLM-judge 轨(对 `问题,时序摘要,参考答案,模型答案` 打 0-5 分),并对两轨不一致样本导出供人工抽检。 + +#### Scenario: 产出 6 类任务评测结果 +- **WHEN** 对评测集运行问答评测 +- **THEN** 对 6 类任务各产出 `{规则准确率, judge 均分, 解析成功率}` + +### Requirement: 同口径对照基线 + +系统 SHALL 提供 4 类同口径基线——纯 LLM 数值喂文本、Time-LLM 风格重映射、ChatTS(若不可复现则标注)、Trivial(Random/Constant/全报异常)——且全部走同一套解析+指标脚本。 + +#### Scenario: 4 类基线产出同口径指标 +- **WHEN** 运行基线评测 +- **THEN** 4 类基线均在同一套 `parse_answer`+`ts_metrics` 下产出指标表 + +### Requirement: 可复现评测报告 + +系统 SHALL 提供一键评测脚本,产出 markdown 报告,覆盖每数据集×每任务的 VUS-PR/Aff-F1/AUC-PR/Point-F1/PA-F1(对照)/问答分/解析成功率/消融/基线对比,并明确标注是否使用 PA、含 trivial 对照。 + +#### Scenario: 一键产出完整报告 +- **WHEN** 运行 `run_eval.sh` +- **THEN** 产出满足设计规格 §5.4 必报清单的完整 markdown 报告 + +### Requirement: 模态消融与泛化验证 + +系统 SHALL 支持模态消融(去掉事件/属性/时序)与跨数据集泛化验证(如 SMD→MSL/SWaT),以证明时序模态确有贡献并暴露合成→真实差距。 + +#### Scenario: 时序消融指标下降 +- **WHEN** 去掉时序模态后评测 +- **THEN** 关键指标(VUS-PR/问答分)明显低于完整模型,证明时序模态有贡献 + +#### Scenario: 真实 benchmark 显著优于纯 LLM 基线 +- **WHEN** 在真实 benchmark 上对比完整模型与纯 LLM 数值喂文本基线 +- **THEN** VUS-PR 显著优于纯 LLM 基线 diff --git a/openspec/changes/ts-as-modality/specs/ts-multimodal-model/spec.md b/openspec/changes/ts-as-modality/specs/ts-multimodal-model/spec.md new file mode 100644 index 0000000..7e23f40 --- /dev/null +++ b/openspec/changes/ts-as-modality/specs/ts-multimodal-model/spec.md @@ -0,0 +1,73 @@ +## ADDED Requirements + +### Requirement: TS Encoder 把时序编码为 patch 表示 + +系统 SHALL 通过通道独立的 Patchify(P=8, stride=4)将多变量时序切分为重叠 patch,并经 2 层 Transformer 编码器(d=256, 4 头)映射为时序 token 序列。 + +#### Scenario: 形状正确 +- **WHEN** 输入形状 `[B, T=512, C=5]` +- **THEN** 输出形状 `[B, 128, 256]`,且 TS Encoder 参数量约 4M + +#### Scenario: 通道独立 +- **WHEN** 通道数 C 变化(如 C=3 与 C=12) +- **THEN** 编码器仍正常工作(通道独立 patchify,不因 C 增大失配) + +### Requirement: Projector 映射到 LLM 隐藏维 + +系统 SHALL 提供线性投影层(256→896)+ LayerNorm,将 TS 表示映射到 Qwen2.5-0.5B 的隐藏维(896),作为可学习 soft token。 + +#### Scenario: 投影对齐 LLM hidden +- **WHEN** TS Encoder 输出 `[B, 128, 256]` +- **THEN** Projector 输出 `[B, 128, 896]`,与 LLM 隐藏维一致 + +### Requirement: 多模态拼接注入 LLM + +系统 SHALL 按 `[属性][时间戳][TS token][事件][问题]` 顺序组装文本 token 与 TS token,统一构造 `inputs_embeds`(文本走 `get_input_embeddings()`,TS 走 Projector 输出)+ `attention_mask` + `labels`(仅回答段非 -100),并约束总长度。 + +#### Scenario: 拼接长度受限 +- **WHEN** 组装一个样本 +- **THEN** 拼接后序列长度 ≤1024 token + +#### Scenario: 回答段 mask 正确 +- **WHEN** 构造 labels +- **THEN** prompt 段(属性/时序/事件/问题)token 的 label 为 -100,仅回答段非 -100 + +### Requirement: 训练/推理统一封装 + +系统 SHALL 提供统一封装,组合 TS Encoder + Projector + LLM + 可选 LoRA,`forward(batch)` 返回 loss、`generate(batch)` 返回文本,并支持阶段①(冻结 LLM)与阶段②(LoRA r=16 on q/v_proj)两种模式。 + +#### Scenario: 单卡前向反向不 OOM +- **WHEN** 在 3060 12GB 上以阶段①模式跑单 batch 前向+反向 +- **THEN** 不 OOM,loss 为有限值 + +#### Scenario: 可生成文本 +- **WHEN** 调用 `generate(batch)` +- **THEN** 返回文本(训练初期允许内容无意义,但流程通) + +### Requirement: 阶段①对齐预训练 + +系统 SHALL 支持阶段①训练:冻结 LLM 主体,仅训 TS Encoder + Projector(AdamW),上下文 ≤512、BF16、梯度检查点,并对回答段计 LM loss,叠加对比损失(扰动时序→回答应变)以防止 LLM 忽略 TS token。 + +#### Scenario: 冒烟跑通且省显存 +- **WHEN** 以 `--max_steps 100` 冒烟训练 +- **THEN** 不 OOM,loss 呈下降趋势,峰值显存 ≤6GB + +#### Scenario: TS token 被有效利用 +- **WHEN** 训练后对 held-out 样本比较原时序与扰动时序的回答 +- **THEN** 扰动后回答变化率 >50% + +### Requirement: 阶段②指令微调 SFT + +系统 SHALL 支持阶段②训练:加载阶段① checkpoint,叠加 LoRA r=16(q/v_proj)、LLM 其余冻结,上下文 ≤1024、BF16、梯度检查点,对回答段做 SFT LM loss。 + +#### Scenario: 冒烟跑通且压在显存内 +- **WHEN** 以 `--max_steps 100` 冒烟训练 +- **THEN** 不 OOM,loss 下降,峰值显存 ≤11GB + +### Requirement: 分阶段 checkpoint 与断点续训 + +系统 SHALL 为每个阶段独立存放 checkpoint(阶段① = Encoder+Projector;阶段②在此之上叠加 LoRA),支持断点续训(每 2000 step 存 ckpt,JSONL 流式加载支持任意 step 续)。 + +#### Scenario: 分阶段互不污染 +- **WHEN** 加载阶段② checkpoint +- **THEN** 其依赖的阶段① Encoder+Projector 权重与阶段② LoRA 适配器可分别回滚,互不污染 diff --git a/openspec/changes/ts-as-modality/specs/ts-synthesis/spec.md b/openspec/changes/ts-as-modality/specs/ts-synthesis/spec.md new file mode 100644 index 0000000..7136337 --- /dev/null +++ b/openspec/changes/ts-as-modality/specs/ts-synthesis/spec.md @@ -0,0 +1,77 @@ +## ADDED Requirements + +### Requirement: 可复现的合成时序生成 + +系统 SHALL 提供 CPU 离线合成数据管线,通过可配置成分模型叠加生成多变量时序,且在给定随机种子下输出完全确定、可复现。 + +#### Scenario: 给定种子输出确定 +- **WHEN** 使用相同 seed 调用 `generate_series(T, C, seed)` 两次 +- **THEN** 两次输出的时序数组逐点相等 + +#### Scenario: 成分叠加覆盖典型形态 +- **WHEN** 生成一条时序 +- **THEN** 该时序由趋势/周期/基线/噪声(含高斯与重尾 Student-t)成分叠加而成,且各成分参数被记录为元数据 + +### Requirement: 异常注入与精确标签 + +系统 SHALL 支持向合成时序注入多类异常,并把异常段位置与逐点标签作为 ground-truth 自动记录,标签与异常位置一致。 + +#### Scenario: 注入异常并记录逐点标签 +- **WHEN** 调用 `inject_anomaly(series, types)` 注入尖刺/水平偏移/方差膨胀/缺失段/缓慢漂移中的任一类 +- **THEN** 返回 `(series, labels)`,其中 labels 为逐点 0/1,且 labels 中值为 1 的点与实际异常区间一致 + +#### Scenario: 异常稀有性兜底 +- **WHEN** 生成用于训练的样本 +- **THEN** 每条样本至少包含 1 类异常,保证异常类指令任务有正样本 + +### Requirement: 事件耦合 + +系统 SHALL 支持在指定时间点注入事件相关的阶跃变化,并生成对应的事件文本描述,以支撑时序+事件联合推理。 + +#### Scenario: 事件注入产生阶跃 +- **WHEN** 调用 `couple_event(series, t, kind)` 在时间 t 注入事件 +- **THEN** 时序在 t 处出现阶跃变化,并返回该事件的文本描述 + +### Requirement: 缺失与不规则采样模拟 + +系统 SHALL 支持随机丢弃部分时序点(用 NaN 占位),以模拟真实采集缺陷。 + +#### Scenario: 按比例丢弃点 +- **WHEN** 调用 `add_missing(series, rate=0.05~0.10)` +- **THEN** 约 5-10% 的点被置为 NaN 占位 + +### Requirement: 属性词表采样 + +系统 SHALL 提供变量名词表(CPU/内存/流量/延迟/温度/请求量等)、单位与采样率档位,并按通道数采样返回结构化属性。 + +#### Scenario: 采样属性字段齐全 +- **WHEN** 调用 `sample_attributes(n_channels)` +- **THEN** 返回长度为 n_channels 的列表,每项含 `name`、`unit`、`freq` 字段,且给定 seed 可复现 + +### Requirement: 多类指令与回答生成 + +系统 SHALL 支持 6 类指令任务(描述/统计、异常检测、根因/解释、预测、比较、事件关联),为每类生成指令,并产出可结构化解析的回答(异常类含 JSON 区间,统计类含数值,解释类含文本)。 + +#### Scenario: 异常类回答可被解析 +- **WHEN** 生成异常检测类的指令与回答 +- **THEN** 回答中的 JSON 可被 `json.loads` 解析,且其异常段与 labels 吻合 + +#### Scenario: 覆盖全部 6 类 +- **WHEN** 运行指令生成 +- **THEN** 6 类任务每类至少各产 1 条样本 + +### Requirement: 离线批量生成 JSONL + +系统 SHALL 提供离线脚本多进程生成 JSONL 数据集,每条记录含 `series`/`attributes`/`timestamps`/`events`/`instruction`/`answer`/`labels`,并支持条数、输出路径、种子、并发数参数。 + +#### Scenario: 小规模生成产出合法 schema +- **WHEN** 运行 `gen_synthetic.py --n 1000` +- **THEN** 抽样 5 条每条均含上述 7 个字段,schema 合规 + +### Requirement: 真实 benchmark 加载与问答改写 + +系统 SHALL 能加载真实多变量时序 benchmark 窗口(至少 SWaT 与 MSL/MSL 系列中的 2 个),做滑窗+归一化+异常标签对齐,并把异常段改写为问答对(仅评测用,不进训练)。 + +#### Scenario: 加载并滑窗 +- **WHEN** 调用 `load_windows(name, T=512, stride=256)` +- **THEN** 返回窗口形状 `[N, T, C]` 与标签形状 `[N, T]`,问答对非空 diff --git a/openspec/changes/ts-as-modality/tasks.md b/openspec/changes/ts-as-modality/tasks.md new file mode 100644 index 0000000..975a111 --- /dev/null +++ b/openspec/changes/ts-as-modality/tasks.md @@ -0,0 +1,45 @@ +# Tasks · ts-as-modality + +> 源自 `docs/superpowers/plans/2026-06-29-ts-as-modality-plan.md`(M1→M5)。 +> 每个里程碑末尾的「出口验证」为该阶段完成判据;建议先跑「冒烟路径」确认端到端通,再放大到全量。 + +## 1. M1 · 数据管线 + +- [ ] 1.1 项目脚手架:创建 `pyproject.toml`(torch/transformers/peft/accelerate/datasets/numpy/tqdm/pyyaml/pytest)、`src/tsmm/` 模块骨架、`configs/`、`scripts/`、`tests/`,并建 `data/`、`checkpoints/` 加 `.gitignore`(验证:`python -c "import tsmm"` 不报错;`pytest tests/` 可跑) +- [ ] 1.2 属性词表与采样 `data/attributes.py`:定义变量名词表/单位/采样率档位,`sample_attributes(n_channels)` 返回结构化属性(验证:单测字段齐全、可复现) +- [ ] 1.3 成分模型与时序合成 `data/synthesis.py`:`generate_series`(趋势+周期+基线+噪声)、`inject_anomaly`(尖刺/水平偏移/方差膨胀/缺失段/缓慢漂移,返回逐点 labels+段元数据)、`couple_event`(t 处阶跃+事件文本)、`add_missing`(NaN 占位)(验证:给定 seed 确定;异常段与 labels 一致;事件处有阶跃) +- [ ] 1.4 指令与回答生成 `data/instruct.py`:6 类指令模板(描述/异常/根因/预测/比较/事件关联)+ Evol-Instruct 演化,`build_instruction` 产 JSON 区间/数值/文本回答(验证:异常类 JSON 可 `json.loads` 且段与 labels 吻合) +- [ ] 1.5 离线生成脚本 `scripts/gen_synthetic.py`:多进程产 `align.jsonl`(50万)/`sft.jsonl`(10万)/`eval_synth.jsonl`(2k held-out),支持 `--n/--out/--seed/--workers` + tqdm(验证:`--n 1000` 跑通,抽样 5 条 schema 合规) +- [ ] 1.6 真实 benchmark 加载 `data/real_bench.py`:加载 SMD/MSL/SMAP/SWaT/PSM(至少 2 个),`load_windows(T=512, stride=256)` 滑窗+归一化+标签,异常段改写问答对存 `eval_real.jsonl`(验证:窗口形状 `[N,T,C]`、标签 `[N,T]`、问答非空) +- [ ] 1.7 M1 出口验证:`gen_synthetic.py --n 1000` 产可视检合法 JSONL;`real_bench.py` 加载 ≥2 数据集;人工抽看 5 条合成样本确认成分/异常/事件正确 + +## 2. M2 · 模型可跑通 + +- [ ] 2.1 TS Encoder `model/ts_encoder.py`:`Patchify(patch=8, stride=4)` 通道独立切 patch 线性嵌入到 d=256;`TSEncoder(d=256, layers=2, heads=4)` 2 层 TF + 可学习位置编码;前向 `[B,T,C]`→`[B,n_patches,256]`(验证:输入 `[2,512,5]`→`[2,128,256]`,参数 ≈4M) +- [ ] 2.2 Projector `model/projector.py`:`Linear(256→896)+LayerNorm`(验证:输出 `[B,128,896]` 对齐 Qwen2.5-0.5B hidden) +- [ ] 2.3 多模态拼接 `model/multimodal.py`:Qwen tokenizer tokenize 文本部分,TS token 作 inputs_embeds 插入 `[属性][时间戳][TS tok][事件][问题]`,统一构造 inputs_embeds+attention_mask+labels(仅回答段非 -100)(验证:seq_len ≤1024,mask/labels 形状对) +- [ ] 2.4 训练/推理封装 `model/wrapper.py`:`MultimodalTSModel` 组合 Encoder+Projector+LLM+LoRA 挂载开关,`forward` 返 loss、`generate` 返文本,支持 `freeze_llm`(阶段①)/`enable_lora(r=16)`(阶段②)(验证:单 batch forward 3060 不 OOM;generate 能出文本) +- [ ] 2.5 Collator `data/collator.py`:JSONL→batch 张量,处理变长 C(padding+mask)与变长文本(padding+attention_mask)(验证:batch=4 张量形状一致无 NaN) +- [ ] 2.6 M2 出口验证:单 batch 前向+反向在 3060 跑通,loss 有限且下降趋势,阶段①模式峰值显存 ~5GB + +## 3. M3 · 阶段①对齐训练 + +- [ ] 3.1 损失函数 `train/losses.py`:`lm_loss`(仅回答段计 loss)、`contrastive_loss`(扰动时序→回答 embedding 变化,InfoNCE/扰动一致性),总 loss=`lm_loss+λ*contrastive_loss`(λ 默认 0.1)(验证:loss 标量可反传,对比损失对扰动敏感) +- [ ] 3.2 阶段①训练脚本 `train/stage1.py`+`scripts/train_stage1.sh`:加载 `align.jsonl` 流式,`freeze_llm=True` 仅训 Encoder+Projector(AdamW, lr=1e-4),bs=8/grad_accum=4/ctx=512/BF16/梯度检查点,每 2000 step 存 ckpt + TensorBoard(验证:`--max_steps 100` 冒烟不 OOM、loss 下降、峰值显存 ≤6GB) +- [ ] 3.3 TS-token 有效性检验:held-out 原时序 vs 扰动时序回答变化率 + 「必看时序」样本答对率对照纯 LLM(验证:扰动后变化率 >50%,必看时序答对率显著高于纯 LLM) +- [ ] 3.4 M3 出口验证:阶段① ckpt 产出;扰动检验通过;峰值显存 ≤6GB(失败回查对比损失权重/数据质量) + +## 4. M4 · 阶段②SFT + +- [ ] 4.1 阶段②训练脚本 `train/stage2.py`+`scripts/train_stage2.sh`:加载阶段① ckpt,`enable_lora(r=16)` on q/v_proj 其余冻结,加载 `sft.jsonl`,bs=4/grad_accum=8/ctx=1024/BF16/梯度检查点,每 2000 step 存含 LoRA ckpt(验证:`--max_steps 100` 冒烟不 OOM、loss 下降、峰值显存 ≤11GB) +- [ ] 4.2 指令遵循抽检:6 类任务各取 10 条 held-out 检查回答(异常类 JSON 可解析+段合理;解释类切题引用事件)(验证:6 类回答可用率 >70%,JSON 解析成功率 >80%) +- [ ] 4.3 M4 出口验证:阶段② ckpt 产出;6 类任务抽检达标;峰值显存 ≤11GB(OOM 则降 bs=2/grad_accum=16、`adamw_8bit`+CPU offload、ctx 降到 768) + +## 5. M5 · 完整评测 + +- [ ] 5.1 回答解析 `eval/parse_answer.py`:文本回答→JSON 异常段→逐点分数 `[T]`,失败→全 0+失败标记(验证:多格式可解析、失败有兜底) +- [ ] 5.2 异常检测指标 `eval/ts_metrics.py`:`tsb_uad` 算 VUS-PR(主),自实现 Affiliation-F1(多 λ)/AUC-PR/Point-F1(无PA),PA-F1 单独对照(验证:已知段算出合理值;trivial 全报异常 VUS-PR 不虚高) +- [ ] 5.3 问答评测 `eval/qa_judge.py`:规则解析轨(JSON/数值容差→准确率)+ LLM-judge 轨(GPT-4o 打 0-5 分),不一致样本导出抽检(验证:对 eval 集产出 6 类任务的 {规则准确率,judge 均分,解析成功率}) +- [ ] 5.4 对照基线 `eval/baselines.py`:纯 LLM 数值喂文本 / Time-LLM 风格重映射 / ChatTS(若可复现) / Trivial(Random/Constant/全报异常),全走同一套 parse+metrics(验证:4 类基线产出同口径指标表) +- [ ] 5.5 评测脚本与报告 `scripts/run_eval.sh`:跑 `eval_synth.jsonl`+`eval_real.jsonl`,产 `reports/eval-YYYYMMDD.md`(含每数据集×每任务全部必报指标、标注是否用 PA、含 trivial 对照)(验证:一键产出满足设计规格 §5.4 必报清单的完整报告) +- [ ] 5.6 M5 出口验证:报告满足设计规格 §6.5 成功标准——真实 benchmark VUS-PR 显著优于纯 LLM 基线;时序消融后指标明显下降;问答均分超基线;评测可复现含 trivial