3. 扫描结果的数据结构与组织
多维参数扫描结束后,我们手里往往是一堆“散装”的结果:每个参数组合对应一个输出值,可能还附带若干中间量、时间戳、版本号。如果这些结果只是零散地打印在日志里,或者以无结构的文本堆叠,后续的可视化就无从下手。本节要解决的核心问题,是把“参数组合 → 结果”这一映射关系,组织成规整、可索引、可扩展的结构化数据,让可视化层能够按任意维度切片、聚合和对比。
先明确三个基本概念。维度(dimension)是扫描中独立变化的参数轴,例如学习率、批大小、网络层数;每个维度有若干取值,所有维度取值的笛卡尔积构成扫描空间。度量(measure)是在每个参数组合上观测到的数值结果,例如准确率、推理延迟、损失值;度量是可视化的“高度”或“颜色”。元数据(metadata)则是描述这次扫描本身的附属信息,例如扫描时间、代码版本、随机种子、硬件型号、参数单位。三者混在一起存储,是后续分析混乱的根源;分开组织,才能让可视化代码只关心“维度怎么切、度量怎么画”。
从“长表”开始:最通用的组织形态
最直接也最通用的结构是长表(long format):每一行对应一个参数组合的一次观测,列包括各维度字段、度量字段和必要的元数据字段。以一次三参数扫描为例,假设学习率取 {0.001, 0.01, 0.1},批大小取 {32, 64},层数取 {4, 8},共 3×2×2=12 个组合,每个组合重复 3 次取平均。长表大致如下:
| lr | batch | layers | repeat | accuracy | latency_ms | run_id |
|---|---|---|---|---|---|---|
| 0.001 | 32 | 4 | 1 | 0.812 | 18.4 | r001 |
| 0.001 | 32 | 4 | 2 | 0.809 | 18.1 | r001 |
| 0.001 | 32 | 4 | 3 | 0.815 | 18.6 | r001 |
| 0.01 | 64 | 8 | 1 | 0.887 | 41.2 | r001 |
| … | … | … | … | … | … | … |
长表的优点是“一行一观测”,天然适合追加写入、按条件过滤和分组聚合。重复实验用 repeat 列区分,而不是把三次结果塞进三个列名,这样重复次数变化时表结构不变。缺点是同一组合的多行存在冗余维度值,存储上略浪费,但换来的是查询和透视的极大灵活性。实际工程中,长表通常作为“事实表”落盘为 CSV 或 Parquet,再由分析脚本透视成宽表或直接喂给绘图库。
多维数组:适合稠密网格与快速切片
当所有维度都是离散且取值规整的网格时,多维数组是更紧凑的选择。把维度按固定顺序排列,例如 (lr, batch, layers),则度量可以存成一个形状为 (3, 2, 2) 的三维数组,数组下标与维度取值一一对应。此时需要额外维护一份“轴标签”映射,例如 axis0 = [0.001, 0.01, 0.1],否则数组本身无法自解释。多维数组的优势在于切片极快:取某一层数下的所有学习率与批大小组合,就是一次简单的索引操作;热力图、切片矩阵图可以直接消费这种结构。代价是它要求网格完整——若某个组合缺失或取值不规则,就得用哨兵值填充,容易与真实度量混淆。
数据库与索引:让“按维度切片”成为一次查询
当扫描规模上升到数千甚至数万组合、且需要反复按不同维度组合查询时,把长表放进关系型或列式数据库更合适。典型做法是建一张事实表,维度字段和度量字段各占一列,并在常用过滤维度上建索引或分区。例如按 run_id 分区、在 (lr, batch) 上建复合索引,那么“取批大小为 64 的所有记录画学习率-准确率曲线”就是一次带 WHERE 的查询,而不是全表扫描。列式存储(如 Parquet)对“只读少数度量列”的聚合尤其友好,因为同列数据连续存放,压缩率高、扫描量小。这里的关键设计决策是:把维度、度量、元数据分列存放,而不是把整个参数组合序列化成一个字符串塞进单列——后者会让任何按维度过滤的查询退化为字符串解析。
组织时容易踩的坑
- 维度取值类型不一致。学习率写成字符串 "0.01" 与数值 0.01 混存,排序和坐标轴刻度就会错乱。落盘前统一类型,并在元数据中记录单位。
- 缺失组合没有显式标记。网格中某组合因失败未产出结果时,用 NaN 或专门的 status 字段标记,而不是留空行——空行在透视时会被静默丢弃,导致热力图出现“假空洞”。
- 重复实验的聚合口径不明。三次重复是取均值、中位数还是保留全部?应在元数据中写明聚合方式,长表保留原始重复行,宽表再按声明口径聚合,避免“同一张图两种口径”。
- 元数据散落在文件名里。把版本号、种子写进文件名(如 run_r001_seed42.csv)看似省事,但无法被查询和关联。应作为列或独立元数据表存储。
把上述结构落地后,可视化阶段的工作会变得非常轻:热力图取两个维度做透视、折线图固定其余维度取切片、平行坐标直接消费长表的维度列与度量列。数据结构规整,图才能规整;这一步做扎实,后面所有图形都只是对同一份结构化数据的不同的“看的方式”。