Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -9,12 +9,12 @@ import albumentations as A
|
|
| 9 |
from albumentations.pytorch import ToTensorV2
|
| 10 |
from transformers import AutoModel
|
| 11 |
import matplotlib.pyplot as plt
|
|
|
|
| 12 |
|
| 13 |
# ==============================================================================
|
| 14 |
# 1. GLOBAL CONFIGURATION & PATHOLOGY DEFINITIONS
|
| 15 |
# ==============================================================================
|
| 16 |
IMAGE_SIZE = 384
|
| 17 |
-
DEVICE = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
|
| 18 |
|
| 19 |
PATHOLOGY_COLS = [
|
| 20 |
'Enlarged Cardiomediastinum', 'Cardiomegaly', 'Lung Opacity',
|
|
@@ -154,21 +154,17 @@ class ViTGradCAM:
|
|
| 154 |
# ==============================================================================
|
| 155 |
# 3. INITIALIZE MODEL & WEIGHTS
|
| 156 |
# ==============================================================================
|
| 157 |
-
def load_trained_model():
|
| 158 |
-
model = OptimizedMultiModalRadDINO(num_classes=13).to(
|
| 159 |
model_path = 'best_model.pt'
|
| 160 |
if os.path.exists(model_path):
|
| 161 |
-
model.load_state_dict(torch.load(model_path, map_location=
|
| 162 |
print("Successfully loaded trained weights from best_model.pt")
|
| 163 |
else:
|
| 164 |
print("Warning: best_model.pt not found. Initializing with pretrained backbone.")
|
| 165 |
model.eval()
|
| 166 |
return model
|
| 167 |
|
| 168 |
-
model = load_trained_model()
|
| 169 |
-
target_layer = model.vision_model.encoder.layer[-1].norm1
|
| 170 |
-
cam_engine = ViTGradCAM(model, target_layer)
|
| 171 |
-
|
| 172 |
# ==============================================================================
|
| 173 |
# 4. PREPROCESSING PIPELINE
|
| 174 |
# ==============================================================================
|
|
@@ -186,12 +182,18 @@ val_transforms = A.Compose([
|
|
| 186 |
])
|
| 187 |
|
| 188 |
# ==============================================================================
|
| 189 |
-
# 5. INFERENCE & VISUALIZATION LOGIC
|
| 190 |
# ==============================================================================
|
|
|
|
| 191 |
def predict_xray(image_input, view_position, target_cam_pathology):
|
| 192 |
if image_input is None:
|
| 193 |
return None, None, "Please upload a valid chest X-ray image."
|
| 194 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 195 |
# Convert image format
|
| 196 |
image_rgb = cv2.cvtColor(image_input, cv2.COLOR_BGR2RGB) if len(image_input.shape) == 3 else image_input
|
| 197 |
|
|
@@ -204,11 +206,11 @@ def predict_xray(image_input, view_position, target_cam_pathology):
|
|
| 204 |
elif view_position == "LL":
|
| 205 |
view_vector = [0.0, 0.0, 1.0]
|
| 206 |
|
| 207 |
-
tabular_tensor = torch.tensor([view_vector], dtype=torch.float32).to(
|
| 208 |
|
| 209 |
# Process Image Tensor
|
| 210 |
augmented = val_transforms(image=image_rgb)
|
| 211 |
-
img_tensor = augmented['image'].unsqueeze(0).to(
|
| 212 |
|
| 213 |
# Run Model Inference
|
| 214 |
with torch.no_grad():
|
|
@@ -312,7 +314,7 @@ with gr.Blocks(css=custom_css, title="ThoraxVision AI - Clinical X-Ray Analysis"
|
|
| 312 |
# TAB 2: TECHNICAL DOCUMENTATION & ARCHITECTURE
|
| 313 |
# ----------------------------------------------------------------------
|
| 314 |
with gr.TabItem("📖 System Architecture & Scientific Documentation"):
|
| 315 |
-
gr.Markdown("""
|
| 316 |
## Executive Overview
|
| 317 |
**ThoraxVision AI** is an advanced multimodal diagnostic deep learning framework trained to detect 13 distinct thoracic pathologies simultaneously from chest radiographs. Built upon the `microsoft/rad-dino` Vision Transformer (ViT) architecture, the model integrates clinical tabular metadata with high-resolution image representations.
|
| 318 |
|
|
@@ -356,7 +358,7 @@ with gr.Blocks(css=custom_css, title="ThoraxVision AI - Clinical X-Ray Analysis"
|
|
| 356 |
metrics_df = pd.DataFrame(MODEL_METRICS)
|
| 357 |
gr.Dataframe(value=metrics_df, interactive=False)
|
| 358 |
|
| 359 |
-
gr.Markdown("""
|
| 360 |
* **Mean AUC-ROC Across All Classes:** **0.7852**
|
| 361 |
* **Optimal Threshold Strategy:** Decision thresholds were tuned individually for each pathology to maximize the F1-Score rather than relying on an arbitrary 0.5 default cut-off.
|
| 362 |
""")
|
|
|
|
| 9 |
from albumentations.pytorch import ToTensorV2
|
| 10 |
from transformers import AutoModel
|
| 11 |
import matplotlib.pyplot as plt
|
| 12 |
+
import spaces
|
| 13 |
|
| 14 |
# ==============================================================================
|
| 15 |
# 1. GLOBAL CONFIGURATION & PATHOLOGY DEFINITIONS
|
| 16 |
# ==============================================================================
|
| 17 |
IMAGE_SIZE = 384
|
|
|
|
| 18 |
|
| 19 |
PATHOLOGY_COLS = [
|
| 20 |
'Enlarged Cardiomediastinum', 'Cardiomegaly', 'Lung Opacity',
|
|
|
|
| 154 |
# ==============================================================================
|
| 155 |
# 3. INITIALIZE MODEL & WEIGHTS
|
| 156 |
# ==============================================================================
|
| 157 |
+
def load_trained_model(device):
|
| 158 |
+
model = OptimizedMultiModalRadDINO(num_classes=13).to(device)
|
| 159 |
model_path = 'best_model.pt'
|
| 160 |
if os.path.exists(model_path):
|
| 161 |
+
model.load_state_dict(torch.load(model_path, map_location=device))
|
| 162 |
print("Successfully loaded trained weights from best_model.pt")
|
| 163 |
else:
|
| 164 |
print("Warning: best_model.pt not found. Initializing with pretrained backbone.")
|
| 165 |
model.eval()
|
| 166 |
return model
|
| 167 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 168 |
# ==============================================================================
|
| 169 |
# 4. PREPROCESSING PIPELINE
|
| 170 |
# ==============================================================================
|
|
|
|
| 182 |
])
|
| 183 |
|
| 184 |
# ==============================================================================
|
| 185 |
+
# 5. INFERENCE & VISUALIZATION LOGIC (DECORATED WITH @spaces.GPU)
|
| 186 |
# ==============================================================================
|
| 187 |
+
@spaces.GPU
|
| 188 |
def predict_xray(image_input, view_position, target_cam_pathology):
|
| 189 |
if image_input is None:
|
| 190 |
return None, None, "Please upload a valid chest X-ray image."
|
| 191 |
|
| 192 |
+
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
|
| 193 |
+
model = load_trained_model(device)
|
| 194 |
+
target_layer = model.vision_model.encoder.layer[-1].norm1
|
| 195 |
+
cam_engine = ViTGradCAM(model, target_layer)
|
| 196 |
+
|
| 197 |
# Convert image format
|
| 198 |
image_rgb = cv2.cvtColor(image_input, cv2.COLOR_BGR2RGB) if len(image_input.shape) == 3 else image_input
|
| 199 |
|
|
|
|
| 206 |
elif view_position == "LL":
|
| 207 |
view_vector = [0.0, 0.0, 1.0]
|
| 208 |
|
| 209 |
+
tabular_tensor = torch.tensor([view_vector], dtype=torch.float32).to(device)
|
| 210 |
|
| 211 |
# Process Image Tensor
|
| 212 |
augmented = val_transforms(image=image_rgb)
|
| 213 |
+
img_tensor = augmented['image'].unsqueeze(0).to(device)
|
| 214 |
|
| 215 |
# Run Model Inference
|
| 216 |
with torch.no_grad():
|
|
|
|
| 314 |
# TAB 2: TECHNICAL DOCUMENTATION & ARCHITECTURE
|
| 315 |
# ----------------------------------------------------------------------
|
| 316 |
with gr.TabItem("📖 System Architecture & Scientific Documentation"):
|
| 317 |
+
gr.Markdown(r"""
|
| 318 |
## Executive Overview
|
| 319 |
**ThoraxVision AI** is an advanced multimodal diagnostic deep learning framework trained to detect 13 distinct thoracic pathologies simultaneously from chest radiographs. Built upon the `microsoft/rad-dino` Vision Transformer (ViT) architecture, the model integrates clinical tabular metadata with high-resolution image representations.
|
| 320 |
|
|
|
|
| 358 |
metrics_df = pd.DataFrame(MODEL_METRICS)
|
| 359 |
gr.Dataframe(value=metrics_df, interactive=False)
|
| 360 |
|
| 361 |
+
gr.Markdown(r"""
|
| 362 |
* **Mean AUC-ROC Across All Classes:** **0.7852**
|
| 363 |
* **Optimal Threshold Strategy:** Decision thresholds were tuned individually for each pathology to maximize the F1-Score rather than relying on an arbitrary 0.5 default cut-off.
|
| 364 |
""")
|