zaher-m's picture
add stacking ensemble
4cbf907 verified
|
Raw
History Blame Contribute Delete
1.87 kB

Stacking ensemble

The combiner: a per-class linear head over the ensemble's per-item probabilities, plus the bank of probabilities it reads. Given those features it reproduces the released label vectors for both tracks.

Run

pip install numpy
python predict.py --track t1     # 352 labels, checked against t1_perclass_stack.txt
python predict.py --track t2     # 644 labels, checked against t2_perclass_stack.txt

Files

File Contents
t1_stacker.json, t2_stacker.json head weights (coef, intercept), the ordered sources list, npy_column_order, label_order, n_items
probs/*.npy per-source (N, 3) probability arrays, 38 sources for T1 and 40 for T2
predict.py loads a head and its features, applies it, writes and checks the labels
t1_perclass_stack.txt, t2_perclass_stack.txt the released label vectors

Method

Each source contributes a 3-way probability per item. The head reads the concatenated (N, 3J) features and applies per-class weights followed by argmax:

logits = X @ W.T + b        # W: (3, 3J), b: (3,)
label  = argmax(logits)

Sizes: T1 has J=38, 114 features and 345 parameters; T2 has J=40, 120 features and 363 parameters.

Watch the column convention. label_order is ["Favor","Against","None"] while the on-disk .npy column order is ["Against","Favor","None"]. predict.py applies the permutation explicitly, so reuse that rather than assuming either order.

Why a per-class head rather than a weighted average

Weighted-mixture families over the same bank (convex, signed linear, and log/product of experts, 39 weights each) cannot reproduce this labeling: each one gives a Farkas certificate with a strictly negative margin. The per-class head can, because it weights every source-by-class cell separately instead of scoring whole members.