Spaces:
Sleeping
Sleeping
| #!/usr/bin/env python3 | |
| """ | |
| train_model.py | |
| ============== | |
| Trains an SVM on the QML-selected features and saves it as model.pkl. | |
| Run this ONCE locally before deploying to Hugging Face Spaces. | |
| QML-Selected Features (Quantum Wrapper, VQC, best accuracy 72%): | |
| - Std_ExG (Variability in Excess Green Index) | |
| - Mean_RBR (Red-Blue Ratio) | |
| - Mean_B (Mean Blue Channel) | |
| - Correlation (GLCM Texture Correlation) | |
| """ | |
| import os | |
| import numpy as np | |
| import pandas as pd | |
| import joblib | |
| from sklearn.svm import SVC | |
| from sklearn.preprocessing import StandardScaler | |
| from sklearn.model_selection import StratifiedKFold, cross_val_score | |
| from sklearn.pipeline import Pipeline | |
| from sklearn.metrics import classification_report | |
| # Paths | |
| HERE = os.path.dirname(os.path.abspath(__file__)) | |
| CSV_PATH = os.path.join(HERE, '..', 'QuantumFeatureSelection', 'icml_features_FULL.csv') | |
| OUT_PKL = os.path.join(HERE, 'model.pkl') | |
| # QML-selected features (best subset from VQC wrapper) | |
| QML_FEATURES = ['Std_ExG', 'Mean_RBR', 'Mean_B', 'Correlation'] | |
| def main(): | |
| print("Loading dataset...") | |
| df = pd.read_csv(CSV_PATH) | |
| df = df.dropna() | |
| # Label encoding | |
| df['y'] = (df['Label'] == 'Pre_Defoliation').astype(int) | |
| X = df[QML_FEATURES].values | |
| y = df['y'].values | |
| print(f" Samples: {len(X)} | Pre: {y.sum()} | Post: {(1-y).sum()}") | |
| # Build pipeline: scaler + SVM | |
| pipeline = Pipeline([ | |
| ('scaler', StandardScaler()), | |
| ('svm', SVC(kernel='rbf', C=10, gamma='scale', | |
| probability=True, random_state=42)) | |
| ]) | |
| # Cross-validate | |
| print("\nRunning 5-fold cross-validation...") | |
| cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=42) | |
| scores = cross_val_score(pipeline, X, y, cv=cv, scoring='accuracy') | |
| print(f" CV Accuracy: {scores.mean():.4f} ± {scores.std():.4f}") | |
| # Train on full dataset | |
| print("\nFitting on full dataset...") | |
| pipeline.fit(X, y) | |
| # Quick sanity check | |
| preds = pipeline.predict(X) | |
| print(classification_report(y, preds, target_names=['Post_Defoliation', 'Pre_Defoliation'])) | |
| # Save | |
| joblib.dump(pipeline, OUT_PKL) | |
| print(f"\n✅ Model saved to: {OUT_PKL}") | |
| if __name__ == '__main__': | |
| main() | |