Spaces:
Running on Zero
Running on Zero
| import os | |
| import sys | |
| import numpy as np | |
| import torch | |
| from PIL import Image | |
| # Add parent directory to sys.path to enable loading of local package | |
| sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) | |
| from gemmasight.config import DIM_FUSED | |
| from gemmasight.utils.preprocess import load_and_preprocess_image | |
| from gemmasight.models.feature_extractor import DualEncoderFeatureExtractor | |
| from gemmasight.models.classifier import MSIClassifier | |
| from gemmasight.models.retriever import CaseRetriever | |
| from gemmasight.utils.occlusion import generate_occlusion_heatmap | |
| from gemmasight.inference import GemmaSightInferencePipeline | |
| def run_pipeline_tests(): | |
| print("=== GemmaSight Verification Test Suite ===") | |
| # Create random synthetic image for test | |
| test_img_np = (np.random.rand(224, 224, 3) * 255).astype(np.uint8) | |
| test_img = Image.fromarray(test_img_np) | |
| print("β Created synthetic H&E image.") | |
| # 1. Preprocessing Test | |
| print("\nRunning Test 1: Preprocessing...") | |
| tensor = load_and_preprocess_image(test_img) | |
| assert tensor.shape == (1, 3, 224, 224), f"Unexpected tensor shape {tensor.shape}" | |
| print(f"β Preprocessed image successfully. Output shape: {tensor.shape}") | |
| # 2. Feature Extraction Test | |
| print("\nRunning Test 2: Dual-Encoder Feature Extraction...") | |
| extractor = DualEncoderFeatureExtractor(force_simulation=True) | |
| embeddings = extractor(test_img) | |
| assert embeddings.shape == (1, DIM_FUSED), f"Unexpected embedding shape {embeddings.shape}" | |
| print(f"β Features extracted successfully. Dimensions: {embeddings.shape}") | |
| # 3. Classifier Test | |
| print("\nRunning Test 3: Classification MLP...") | |
| classifier = MSIClassifier(input_dim=DIM_FUSED) | |
| classifier.eval() | |
| prob_tensor = classifier(embeddings) | |
| assert prob_tensor.shape == (1, 1), f"Unexpected prob shape {prob_tensor.shape}" | |
| prob = prob_tensor.item() | |
| assert 0.0 <= prob <= 1.0, f"Probability {prob} out of bounds" | |
| print(f"β Classifier forward pass successful. Predicted MSI-High Probability: {prob:.4%}") | |
| # 4. FAISS Index & Case Retrieval Test | |
| print("\nRunning Test 4: Case Retrieval (FAISS)...") | |
| retriever = CaseRetriever(index_dim=DIM_FUSED) | |
| # Build mini-index | |
| mock_emb = np.random.randn(5, DIM_FUSED).astype(np.float32) | |
| # L2 normalize | |
| mock_emb /= np.linalg.norm(mock_emb, axis=1, keepdims=True) | |
| mock_labels = [0, 1, 0, 1, 0] | |
| mock_descriptions = ["Desc A", "Desc B", "Desc C", "Desc D", "Desc E"] | |
| mock_patient_ids = ["P-1", "P-2", "P-3", "P-4", "P-5"] | |
| retriever.build_index(mock_emb, mock_labels, mock_descriptions, mock_patient_ids) | |
| # Query index | |
| matches = retriever.retrieve_top_k(embeddings.cpu().numpy(), k=3) | |
| assert len(matches) == 3, f"Expected 3 matches, got {len(matches)}" | |
| for match in matches: | |
| assert "similarity" in match, "Matching similarity score missing" | |
| assert "patient_id" in match, "Patient metadata missing" | |
| assert 0.0 <= match["similarity"] <= 1.0, "Similarity out of bounds" | |
| print("β FAISS build, serialization, and top-3 retrieval verified successfully.") | |
| # 5. Occlusion Heatmap Test | |
| print("\nRunning Test 5: Sliding-Window Occlusion Saliency...") | |
| heatmap_overlay = generate_occlusion_heatmap(test_img, extractor, classifier, window_size=40, stride=20) | |
| assert isinstance(heatmap_overlay, Image.Image), "Heatmap output is not PIL Image" | |
| assert heatmap_overlay.size == (224, 224), f"Unexpected heatmap size {heatmap_overlay.size}" | |
| print(f"β Occlusion heatmap visual overlay generated successfully. Resolution: {heatmap_overlay.size}") | |
| # 6. End-to-End Inference Pipeline Orchestrator Test | |
| print("\nRunning Test 6: End-to-End Pipeline Orchestration...") | |
| pipeline = GemmaSightInferencePipeline(force_simulation=True) | |
| prob_p, label_p, heatmap_p, cases_p, report_p = pipeline.run_diagnosis(test_img) | |
| assert 0.0 <= prob_p <= 1.0, "Pipeline probability out of bounds" | |
| assert label_p in ["MSS", "MSI-High"], f"Unexpected label {label_p}" | |
| assert isinstance(heatmap_p, Image.Image), "Pipeline heatmap is not PIL Image" | |
| assert len(cases_p) == 3, f"Expected 3 pipeline cases, got {len(cases_p)}" | |
| assert isinstance(report_p, str) and len(report_p) > 0, "Pipeline report is empty or invalid" | |
| print("β End-to-end pipeline run executed successfully!") | |
| print(f" - Calculated Probability: {prob_p:.2%}") | |
| print(f" - Status Classification: {label_p}") | |
| print(f" - Retrieved Case Matches: {', '.join([c['patient_id'] for c in cases_p])}") | |
| print(f" - Clinical Report Word Count: {len(report_p.split())} words") | |
| print("\n===========================================") | |
| print("π ALL GEMMASIGHT TESTS PASSED SUCCESSFULLY! π") | |
| print("===========================================") | |
| if __name__ == "__main__": | |
| run_pipeline_tests() | |