Paradigm A
规则残差做判定,也做排序
十条勾稽的连续相对残差是判定和审核顺序的基线。MLP 只在见过的注入上压低舍入误报,换一种注入排序差于随机。实验项,不进门禁。
OCANNL lab · cc_replica
工作底稿只跑港股实报。下面的曲线来自合成语料上的 cc 复刻,用来固定种子和黄金文件,不进队列。与 ocaml/bin/goki.ml 同一套结构。模型说明 PDF
Paradigm A
十条勾稽的连续相对残差是判定和审核顺序的基线。MLP 只在见过的注入上压低舍入误报,换一种注入排序差于随机。实验项,不进门禁。
Paradigm B
整张报表压缩重建。重建误差大、但说不上哪条规则 violated 的样本送人工。
Paradigm C
用其余科目回归货币资金 / 资产。残差超阈值即标记。可解释性最好。
Paradigm D
Map-Net 取数,七个闭合头,Pack-Net 取包,Completeness-Net 找漏填,ECL/公允/折耗估计。合成样本上训,港股底稿上填。
切分与上面的 MLP 相同:种子 3,80/10/10 · 打乱种子 42 · 特征 38。四个切点都只在验证集上按 Youden(召回 − 误报)选定,测试集只评一次。误报率是干净、舍入、重分类被标成真错误的比例。这张表不进门禁。
| 模型 | 准确率 | 召回 | 误报率 | 误报构成 |
|---|---|---|---|---|
规则阈值 八条恒等里最大 |相对残差| | 99.0% | 6/7 | 0/93 | 干净 0 · 舍入 0 · 重分类 0 |
逻辑回归 L2,正负类权重平衡,同一套标准化特征 | 97.0% | 4/7 | 0/93 | 干净 0 · 舍入 0 · 重分类 0 |
浅树 深度 3,基尼,叶上经验概率 | 99.0% | 7/7 | 1/93 | 干净 0 · 舍入 1 · 重分类 0 |
MLP 64-32,与实验室同一训练日程 | 99.0% | 6/7 | 0/93 | 干净 0 · 舍入 0 · 重分类 0 |
测试集 100 条,真错误 7 条。召回一步是 1/7,误报一步是 1/93。MLP 与规则阈值的召回和误报相同,没有优于规则。逻辑回归相对规则:召回 -2,误报 +0。浅树相对规则:召回 +1,误报 +1。一步以内的差距不读成胜出。四行都不进门禁。
这份容易集上,真错误的最小恒等相对残差是 0.067,舍入最大是 0.021,两类不相交。真错误中位数 0.744。规则阈值是注入方式的反函数,MLP 追平并不意外。
每个种子 4000 条,种子 3、11、29、47、71。规则的 AP 用的是连续的最大恒等相对残差,另外加了八条 |rel| 之和,不是二值判定。同召回误报把验证集切点定在召回先到 95% 的地方。换注入的那套没有参与训练,两半分开报。MLP 是实验项,不是排序层。已公告更正的完整科目账还没有,不编。不进门禁。
正在重跑。这一页可以先看上面的容易集。
.cd → .ll → .c · packed FMA
/* goki_mlp_forward — OCANNL cc backend replica
* schedule: packed FMA (v1.0.1-class SIMD)
* seed=3 params=4609 dtype=f32
* checksum=9a7e857d test_auc=1.0000
* .cd → .ll → .c bit-stable under fixed_state_for_init
*/
void goki_mlp_forward(const float *x /* [38] */, float *y /* [1] */) {
float h1[64], h2[32];
/* h1 = relu(W1 @ x + b1) W1 : 64 × 38 */
for (int i = 0; i < 64; ++i) {
float acc = b1[i];
for (int j = 0; j < 38; ++j) acc = fmaf(W1[i*38+j], x[j], acc);
h1[i] = acc > 0.f ? acc : 0.f;
}
/* h2 = relu(W2 @ h1 + b2) W2 : 32 × 64 */
for (int i = 0; i < 32; ++i) {
float acc = b2[i];
for (int j = 0; j < 64; ++j) acc = fmaf(W2[i*64+j], h1[j], acc);
h2[i] = acc > 0.f ? acc : 0.f;
}
/* logit = W3 @ h2 + b3 */
float z = b3[0];
for (int j = 0; j < 32; ++j) z = fmaf(W3[j], h2[j], z);
y[0] = 1.f / (1.f + expf(-z)); /* sigmoid, audit-stable */
}
黄金文件记录边界,不记录不可移植的尾数。
goki_mlp.expected backend=cc_replica fixed_state_for_init=3 n_issuers=1000 n_features=38 params=4609 epochs=14 split=80/10/10 seed=42 train_bce_tail=0.002856 val_bce_tail=0.015417 test_auc=1.000000 test_ap=1.000000 weight_checksum=9a7e857d bit_stable=true (same seed, same schedule, same IEEE f32)
Triage MLP · BCE-with-logits
(* GOKI — tabular MLP on 勾稽 residuals.
Adapted from test/training/mlp_names.ml: embedding replaced with a hosted
feature matrix, softmax + NLL replaced with BCE-with-logits. *)
open Base
open Ocannl
open Stdio
module IDX = Train.IDX
open Nn_blocks.DSL_modules
module Asgns = Ir.Assignments
let n_features = 38
let hid1 = 64
let hid2 = 32
let batch_size = 32
let epochs = 28
let init_seed = 3
let () =
Utils.settings.fixed_state_for_init <- Some init_seed;
Tensor.unsafe_reinitialize ();
let make_x label =
let open Bigarray in
let ga = Genarray.create Float32 c_layout [| batch_size; n_features |] in
let nd = Ir.Ndarray.as_array Ir.Ops.Single ga in
Tensor.term ~init_data:(Reshape nd) ~grad_spec:If_needed ~label:[ label ]
~batch_dims:[ batch_size ] ~input_dims:[] ~output_dims:[ n_features ] ()
in
let make_y label =
let open Bigarray in
let ga = Genarray.create Float32 c_layout [| batch_size; 1 |] in
let nd = Ir.Ndarray.as_array Ir.Ops.Single ga in
Tensor.term ~init_data:(Reshape nd) ~grad_spec:If_needed ~label:[ label ]
~batch_dims:[ batch_size ] ~input_dims:[] ~output_dims:[ 1 ] ()
in
let x_batch = make_x "x_batch" in
let y_batch = make_y "y_batch" in
let%op h1 x = relu (({ w1 } * x) + { b1; o = [ hid1 ] }) in
let%op h2 x = relu (({ w2 } * h1 x) + { b2; o = [ hid2 ] }) in
let%op logit x = ({ w3 } * h2 x) + { b3; o = [ 1 ] } in