prism-backend / src /train_multimodal.py
Penguindrum920's picture
Prepare PRISM backend for Hugging Face Spaces
7bc5fde verified
Raw
History Blame Contribute Delete
5.33 kB
"""
Train and evaluate multimodal machine learning models for Parkinson's disease classification.
This script combines traditional ML, transformer models, and ensemble methods.
"""
import os
import sys
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.metrics import classification_report, confusion_matrix
import warnings
warnings.filterwarnings('ignore')
# Add src directory to path
sys.path.append(os.path.join(os.path.dirname(__file__)))
sys.path.append(os.path.join(os.path.dirname(__file__), 'models'))
from data_preprocessing import DataPreprocessor
from models.multimodal_ml import MultimodalEnsemble, AdvancedFeatureEngineering, create_multimodal_pipeline
def main():
"""Main function to run multimodal ML pipeline."""
print("Multimodal Machine Learning for Parkinson's Disease Classification")
print("=" * 70)
# --- Load and prepare data ---
preprocessor = DataPreprocessor()
base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
file_paths = [
os.path.join(base_dir, "PPMI_Curated_Data_Cut_Public_20241211.csv"),
os.path.join(base_dir, "PPMI_Curated_Data_Cut_Public_20250321.csv"),
os.path.join(base_dir, "PPMI_Curated_Data_Cut_Public_20250714.csv"),
]
print("\nLoading and preparing data with patient-level split...")
X_train, X_test, y_train, y_test = preprocessor.prepare_data(
file_paths,
test_size=0.2,
use_patient_split=True,
)
print(f" Train: {X_train.shape}, Test: {X_test.shape}")
# Convert to numpy arrays if they are DataFrames
if isinstance(X_train, pd.DataFrame):
X_train_np = X_train.values
X_test_np = X_test.values
else:
X_train_np = X_train
X_test_np = X_test
if isinstance(y_train, pd.Series):
y_train_np = y_train.values
y_test_np = y_test.values
else:
y_train_np = y_train
y_test_np = y_test
# Create multimodal pipeline
print("\nCreating multimodal ML pipeline...")
ensemble, results = create_multimodal_pipeline(X_train, X_test, y_train_np, y_test_np)
# Detailed evaluation of ensemble
if ensemble.ensemble_model is not None:
print("\nDetailed Ensemble Evaluation:")
print("-" * 40)
ensemble_results = ensemble.evaluate_ensemble(X_test, y_test_np)
print(f"Ensemble Accuracy: {ensemble_results['accuracy']:.4f}")
print("\nClassification Report:")
print(ensemble_results['classification_report'])
# Plot confusion matrix
os.makedirs('notebooks', exist_ok=True)
plt.figure(figsize=(10, 8))
sns.heatmap(ensemble_results['confusion_matrix'],
annot=True, fmt='d', cmap='Blues',
xticklabels=['HC', 'PD', 'SWEDD', 'PRODROMAL'],
yticklabels=['HC', 'PD', 'SWEDD', 'PRODROMAL'])
plt.title('Multimodal Ensemble - Confusion Matrix')
plt.ylabel('True Label')
plt.xlabel('Predicted Label')
plt.tight_layout()
plt.savefig('notebooks/multimodal_confusion_matrix.png', dpi=300, bbox_inches='tight')
plt.close()
print("Confusion matrix saved to notebooks/multimodal_confusion_matrix.png")
# Advanced analysis
print("\nAdvanced Multimodal Analysis:")
print("-" * 40)
# Feature importance analysis (if available)
if hasattr(ensemble.ensemble_model, 'coef_'):
feature_importance = np.abs(ensemble.ensemble_model.coef_).mean(axis=0)
print("Top 10 most important ensemble features:")
top_indices = np.argsort(feature_importance)[-10:][::-1]
for i, idx in enumerate(top_indices):
print(f"{i+1:2d}. Feature {idx}: {feature_importance[idx]:.4f}")
# Model diversity analysis
print("\nModel Diversity Analysis:")
if len(ensemble.traditional_models) > 0 and len(ensemble.transformer_models) > 0:
trad_preds, _ = ensemble.get_traditional_predictions(X_test)
trans_preds, _ = ensemble.get_transformer_predictions(X_test_np)
if trad_preds and trans_preds:
trad_pred = list(trad_preds.values())[0]
trans_pred = list(trans_preds.values())[0]
agreement = np.mean(trad_pred == trans_pred)
print(f"Agreement between traditional and transformer models: {agreement:.4f}")
# Performance summary
print("\nFinal Performance Summary:")
print("-" * 40)
best_model = max(results.items(), key=lambda x: x[1])
print(f"Best performing model: {best_model[0]} (Accuracy: {best_model[1]:.4f})")
if 'Ensemble' in results:
ensemble_acc = results['Ensemble']
individual_accs = [acc for name, acc in results.items() if name != 'Ensemble']
if individual_accs:
avg_individual = np.mean(individual_accs)
improvement = ensemble_acc - avg_individual
print(f"Ensemble improvement over average individual model: {improvement:.4f}")
print("\nMultimodal ML pipeline completed successfully!")
print("Results and visualizations saved to notebooks/ directory")
if __name__ == "__main__":
main()