Eklavya16 commited on
Commit
f086854
·
verified ·
1 Parent(s): 9373b9c

Delete src/streamlit_app.py

Browse files
Files changed (1) hide show
  1. src/streamlit_app.py +0 -249
src/streamlit_app.py DELETED
@@ -1,249 +0,0 @@
1
- import streamlit as st
2
- import torch
3
- import torch.nn as nn
4
- import torchvision.models as models
5
- import torchvision.transforms as transforms
6
- import numpy as np
7
- from PIL import Image
8
- import cv2
9
- from huggingface_hub import hf_hub_download
10
-
11
- HF_REPO_ID = "Eklavya16/DermAssist"
12
-
13
- CLASSIFICATION_THRESHOLD = 0.5
14
- UNCERTAINTY_THRESHOLD = 0.165
15
-
16
- device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
17
-
18
- st.set_page_config(
19
- page_title="DermAssist – Clinical Dermoscopic AI",
20
- layout="wide"
21
- )
22
-
23
- def build_model():
24
- model = models.resnet50(weights="IMAGENET1K_V1")
25
- in_features = model.fc.in_features
26
- model.fc = nn.Sequential(
27
- nn.Linear(in_features, 256),
28
- nn.ReLU(),
29
- nn.Dropout(p=0.5),
30
- nn.Linear(256, 1)
31
- )
32
- return model.to(device)
33
-
34
- @st.cache_resource
35
- def load_models():
36
- models_list = []
37
- for i in range(1, 4):
38
- model_path = hf_hub_download(
39
- repo_id=HF_REPO_ID,
40
- filename=f"resnet50_model_{i}.pth"
41
- )
42
-
43
- model = build_model()
44
- model.load_state_dict(
45
- torch.load(model_path, map_location=device)
46
- )
47
- model.eval()
48
- models_list.append(model)
49
- return models_list
50
-
51
- ensemble_models = load_models()
52
-
53
- val_transform = transforms.Compose([
54
- transforms.Resize((224, 224)),
55
- transforms.ToTensor(),
56
- transforms.Normalize(
57
- mean=[0.485, 0.456, 0.406],
58
- std=[0.229, 0.224, 0.225]
59
- )
60
- ])
61
-
62
- class GradCAM:
63
- def __init__(self, model, target_layer):
64
- self.model = model
65
- self.gradients = None
66
- self.activations = None
67
-
68
- target_layer.register_forward_hook(self.save_activation)
69
- target_layer.register_backward_hook(self.save_gradient)
70
-
71
- def save_activation(self, module, input, output):
72
- self.activations = output
73
-
74
- def save_gradient(self, module, grad_input, grad_output):
75
- self.gradients = grad_output[0]
76
-
77
- def generate(self, input_image, class_idx):
78
- self.model.zero_grad()
79
- output = self.model(input_image)
80
- loss = output[0]
81
- loss.backward()
82
-
83
- gradients = self.gradients[0].cpu().data.numpy()
84
- activations = self.activations[0].cpu().data.numpy()
85
-
86
- weights = np.mean(gradients, axis=(1, 2))
87
- cam = np.zeros(activations.shape[1:], dtype=np.float32)
88
-
89
- for i, w in enumerate(weights):
90
- cam += w * activations[i]
91
-
92
- cam = np.maximum(cam, 0)
93
- cam = cv2.resize(cam, (224, 224))
94
-
95
- cam[cam < np.percentile(cam, 75)] = 0
96
-
97
- if cam.max() > 0:
98
- cam = cam / cam.max()
99
-
100
- return cam
101
-
102
- target_layer = ensemble_models[0].layer4[-1]
103
- gradcam = GradCAM(ensemble_models[0], target_layer)
104
-
105
- def ensemble_predict(models, image_tensor):
106
- probs_list = []
107
-
108
- with torch.no_grad():
109
- for model in models:
110
- output = model(image_tensor)
111
- prob = torch.sigmoid(output).item()
112
- probs_list.append(prob)
113
-
114
- mean_prob = np.mean(probs_list)
115
- std_prob = np.std(probs_list)
116
-
117
- return mean_prob, std_prob, probs_list
118
-
119
- def decision_logic(mean_prob, std_prob):
120
- if std_prob > UNCERTAINTY_THRESHOLD:
121
- return "UNCERTAIN"
122
-
123
- if mean_prob >= 0.75:
124
- return "HIGH RISK"
125
-
126
- if mean_prob >= CLASSIFICATION_THRESHOLD:
127
- return "MODERATE RISK"
128
-
129
- return "LOW RISK"
130
-
131
- def overlay_gradcam(original_image, cam):
132
- image = np.array(original_image.resize((224, 224)))
133
- heatmap = cv2.applyColorMap(np.uint8(255 * cam), cv2.COLORMAP_JET)
134
- heatmap = cv2.cvtColor(heatmap, cv2.COLOR_BGR2RGB)
135
-
136
- overlay = cv2.addWeighted(image, 0.6, heatmap, 0.4, 0)
137
- return overlay
138
-
139
- st.sidebar.title("About DermAssist")
140
-
141
- st.sidebar.write("""
142
- DermAssist is an AI-powered dermoscopic analysis system trained on HAM10000
143
- and externally validated on ISIC 2019.
144
-
145
- This system:
146
- - Uses a 3-model ResNet50 ensemble
147
- - Provides calibrated risk scores
148
- - Estimates uncertainty via model disagreement
149
- - Generates Grad-CAM visual explanations
150
- """)
151
-
152
- st.sidebar.write("---")
153
- st.sidebar.write("Clinical Use Disclaimer:")
154
- st.sidebar.write("""
155
- This tool is for research and educational purposes only.
156
- It does not replace professional medical diagnosis.
157
- """)
158
-
159
- st.title("DermAssist – Clinical Dermoscopic Risk Triage System")
160
-
161
- page = st.radio("Select View", ["Prediction", "Validation Metrics"])
162
-
163
- if page == "Prediction":
164
-
165
- uploaded_file = st.file_uploader("Upload Dermoscopic Image", type=["jpg","jpeg","png"])
166
-
167
- if uploaded_file:
168
- image = Image.open(uploaded_file).convert("RGB")
169
-
170
- col1, col2 = st.columns(2)
171
-
172
- with col1:
173
- st.image(image, caption="Uploaded Image", use_container_width=True)
174
-
175
- image_tensor = val_transform(image).unsqueeze(0).to(device)
176
-
177
- mean_prob, std_prob, individual_probs = ensemble_predict(
178
- ensemble_models,
179
- image_tensor
180
- )
181
-
182
- decision = decision_logic(mean_prob, std_prob)
183
- confidence = 1 - std_prob
184
-
185
- target_class = 1 if mean_prob >= CLASSIFICATION_THRESHOLD else 0
186
- cam = gradcam.generate(image_tensor, target_class)
187
- overlay = overlay_gradcam(image, cam)
188
-
189
- with col2:
190
- st.image(overlay, caption="Grad-CAM Attention Map", use_container_width=True)
191
-
192
- st.write("---")
193
-
194
- if decision == "HIGH RISK":
195
- st.error("High Risk – Immediate Clinical Evaluation Recommended")
196
- elif decision == "MODERATE RISK":
197
- st.warning("Moderate Risk – Professional Evaluation Recommended")
198
- elif decision == "UNCERTAIN":
199
- st.info("Uncertain – Dermatologist Review Recommended")
200
- else:
201
- st.success("Low Risk – Monitor and Recheck")
202
-
203
- st.subheader("Prediction Summary")
204
-
205
- st.metric("Malignancy Probability", f"{mean_prob * 100:.2f}%")
206
- st.metric("Confidence Score", f"{confidence * 100:.2f}%")
207
- st.metric("Model Disagreement", f"{std_prob * 100:.2f}%")
208
-
209
- st.write("Individual Model Outputs:")
210
- for i, p in enumerate(individual_probs):
211
- st.write(f"Model {i+1}: {p*100:.2f}%")
212
-
213
- st.write("---")
214
- st.write("Clinical Notes:")
215
- st.write("""
216
- - Probability reflects estimated malignancy risk.
217
- - Confidence is derived from ensemble agreement.
218
- - High model disagreement indicates uncertainty.
219
- - Grad-CAM highlights regions influencing the model's decision.
220
- """)
221
-
222
- if page == "Validation Metrics":
223
-
224
- st.subheader("Internal Validation (HAM10000)")
225
-
226
- st.write("""
227
- Ensemble AUC: 0.937
228
- Malignant Recall: ~0.93
229
- Accuracy (t=0.35): 82%
230
- """)
231
-
232
- st.write("""
233
- The model demonstrates strong internal performance with
234
- calibrated sensitivity for melanoma detection.
235
- """)
236
-
237
- st.write("---")
238
- st.subheader("External Validation (ISIC 2019)")
239
- st.write("""
240
- External AUC: 0.740
241
- Precision (t=0.31): 80.7%
242
- Recall (t=0.31): 50.0%
243
- """)
244
-
245
- st.write("""
246
- External testing revealed expected performance drop due to domain shift,
247
- while maintaining clinically useful accuracy. The model generalizes well
248
- to independent datasets.
249
- """)