pub fn run_oof_classification(
model: &TabFMModel,
x_train_raw: &[Vec<Value>],
y_train_codes: &[f64],
cat_mask: &[bool],
n_classes: usize,
configs: &[MemberConfig],
p: &EnsembleParams,
num_folds: usize,
) -> Result<Vec<Vec<Vec<f64>>>>Expand description
Runs the full n_estimators-member ensemble on each of num_folds folds (fold’s validation
rows as query, the rest as context), assembling [member][original_train_row][class]
un-shifted OOF logits (every training row appears in exactly one fold’s validation set).
A flattened-across-folds version (grouping folds by (train_size, val_size) shape and running
all fold×member tasks through one rayon pass per shape group) was tried here, on the theory
that 5 sequential per-fold rounds (default num_folds_for_cv=5) waste parallelism when each
round only chunks n_estimators members into a handful of rayon chunks. Measured worse in
every configuration tried (same or ~25% slower with default chunking, ~75% slower forcing one
batch per shape group) — each fold’s own predict_batch call already saturates Accelerate’s
internal BLAS threading on this machine, so adding a rayon layer across folds/shape-groups on
top oversubscribes rather than helping (the same class of issue Round 1 documented for thread
count). Reverted; kept simple.