同名的 CSV 和昨天不一样
目标
给训练数据打上指纹作为版本,用声明了什么是正常的契约来检查新收集的数据,并测量当训练和评估的划分发生重叠时,指标实际上会动多少。
为什么重要
复现被破坏的地方,大多不是代码,而是数据。train.csv 这个名字没有变,里面的行变了也没有任何警告,只有指标稍微不同。所以要给数据贴上 内容哈希 作为版本,提前声明正常范围,再用机器去核对新收集的数据。把违反契约的行隔离起来,而不是悄悄丢掉,也是同样的理由——悄悄减少的样本,几个月后会变成“为什么性能下降了”。
最后两步用实测打破一个常见的误解。看起来有泄漏的话指标会明显升高,但在记忆力弱的模型里,它几乎纹丝不动。
步骤
- 给三个划分取指纹(哈希、大小、行数、表头)。
- 用业务规则声明数据契约,确认训练数据落在其中。
- 用契约核对新收集的数据,做出违规清单。
- 隔离违规的行,把用于训练的行单独留下。
- 在坏划分中找出重叠的客户。
- 去掉重叠,训练两次,测量指标差异。
- 把到目前为止的事实和局限汇总成数据卡。
参考
- 所有工作都在
/root/datacontract下进行。请先执行mkdir -p /root/datacontract。 - 材料在
/opt/fixtures/mlops,各列的说明在同一个文件夹的DATA-CARD.md里。 - 行号始终是 去掉表头后 从 1 开始。评分器也按同样的规则数。
- 常见错误——把空字符串读成
0,导致漏掉违规;以及重写 CSV 时漏掉表头。 - 实验 Pod 没有卷,会话一结束
/root就消失。如果觉得会花很久,请先用+시간(界面上显示为“+时间”)延长。
确认同名的文件是不是同一个文件
在 /root/datacontract/dataset.json 中创建 files 对象,对 train.csv、valid.csv、test.csv 分别保存 sha256、bytes、rows(去掉表头的数据行数)、columns(表头列表)。材料在 /opt/fixtures/mlops 下。
文件名不是版本。内容的哈希才是版本。行数要用 csv 模块跳过表头之后再数。
声明什么是正常的
在 /root/datacontract/contract.json 中保存 source、source_sha256、row_count、required、ranges、observed。source 是 /opt/fixtures/mlops/train.csv,required 是按表头中写的顺序排列的列名列表,ranges 是把业务规则(tenure_months 0..120、monthly_fee 0..200、support_tickets 0..20、late_payments 0..12、usage_hours 0..400、churn 0..1)写成 [最小值, 最大值] 的形式,observed 是在 train.csv 中实际观察到的 [最小值, 最大值]。
契约不是从数据里推断出来的,而是从业务出发声明的。不过,训练数据是否落在这个声明之内,必须确认。
用契约核对新收集的数据
用 /root/datacontract/contract.json 检查 /opt/fixtures/mlops/week2.csv,把 source、total_rows、violations、violation_count、passed 保存到 /root/datacontract/validation.json。violations 的每一项只有 row(去掉表头后从 1 开始的行号)、column、rule 三个键,rule 在为空值时是 required,读不成数字时是 type,超出范围时是 range。排序按行号升序,同一行内按文件中写的列顺序。
把检查规则集中放在代码的一处,下周收集的数据也能照样运行。注意不要把空字符串和 0 当成同一回事。
被丢弃的行也要留下
把只要有一处违反契约的行保存到 /root/datacontract/quarantine.csv,其余的保存到 /root/datacontract/clean_week2.csv。两个文件的第一行都放与原文件相同的表头,并保持原来的顺序。
悄悄丢掉的行,下个月会变成“数据为什么少了”。有隔离文件,以后就能重新看到丢掉了什么、为什么丢。
用结构来确认划分是否重叠
比较 /opt/fixtures/mlops/bad_train.csv 和 /opt/fixtures/mlops/bad_valid.csv 的 customer_id,把 train、valid(两个文件路径)、overlap_count、overlap_ratio(重叠数 ÷ 评估行数,四舍五入到小数点后第四位)、overlapping_ids(字典序靠前的 5 个)、split_valid 保存到 /root/datacontract/leakage.json。
重叠要按 个体 而不是按行来数。同一个客户如果两边都有,对这个客户来说,模型就已经看过答案了。
去掉泄漏,测一测指标动了多少
从 /opt/fixtures/mlops/bad_valid.csv 中只留下去掉训练一侧客户的行,生成 /root/datacontract/fixed_valid.csv(保持表头和顺序)。然后用 bad_train.csv 以 lr 0.1、epochs 40、seed 7 训练两次,把 leaky_accuracy(用 bad_valid.csv 测得的值)、clean_accuracy(用 fixed_valid.csv 测得的值)、delta(clean − leaky,四舍五入到小数点后第四位)、threshold(0.05)、visible_in_metric(|delta| 是否大于等于 threshold)保存到 /root/datacontract/split_effect.json。
先预测结果再去测。如果与预测不同,这个差别就是这一步要学的东西。
写下用这份数据能说什么
把 train_sha256、contract_sha256(/root/datacontract/contract.json 的哈希)、clean_week2_sha256、violation_count、leakage_overlap_count、approved_for_training、limitations(40 个字符以上)保存到 /root/datacontract/datacard.json。从前面步骤的产出中取值并对上。
数据卡不是用来夸耀的,而是用来写局限的。把用合成数据说不了的事写下来,下一个人就不会用错。