同じ名前のCSVが昨日と違う
目標
学習データに指紋を付けてバージョンとし、何が正常かを宣言した契約で新しい収集分を検査し、学習・評価の分割が重なったとき、指標が実際にどれだけ動くかを測ってみます。
なぜ重要なのか
再現が壊れるのは、たいていコードではなくデータです。train.csvという名前はそのままで、中の行が変わっても、何の警告もなく、指標だけが少し変わります。そのため、データには、名前ではなく内容のハッシュをバージョンとして付け、正常な範囲をあらかじめ宣言しておいて、新しく入った収集分を機械で突き合わせます。契約に違反した行を黙って捨てずに、隔離しておくのも、同じ理由です。黙って減ったサンプルは、数か月後に「なぜ性能が下がったのか」として戻ってきます。
最後の2つのステップは、よくある誤解を1つ、実測で崩します。リークがあれば、指標が目立って上がりそうですが、記憶力の弱いモデルでは、ほとんど動きません。
ステップ
- 3つの分割の指紋(ハッシュ・サイズ・行数・ヘッダー)を取ります。
- 業務ルールでデータ契約を宣言し、学習データがその中に収まるかを確認します。
- 新しい収集分を契約に突き合わせて、違反をリストにします。
- 違反した行を隔離し、学習に使う行だけを別に残します。
- 壊れた分割で、重なっている顧客を見つけ出します。
- 重なりを取り除いて2回学習させ、指標の差を測ります。
- これまでの事実と限界を、データカードにまとめます。
参考
- 作業はすべて
/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で実際に観察される[最小, 最大]です。
契約は、データから推測するものではなく、業務から宣言するものです。ただし、学習データがその宣言に収まるかは、必ず確認する必要があります。
新しく入った収集分を契約に突き合わせる
/opt/fixtures/mlops/week2.csvを/root/datacontract/contract.jsonで検査して、/root/datacontract/validation.jsonに、source・total_rows・violations・violation_count・passedを保存してください。violationsの各項目は、row(ヘッダーを除いた1からの行番号)・column・ruleの3つのキーだけを持ち、ruleは、空の値ならrequired、数値として読めなければtype、範囲を外れればrangeです。並べ替えは、行番号の昇順で、同じ行の中では、ファイルに書かれた列の順です。
検査のルールをコードの1か所にまとめておけば、来週の収集分にも、そのまま回せます。空文字列と0を同じものとして扱わないように、注意してください。
捨てた行も残す
契約に違反した行が1つでもある行は/root/datacontract/quarantine.csvに、残りは/root/datacontract/clean_week2.csvに分けて保存してください。2つのファイルとも、元と同じヘッダーを最初の行に置いて、元の順序を維持します。
黙って捨てた行は、来月、「データがなぜ減ったのか」として戻ってきます。隔離ファイルがあれば、何をなぜ捨てたのかを、あとでもう一度見られます。
分割が重なっていないかを構造で確認する
/opt/fixtures/mlops/bad_train.csvと/opt/fixtures/mlops/bad_valid.csvのcustomer_idを比べて、/root/datacontract/leakage.jsonに、train・valid(2つのファイルのパス)・overlap_count・overlap_ratio(重なった数÷評価の行数、小数点以下4桁に丸める)・overlapping_ids(辞書順の先頭5個)・split_validを保存してください。
重なりは、行ではなく個体で数えます。同じ顧客が両側にいれば、その顧客については、モデルが答えをすでに見たことになります。
リークを取り除いて、指標がどれだけ動くかを測る
/opt/fixtures/mlops/bad_valid.csvから、学習側の顧客を除いた行だけを残して、/root/datacontract/fixed_valid.csvを作ってください(ヘッダーと順序は維持)。そのあと、bad_train.csvで、lr 0.1、epochs 40、seed 7で2回学習させて、/root/datacontract/split_effect.jsonに、leaky_accuracy(bad_valid.csvで測った値)・clean_accuracy(fixed_valid.csvで測った値)・delta(clean − leaky、小数点以下4桁に丸める)・threshold(0.05)・visible_in_metric(|delta|がthreshold以上か)を保存してください。
結果を予想してから測ってください。予想と違えば、その差が、このステップで学ぶことです。
このデータで何を言えるかを書く
/root/datacontract/datacard.jsonに、train_sha256・contract_sha256(/root/datacontract/contract.jsonのハッシュ)・clean_week2_sha256・violation_count・leakage_overlap_count・approved_for_training・limitations(40文字以上)を保存してください。前のステップの出力から値を持ってきて合わせます。
データカードは自慢ではなく、限界を書く場所です。合成データでは言えないことを書いておけば、次の人が間違って使いません。