Commit 62798505 62798505abed640f87daa52865a41597e4ccf1be by cnb.bofCdSsphPA

parameterize dual-axis hard-case weighting for low-risk experiments\n\nConstrain…

…t: Keep the training pipeline behavior stable while exposing humming_like and confused controls through config only\nRejected: Add a brand-new sampler framework first | The smallest useful step is config-driven control on the existing dataset weighting path\nConfidence: high\nScope-risk: narrow\nDirective: Run weight-search experiments through training.sample_type_weights and training.pair_type_weights before attempting broader training-stack refactors\nTested: py_compile passed, train.py dry-run on synthetic_v2 passed, and custom SongPairDataset weighting instantiation produced expected hard_weight output\nNot-tested: End-to-end retraining and metric improvements from new dual-axis weight combinations
1 parent 7812b589
......@@ -74,21 +74,22 @@
## 5.5 最新真实 FMA / chromaprint 运行态(2026-06-02)
### 当前最新快照(15:46 UTC)
- 远程同步基线:`93dfa15`(更新前)
- 当前最重要的新证据:**`v5` 与 `v6` 的 hard-case 差异来源已经被解释清楚**
- `v5` = `type-aware hard-case weighting`
- `humming_like top1=0.50`
- `confused top1=0.00`
- `v6` = `sample-level confused-priority weighting`
- `humming_like top1=0.25`
- `confused top1=0.25`
- 这说明:下一轮最值得做的不是继续盲 sweep,而是设计 `humming_like``confused` 分开控制的双轴策略。
### 当前最新快照(15:47 UTC)
- 远程同步基线:`7812b58`(更新前)
- 当前最重要的新证据:**dual-axis hard-case weighting 已在代码中参数化**
- 当前可调入口:
- `training.sample_type_weights`
- `training.pair_type_weights`
- fresh verification:
- `py_compile` 通过
- `train.py --dry-run` 通过
- 自定义权重实例化检查通过
- 这说明:下一轮已经可以直接做权重搜索实验,而不需要再先改数据集/训练框架结构。
- 下一次值得提交的事件:
1. 双轴 hard-case weighting / sampling 方案落地
2. 其对 `v6` 的 hard-case 指标改善
3. dual-track 回归结果稳定
1. 首轮 dual-axis 权重实验结果
2. `humming_like` 改善且 `confused` 不回退的组合
3. dual-track 回归验证结果
## 6. 高风险注意事项
......
......@@ -31,6 +31,15 @@ training:
gradient_clip: 1.0
save_every: 10
log_every: 10
sample_type_weights:
default: 1
humming_like: 3
confused: 5
pair_type_weights:
default: 1.0
augmented: 1.4
humming_like: 2.5
confused: 4.0
engine:
chromaprint:
......
......@@ -331,6 +331,8 @@ class SongPairDataset(Dataset):
augment: bool = True,
segment_strategy: str = "random",
silence_top_db: int = 30,
sample_type_weights: Optional[Dict[str, int]] = None,
pair_type_weights: Optional[Dict[str, float]] = None,
):
self.sr = sr
self.n_mels = n_mels
......@@ -342,6 +344,19 @@ class SongPairDataset(Dataset):
self.silence_top_db = silence_top_db
self.data_dir = Path(data_dir)
self.asset_root = self.data_dir.parent if self.data_dir.name == "manifests" else self.data_dir
self.sample_type_weights = {
"default": 1,
"humming_like": 3,
"confused": 5,
**(sample_type_weights or {}),
}
self.pair_type_weights = {
"default": 1.0,
"augmented": 1.4,
"humming_like": 2.5,
"confused": 4.0,
**(pair_type_weights or {}),
}
with open(self.data_dir / f"{split}.json") as f:
metadata = json.load(f)
......@@ -358,12 +373,9 @@ class SongPairDataset(Dataset):
self.sample_song_ids = []
for sid, items in self.by_song.items():
item_types = {x.get("type") for x in items}
if "confused" in item_types:
weight = 5
elif "humming_like" in item_types:
weight = 3
else:
weight = 1
weight = self.sample_type_weights.get("default", 1)
for item_type in item_types:
weight = max(weight, int(self.sample_type_weights.get(item_type, weight)))
self.sample_song_ids.extend([sid] * weight)
self.song_to_idx = {sid: i for i, sid in enumerate(self.song_ids)}
......@@ -432,14 +444,9 @@ class SongPairDataset(Dataset):
else:
a, b = random.sample(choices, 2)
type_to_weight = {
"confused": 4.0,
"humming_like": 2.5,
"augmented": 1.4,
}
pair_weights = [
type_to_weight.get(a.get("type", "unknown"), 1.0),
type_to_weight.get(b.get("type", "unknown"), 1.0),
self.pair_type_weights.get(a.get("type", "unknown"), self.pair_type_weights.get("default", 1.0)),
self.pair_type_weights.get(b.get("type", "unknown"), self.pair_type_weights.get("default", 1.0)),
]
wavs = []
......
......@@ -157,6 +157,8 @@ def main():
augment=True,
segment_strategy=args.segment_strategy,
silence_top_db=args.silence_top_db,
sample_type_weights=cfg["training"].get("sample_type_weights"),
pair_type_weights=cfg["training"].get("pair_type_weights"),
)
catalog_dataset = ACRDataset(
......
## 2026-06-02 15:47 UTC / dual-axis hard-case weighting is now configurable in code
- 已把 `SongPairDataset` 中的 hard-case 采样权重与 pair loss 权重从硬编码改为配置驱动
- 代码变更:
- `src/data/dataset.py`:新增 `sample_type_weights` / `pair_type_weights` 参数
- `train.py`:从 `cfg["training"]` 透传上述配置
- `configs/default.yaml`:新增默认 dual-axis hard-case 权重配置
- fresh verification:
- `python -m py_compile train.py src/data/dataset.py` 通过
- `train.py --data data/synthetic_v2 --device cpu --epochs 1 --batch-size 4 --dry-run` 通过
- 自定义权重实例化检查通过:
- `dataset_len=96`
- `unique_songs=16`
- `sample_multiplicity_minmax=6/6`
- 示例 `hard_weight=[5.0, 1.0]`
- 结论:下一轮可直接在不改代码结构的前提下,实验 `humming_like` / `confused` 的双轴 weighting 组合
## 2026-06-02 15:46 UTC / v5-v6 hard-case difference is now causally explained
- 基于仓库内历史实验记录,补齐了 `v5``v6` hard-case 表现差异的来源解释
......
......@@ -272,3 +272,28 @@
- 现在已经不仅知道 `v5/v6` 哪个更强,还知道“为什么”。
- 下一轮应把 `humming_like``confused` 分开建模或分开加权。
## 本次追加交付(2026-06-02 15:47 UTC)
### 新增代码能力
| 文件 | 变更 |
|---|---|
| [../acr-engine/src/data/dataset.py](../acr-engine/src/data/dataset.py) | hard-case 采样权重与 pair 权重改为配置驱动 |
| [../acr-engine/train.py](../acr-engine/train.py) | 训练链路透传 dual-axis 权重配置 |
| [../acr-engine/configs/default.yaml](../acr-engine/configs/default.yaml) | 增加 `sample_type_weights` / `pair_type_weights` 默认配置 |
### 当前最重要的 fresh evidence
- `python -m py_compile train.py src/data/dataset.py`:通过
- `train.py --data data/synthetic_v2 --device cpu --epochs 1 --batch-size 4 --dry-run`:通过
- 自定义权重实例化检查:
- `dataset_len=96`
- `unique_songs=16`
- `sample_multiplicity_minmax=6/6`
- `hard_weight=[5.0, 1.0]`
### 结论
- dual-axis hard-case weighting 已从“设计建议”升级为“代码中可直接调参实验”的状态。
- 下一轮可直接围绕 `sample_type_weights``pair_type_weights` 做最小实验。
......
## 本次交付包追加更新(2026-06-02 15:47 UTC)
### 交付结论
当前最新里程碑已经从“知道该做 dual-axis”推进到 **dual-axis hard-case weighting 已在代码中参数化**
- 远程基线当前为:`7812b58`(更新前)
- `sample_type_weights``pair_type_weights` 已可配置
- 训练 dry-run 已通过
- 因此下一轮可直接做最小调参实验,而不是再先改代码结构
### 当前最新事实
#### 代码实现位置
- `src/data/dataset.py`
- `sample_type_weights` 控制 song-level 采样重复度
- `pair_type_weights` 控制 pair-level `hard_weight`
- `train.py`:从 `training` 配置透传
- `configs/default.yaml`:提供默认 dual-axis 配置
#### fresh verification
- `python -m py_compile train.py src/data/dataset.py`:通过
- `train.py --data data/synthetic_v2 --device cpu --epochs 1 --batch-size 4 --dry-run`:通过
- 自定义权重实例化检查:
- `dataset_len=96`
- `sample_multiplicity_minmax=6/6`
- `hard_weight=[5.0, 1.0]`
### 当前判断
- 现在已经具备一个最小、低风险、可反复实验的 dual-axis 入口。
- 下一阶段最值得做的是直接搜索 `humming_like` / `confused` 的权重组合,而不是继续做只读分析。
---
## 本次交付包追加更新(2026-06-02 15:46 UTC)
### 交付结论
......
......@@ -5,24 +5,22 @@
## 一页结论
### 最新交付快照(2026-06-02 15:46 UTC)
- 当前远程同步基线:`93dfa15`(更新前)
- 当前最重要的新事实:**`v5` 与 `v6` 的 hard-case 差异来源已经被解释清楚**
- `v5``type-aware hard-case weighting`
- `humming_like top1=0.50`
- `confused top1=0.00`
- `v6``sample-level confused-priority weighting`
- `humming_like top1=0.25`
- `confused top1=0.25`
- 结论:
- `v5` 更偏向提升 `humming_like`
- `v6` 更偏向提升 `confused`
- 下一轮应设计双轴 hard-case weighting / 分治策略,而不是继续单轴加权
### 最新交付快照(2026-06-02 15:47 UTC)
- 当前远程同步基线:`7812b58`(更新前)
- 当前最重要的新事实:**dual-axis hard-case weighting 已在代码中参数化**
- 新增可调入口:
- `training.sample_type_weights`
- `training.pair_type_weights`
- fresh verification:
- `py_compile` 通过
- `train.py --dry-run` 通过
- 自定义权重实例化检查通过
- 结论:下一轮不需要先改代码结构,已经可以直接做最小调参实验。
- 新 session 第一优先级:
1. 设计 `humming_like` / `confused` 分开控制的 weighting 或 sampling
2. 复用现有 `v6` 主基线做最小改动实验
3. 用 real-path clean + synthetic hard-case 双轨回归
1. `v6` 主基线上搜索 dual-axis 权重组合
2. 目标优先提升 `humming_like top1`,同时不丢掉 `confused top1`
3. 用 real-path clean + synthetic hard-case 双轨复测
### 最新可观测性修复(2026-06-02 15:18 UTC)
......