irenekar commited on
Commit
2a7cd3d
·
verified ·
1 Parent(s): 331a370

Upload 3 files

Browse files
Files changed (3) hide show
  1. app (2).py +179 -0
  2. model_fold_0.pth +3 -0
  3. requirements (2).txt +5 -0
app (2).py ADDED
@@ -0,0 +1,179 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # -*- coding: utf-8 -*-
2
+ """app.ipynb
3
+
4
+ Automatically generated by Colab.
5
+
6
+ Original file is located at
7
+ https://colab.research.google.com/drive/1KKOkxXNFwhNS2I3EHiTAAnmT0g6xZwIT
8
+ """
9
+
10
+ import gradio as gr
11
+ import torch
12
+ import torch.nn as nn
13
+ from torchvision import models, transforms
14
+ from PIL import Image
15
+ import numpy as np
16
+
17
+ # =======================================
18
+ # CONFIGURATION
19
+ # =======================================
20
+
21
+ # Force CPU for Hugging Face free tier
22
+ DEVICE = torch.device("cpu")
23
+
24
+ CLASS_NAMES = ["Non-Glaucoma", "Glaucoma"]
25
+ MODEL_PATH = "model_fold_0.pth"
26
+
27
+ # =======================================
28
+ # LOAD MODEL
29
+ # =======================================
30
+
31
+ try:
32
+ model = models.resnet18(weights=None)
33
+ model.fc = nn.Linear(model.fc.in_features, 2)
34
+
35
+ state_dict = torch.load(MODEL_PATH, map_location=DEVICE)
36
+ model.load_state_dict(state_dict)
37
+
38
+ model.to(DEVICE)
39
+ model.eval()
40
+
41
+ except Exception as e:
42
+ raise RuntimeError(f"Failed to load model from {MODEL_PATH}\nError: {str(e)}")
43
+
44
+ # =======================================
45
+ # IMAGE PREPROCESSING
46
+ # =======================================
47
+
48
+ transform = transforms.Compose([
49
+ transforms.Resize((256, 256)),
50
+ transforms.CenterCrop(224),
51
+ transforms.ToTensor(),
52
+ transforms.Normalize(
53
+ mean=[0.485, 0.456, 0.406],
54
+ std=[0.229, 0.224, 0.225]
55
+ )
56
+ ])
57
+
58
+ # =======================================
59
+ # PREDICTION FUNCTION
60
+ # =======================================
61
+
62
+ def predict_fundus(image):
63
+ if image is None:
64
+ return "Please upload a retinal fundus image to begin.", None
65
+
66
+ try:
67
+ img_pil = Image.fromarray(image).convert("RGB")
68
+ img_tensor = transform(img_pil).unsqueeze(0).to(DEVICE)
69
+
70
+ with torch.no_grad():
71
+ output = model(img_tensor)
72
+ probs = torch.softmax(output, dim=1)[0].cpu().numpy()
73
+
74
+ pred_idx = int(np.argmax(probs))
75
+ confidence = float(probs[pred_idx])
76
+ label = CLASS_NAMES[pred_idx]
77
+
78
+ result_text = f"""
79
+ ### Prediction Result
80
+
81
+ **Prediction:** {label}
82
+ **Confidence:** {confidence:.1%}
83
+
84
+ **Non-Glaucoma Probability:** {probs[0]:.1%}
85
+ **Glaucoma Probability:** {probs[1]:.1%}
86
+
87
+ ---
88
+
89
+ ⚠ This tool is for research/educational purposes only.
90
+ For clinical decisions, consult a qualified ophthalmologist.
91
+ """.strip()
92
+
93
+ img_display = np.array(img_pil.resize((400, 400)))
94
+
95
+ return result_text, img_display
96
+
97
+ except Exception as e:
98
+ return f"Error during analysis: {str(e)}", None
99
+
100
+
101
+ # =======================================
102
+ # CUSTOM CSS
103
+ # =======================================
104
+
105
+ custom_css = """
106
+ body { font-family: 'Segoe UI', sans-serif; background: #f8fafc; }
107
+ .gradio-container { max-width: 1100px !important; margin: auto; }
108
+ h1 { color: #1e40af; text-align: center; margin-bottom: 0.4em; }
109
+ .upload-zone { border: 2px dashed #94a3b8; border-radius: 12px; padding: 20px; background: white; }
110
+ .result-panel {
111
+ background: white;
112
+ border-radius: 12px;
113
+ box-shadow: 0 4px 15px rgba(0,0,0,0.08);
114
+ padding: 24px;
115
+ min-height: 380px;
116
+ }
117
+ .note { font-size: 0.95em; color: #64748b; margin-top: 16px; }
118
+ """
119
+
120
+ # =======================================
121
+ # GRADIO INTERFACE
122
+ # =======================================
123
+
124
+ with gr.Blocks(theme=gr.themes.Soft(), css=custom_css) as demo:
125
+ gr.Markdown(
126
+ """
127
+ # Glaucoma Screening – Fundus Image Analysis
128
+
129
+ Upload a retinal fundus photograph to receive an AI-based probability assessment.
130
+ This tool is for research/educational purposes only — **not for clinical diagnosis**.
131
+ """
132
+ )
133
+
134
+ with gr.Row(equal_height=True):
135
+ with gr.Column(scale=5):
136
+ gr.Markdown("### Upload Fundus Image")
137
+ input_image = gr.Image(
138
+ type="numpy",
139
+ label="",
140
+ elem_classes=["upload-zone"],
141
+ height=480,
142
+ image_mode="RGB"
143
+ )
144
+ analyze_btn = gr.Button("Analyze Image", variant="primary")
145
+
146
+ with gr.Column(scale=5):
147
+ gr.Markdown("### Analysis Result")
148
+ output_text = gr.Markdown(
149
+ value="Upload an image and click Analyze to begin.",
150
+ elem_classes=["result-panel"]
151
+ )
152
+ output_image = gr.Image(
153
+ label="Uploaded Image (resized)",
154
+ type="numpy",
155
+ height=400,
156
+ interactive=False
157
+ )
158
+
159
+ gr.Markdown(
160
+ """
161
+ <div class="note">
162
+ <strong>Important:</strong> This is an experimental AI model trained on limited data.
163
+ Results should be interpreted cautiously and verified by a qualified ophthalmologist.
164
+ </div>
165
+ """,
166
+ elem_classes=["note"]
167
+ )
168
+
169
+ analyze_btn.click(
170
+ fn=predict_fundus,
171
+ inputs=input_image,
172
+ outputs=[output_text, output_image]
173
+ )
174
+
175
+ # =======================================
176
+ # LAUNCH (HF Compatible)
177
+ # =======================================
178
+
179
+ demo.launch()
model_fold_0.pth ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:75c8995845cbefd4c06a0c3aefbad08007d9d131e3792a61b3c63f9dee0bd631
3
+ size 44790027
requirements (2).txt ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ gradio
2
+ torch
3
+ torchvision
4
+ pillow
5
+ numpy