Download model/train_classifier.py from WolfDavid/ai-internet-diagnostic-model: direct link, hf CLI and curl.
- Browser
- Download file 2.64 kB
-
https://huggingface.co/WolfDavid/ai-internet-diagnostic-model/resolve/main/model/train_classifier.py
- Command line
-
hf download hf://WolfDavid/ai-internet-diagnostic-model/model/train_classifier.py
-
curl -L -o train_classifier.py https://huggingface.co/WolfDavid/ai-internet-diagnostic-model/resolve/main/model/train_classifier.py
2.64 kB
| """LightGBM 10-class classifier with isotonic calibration (D-CAL-01..03). | |
| Per OQ-2 resolution / D-CAL-02: pass LGBMClassifier directly to | |
| CalibratedClassifierCV — sklearn 1.8 applies OvR internally for | |
| method='isotonic' on multi-class. An explicit one-vs-rest wrapper around | |
| the base estimator would cause double-OvR (Pitfall 4). | |
| """ | |
| from __future__ import annotations | |
| import numpy as np | |
| from lightgbm import LGBMClassifier | |
| from sklearn.calibration import CalibratedClassifierCV | |
| from sklearn.model_selection import StratifiedKFold | |
| # D-PUB-07 fixed defaults at v1, no HPO. D-REPRO-01 determinism trio. | |
| LGBM_PARAMS: dict = { | |
| "n_estimators": 500, | |
| "learning_rate": 0.05, | |
| "num_leaves": 63, | |
| "max_depth": -1, | |
| "class_weight": "balanced", # carries forward Phase 1 D-07 | |
| "deterministic": True, # Pitfall 1 — required for 1e-4 reproducibility | |
| "force_col_wise": True, # required when deterministic=True (LightGBM docs) | |
| "n_jobs": -1, | |
| "verbose": -1, # silence LightGBM stdout for clean CI logs | |
| } | |
| def train_calibrated_classifier( | |
| X: np.ndarray, | |
| y: np.ndarray, | |
| *, | |
| classifier_seed: int, | |
| cv_seed: int, | |
| ) -> CalibratedClassifierCV: | |
| """Fit LightGBM + isotonic calibration with stratified 5-fold CV. | |
| Single-wrap CalibratedClassifierCV(LGBMClassifier, method='isotonic', cv=5). | |
| Returns a fitted CalibratedClassifierCV with len(.calibrated_classifiers_) == 5 | |
| (one per fold; ensemble='auto' resolves to True since base is not FrozenEstimator). | |
| """ | |
| base = LGBMClassifier(random_state=classifier_seed, **LGBM_PARAMS) | |
| cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=cv_seed) | |
| calibrated = CalibratedClassifierCV( | |
| estimator=base, | |
| method="isotonic", # D-CAL-01 | |
| cv=cv, # D-CAL-03 — explicit StratifiedKFold for reproducibility | |
| ensemble="auto", # resolves to True; keeps 5 (base + isotonic) pairs | |
| n_jobs=-1, | |
| ) | |
| calibrated.fit(X, y) | |
| return calibrated | |
| def train_raw_classifier( | |
| X: np.ndarray, y: np.ndarray, *, classifier_seed: int | |
| ) -> LGBMClassifier: | |
| """Fit a non-calibrated LGBMClassifier on the same train data + seed. | |
| Needed by the orchestrator (Pattern 6 / 02-02) to produce raw_proba for | |
| the dual reliability grid (D-CAL-06). CalibratedClassifierCV does not | |
| expose the underlying full-train softmax — fold-internal estimators are | |
| on 4/5 of data; we want the matched-seed 5/5 baseline for the raw plot. | |
| """ | |
| clf = LGBMClassifier(random_state=classifier_seed, **LGBM_PARAMS) | |
| clf.fit(X, y) | |
| return clf | |