数据清洗胜过 5× 堆量:simedw 的数据哲学
simedw 试过 5 倍数据,模型反而更差。回到清洗,最后好了一截。
5× 堆量为什么失败
直觉:数据多 = 模型好。
simedw 试过:把原始数据集从 60 万 MIDI 文件扩到 300 万。
结果:
- 验证 loss:略升(更多噪声分布)
- rollout 质量:明显变差(更频繁卡在重复 loop)
- 训练时间:5 倍
直觉错的地方:MIDI 文件池里有大量多轨病理混录、游戏配乐、练习 demo、教学片段。这些不是「钢琴主导」的 MIDI。把它们加进训练集,等于把噪声加进钢琴分布。
simedw 的清洗流水线
按顺序跑 5 步:
- 钢琴主导筛选:每个 MIDI 文件跑音色识别,留 piano track 占比 > 80% 的。
- 多轨病理砍掉:同时有 > 4 个 track 的录音通常是大混录,砍。
- 维度筛选:按密度(每分钟 note 数)、音域(最低音到最高音跨度)、时间覆盖(10 秒 vs 10 分钟)筛。
- 指纹去重:忽略全局移调(+12 / -12 半音视为同一首)+ 等比 tempo(1.5x / 0.5x tempo 视为同一首),算哈希去重。
- 同曲不同版本归到同一 split:避免一首练习曲的 5 个版本分别进 train / test 造成数据泄漏。
第 4 步特别值得展开——「同一首曲子升 12 半音」在 MIDI 文件里是常见做法(不同乐器适配不同音域)。如果不去重,模型会学到「一首曲子有 5 个版本」这种虚假的多样性。
维度筛选的具体阈值
- 密度:每分钟 30-300 个 note 事件。太稀疏(环境音乐)丢掉,太密集(鼓机 pattern)丢掉。
- 音域:A0-C8 范围内。超出钢琴音域的 MIDI 几乎都是合成器 / 鼓机。
- 时间覆盖:30 秒 - 15 分钟。短于 30 秒太碎,长于 15 分钟是交响乐总谱。
指纹去重的几何
忽略全局移调:把每个 MIDI 的所有音高减去中位数音高,得到相对音高序列。 等比 tempo:把每个 MIDI 的 onset 时间归一化到总时长 1。
两个归一化后的序列算编辑距离(Levenshtein 变种),低于阈值视为同一首。
这一步把训练集的「同曲不同版本」从 12% 砍到 0.3%。
清洗后训练的效果
- 训练集:60 万 MIDI → 18 万高质量 MIDI。
- 验证 loss:略降(更纯净分布)。
- rollout 质量:明显变好(少重复 loop,多音乐性)。
- 训练时间:3 倍(不是 5 倍,因为训练集小了)。
从 5× 数据变差,到 0.3× 数据变好,杠杆全部在清洗质量。
一人工程的清洗哲学
OpenAI 的方法是「人海标注 + 数据工厂」:几千标注员写规则,几百人标注,几亿条数据。规模到极致,质量由人海保证。
simedw 的方法是「一个人写清洗流水线 + 算法去重」:他一个人写 5 步流水线 + 指纹去重算法 + 维度阈值。质量由算法保证,规模靠清洗换。
一个人 + 一台机器 + 5 步清洗流水线,能达到 OpenAI 数据工厂 80% 的质量,10% 的成本。
清洗胜过堆量的更深意义
「堆量」是算力时代的默认答案——更多 GPU = 更多数据 = 更好模型。
simedw 的清洗反着走:更少但更纯净的数据 = 更好模型。
这不是「聪明地少」的中二姿态,是数学事实:
- 训练集 D_train,期望损失 E_loss ∝ |D_clean| / σ²(D_clean) + 常数(噪声方差)
- 5× 数据但 σ² 也涨 5× → E_loss 不变或更差
- 0.3× 数据但 σ² 砍到 0.05 → E_loss 降到 30%
清洗把 σ² 砍下去,杠杆远大于把 |D| 涨上去。
一人工程的可持续性
simedw 一个人写清洗流水线,能跑一遍 60 万 MIDI → 18 万。OpenAI 100+ 数据工程师写工厂,能跑一遍 10 亿文档 → 5 亿。一个人 vs 100 人的规模差是 100×,质量差是 20%。
一人工程的数据清洗不是「OpenAI 的弱化版」,是「一人 + 算法的独立版本」。
14 次实验里数据的位置
simedw 的 14 次实验,第 0 次(实验前)就是数据准备:60 万 MIDI 跑 5 步清洗 → 18 万高质量。后面 13 次实验都在这 18 万上跑。
数据是地基。地基不在,13 次实验都是空中楼阁。
simedw 的「5× 失败」是第 0 次实验的失败——地基没打对,楼上盖得再高也没用。
签名
solus opus。