xTorch8 commited on
Commit
267c122
·
1 Parent(s): a8be84c

Refactor application

Browse files
app.ipynb ADDED
@@ -0,0 +1,189 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "code",
5
+ "execution_count": 2,
6
+ "id": "877fa66b",
7
+ "metadata": {},
8
+ "outputs": [
9
+ {
10
+ "ename": "OSError",
11
+ "evalue": "Unable to synchronously open file (file signature not found)",
12
+ "output_type": "error",
13
+ "traceback": [
14
+ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
15
+ "\u001b[1;31mOSError\u001b[0m Traceback (most recent call last)",
16
+ "Cell \u001b[1;32mIn[2], line 95\u001b[0m\n\u001b[0;32m 92\u001b[0m swinunet_model\u001b[38;5;241m.\u001b[39meval()\n\u001b[0;32m 94\u001b[0m \u001b[38;5;66;03m# ----------- Load Classifier Model -----------\u001b[39;00m\n\u001b[1;32m---> 95\u001b[0m classifier_model \u001b[38;5;241m=\u001b[39m \u001b[43mtf\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mkeras\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mmodels\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mload_model\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43m./cnn-swinunet.keras\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\n\u001b[0;32m 97\u001b[0m \u001b[38;5;66;03m# ----------- Transform -----------\u001b[39;00m\n\u001b[0;32m 98\u001b[0m transform \u001b[38;5;241m=\u001b[39m T\u001b[38;5;241m.\u001b[39mCompose([\n\u001b[0;32m 99\u001b[0m T\u001b[38;5;241m.\u001b[39mResize((\u001b[38;5;241m224\u001b[39m, \u001b[38;5;241m224\u001b[39m)),\n\u001b[0;32m 100\u001b[0m T\u001b[38;5;241m.\u001b[39mToTensor()\n\u001b[0;32m 101\u001b[0m ])\n",
17
+ "File \u001b[1;32mc:\\Users\\PC\\anaconda3\\envs\\main-gpu\\lib\\site-packages\\keras\\utils\\traceback_utils.py:70\u001b[0m, in \u001b[0;36mfilter_traceback.<locals>.error_handler\u001b[1;34m(*args, **kwargs)\u001b[0m\n\u001b[0;32m 67\u001b[0m filtered_tb \u001b[38;5;241m=\u001b[39m _process_traceback_frames(e\u001b[38;5;241m.\u001b[39m__traceback__)\n\u001b[0;32m 68\u001b[0m \u001b[38;5;66;03m# To get the full stack trace, call:\u001b[39;00m\n\u001b[0;32m 69\u001b[0m \u001b[38;5;66;03m# `tf.debugging.disable_traceback_filtering()`\u001b[39;00m\n\u001b[1;32m---> 70\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m e\u001b[38;5;241m.\u001b[39mwith_traceback(filtered_tb) \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[0;32m 71\u001b[0m \u001b[38;5;28;01mfinally\u001b[39;00m:\n\u001b[0;32m 72\u001b[0m \u001b[38;5;28;01mdel\u001b[39;00m filtered_tb\n",
18
+ "File \u001b[1;32mc:\\Users\\PC\\anaconda3\\envs\\main-gpu\\lib\\site-packages\\h5py\\_hl\\files.py:564\u001b[0m, in \u001b[0;36mFile.__init__\u001b[1;34m(self, name, mode, driver, libver, userblock_size, swmr, rdcc_nslots, rdcc_nbytes, rdcc_w0, track_order, fs_strategy, fs_persist, fs_threshold, fs_page_size, page_buf_size, min_meta_keep, min_raw_keep, locking, alignment_threshold, alignment_interval, meta_block_size, **kwds)\u001b[0m\n\u001b[0;32m 555\u001b[0m fapl \u001b[38;5;241m=\u001b[39m make_fapl(driver, libver, rdcc_nslots, rdcc_nbytes, rdcc_w0,\n\u001b[0;32m 556\u001b[0m locking, page_buf_size, min_meta_keep, min_raw_keep,\n\u001b[0;32m 557\u001b[0m alignment_threshold\u001b[38;5;241m=\u001b[39malignment_threshold,\n\u001b[0;32m 558\u001b[0m alignment_interval\u001b[38;5;241m=\u001b[39malignment_interval,\n\u001b[0;32m 559\u001b[0m meta_block_size\u001b[38;5;241m=\u001b[39mmeta_block_size,\n\u001b[0;32m 560\u001b[0m \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwds)\n\u001b[0;32m 561\u001b[0m fcpl \u001b[38;5;241m=\u001b[39m make_fcpl(track_order\u001b[38;5;241m=\u001b[39mtrack_order, fs_strategy\u001b[38;5;241m=\u001b[39mfs_strategy,\n\u001b[0;32m 562\u001b[0m fs_persist\u001b[38;5;241m=\u001b[39mfs_persist, fs_threshold\u001b[38;5;241m=\u001b[39mfs_threshold,\n\u001b[0;32m 563\u001b[0m fs_page_size\u001b[38;5;241m=\u001b[39mfs_page_size)\n\u001b[1;32m--> 564\u001b[0m fid \u001b[38;5;241m=\u001b[39m \u001b[43mmake_fid\u001b[49m\u001b[43m(\u001b[49m\u001b[43mname\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mmode\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43muserblock_size\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mfapl\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mfcpl\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mswmr\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mswmr\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 566\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(libver, \u001b[38;5;28mtuple\u001b[39m):\n\u001b[0;32m 567\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_libver \u001b[38;5;241m=\u001b[39m libver\n",
19
+ "File \u001b[1;32mc:\\Users\\PC\\anaconda3\\envs\\main-gpu\\lib\\site-packages\\h5py\\_hl\\files.py:238\u001b[0m, in \u001b[0;36mmake_fid\u001b[1;34m(name, mode, userblock_size, fapl, fcpl, swmr)\u001b[0m\n\u001b[0;32m 236\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m swmr \u001b[38;5;129;01mand\u001b[39;00m swmr_support:\n\u001b[0;32m 237\u001b[0m flags \u001b[38;5;241m|\u001b[39m\u001b[38;5;241m=\u001b[39m h5f\u001b[38;5;241m.\u001b[39mACC_SWMR_READ\n\u001b[1;32m--> 238\u001b[0m fid \u001b[38;5;241m=\u001b[39m \u001b[43mh5f\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mopen\u001b[49m\u001b[43m(\u001b[49m\u001b[43mname\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mflags\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mfapl\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mfapl\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 239\u001b[0m \u001b[38;5;28;01melif\u001b[39;00m mode \u001b[38;5;241m==\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mr+\u001b[39m\u001b[38;5;124m'\u001b[39m:\n\u001b[0;32m 240\u001b[0m fid \u001b[38;5;241m=\u001b[39m h5f\u001b[38;5;241m.\u001b[39mopen(name, h5f\u001b[38;5;241m.\u001b[39mACC_RDWR, fapl\u001b[38;5;241m=\u001b[39mfapl)\n",
20
+ "File \u001b[1;32mh5py\\\\_objects.pyx:54\u001b[0m, in \u001b[0;36mh5py._objects.with_phil.wrapper\u001b[1;34m()\u001b[0m\n",
21
+ "File \u001b[1;32mh5py\\\\_objects.pyx:55\u001b[0m, in \u001b[0;36mh5py._objects.with_phil.wrapper\u001b[1;34m()\u001b[0m\n",
22
+ "File \u001b[1;32mh5py\\\\h5f.pyx:102\u001b[0m, in \u001b[0;36mh5py.h5f.open\u001b[1;34m()\u001b[0m\n",
23
+ "\u001b[1;31mOSError\u001b[0m: Unable to synchronously open file (file signature not found)"
24
+ ]
25
+ }
26
+ ],
27
+ "source": [
28
+ "import gradio as gr\n",
29
+ "import numpy as np\n",
30
+ "import timm\n",
31
+ "import torch\n",
32
+ "import torch.nn as nn\n",
33
+ "import torch.nn.functional as F\n",
34
+ "import torchvision.transforms as T\n",
35
+ "import tensorflow as tf\n",
36
+ "from PIL import Image\n",
37
+ "from skimage.transform import resize\n",
38
+ "\n",
39
+ "# ----------- Constants -----------\n",
40
+ "CLASSES = [\"Glioma\", \"Meningioma\", \"No Tumor\", \"Pituitary\"]\n",
41
+ "IMG_SIZE = (224, 224)\n",
42
+ "device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n",
43
+ "\n",
44
+ "# ----------- Segmentation Model Definition -----------\n",
45
+ "swin = timm.create_model('swin_base_patch4_window7_224', pretrained = False, features_only = True)\n",
46
+ "\n",
47
+ "class UNetDecoder(nn.Module):\n",
48
+ " def __init__(self):\n",
49
+ " super().__init__()\n",
50
+ "\n",
51
+ " def conv_block(in_c, out_c):\n",
52
+ " return nn.Sequential(\n",
53
+ " nn.Conv2d(in_c, out_c, kernel_size=3, padding=1),\n",
54
+ " nn.ReLU(inplace=True),\n",
55
+ " nn.Conv2d(out_c, out_c, kernel_size=3, padding=1),\n",
56
+ " nn.ReLU(inplace=True)\n",
57
+ " )\n",
58
+ "\n",
59
+ " self.up3 = nn.ConvTranspose2d(512, 256, kernel_size=2, stride=2)\n",
60
+ " self.dec3 = conv_block(768, 256)\n",
61
+ "\n",
62
+ " self.up2 = nn.ConvTranspose2d(256, 128, kernel_size=2, stride=2)\n",
63
+ " self.dec2 = conv_block(384, 128)\n",
64
+ "\n",
65
+ " self.up1 = nn.ConvTranspose2d(128, 64, kernel_size=2, stride=2)\n",
66
+ " self.dec1 = conv_block(192, 64)\n",
67
+ "\n",
68
+ " self.final = nn.Conv2d(64, 1, kernel_size=1)\n",
69
+ "\n",
70
+ " def forward(self, features):\n",
71
+ " e1, e2, e3, e4 = features # e4 is reduced 512 channels\n",
72
+ "\n",
73
+ " d3 = self.up3(e4)\n",
74
+ " d3 = self.dec3(torch.cat([d3, e3], dim=1)) # concat 256 + 512 = 768\n",
75
+ "\n",
76
+ " d2 = self.up2(d3)\n",
77
+ " d2 = self.dec2(torch.cat([d2, e2], dim=1)) # concat 128 + 256 = 384\n",
78
+ "\n",
79
+ " d1 = self.up1(d2)\n",
80
+ " d1 = self.dec1(torch.cat([d1, e1], dim=1)) # concat 64 + 128 = 192\n",
81
+ "\n",
82
+ " out = F.interpolate(d1, scale_factor=4, mode='bilinear', align_corners=False)\n",
83
+ " return torch.sigmoid(self.final(out))\n",
84
+ " \n",
85
+ "class SwinUNet(nn.Module):\n",
86
+ " def __init__(self):\n",
87
+ " super().__init__()\n",
88
+ " self.encoder = swin\n",
89
+ " self.channel_reducer = nn.Conv2d(1024, 512, kernel_size=1)\n",
90
+ " self.decoder = UNetDecoder()\n",
91
+ "\n",
92
+ " def forward(self, x):\n",
93
+ " if x.shape[1] == 1:\n",
94
+ " x = x.repeat(1, 3, 1, 1)\n",
95
+ "\n",
96
+ " features = self.encoder(x)\n",
97
+ " features = [self._to_channels_first(f) for f in features]\n",
98
+ "\n",
99
+ " features[3] = self.channel_reducer(features[3])\n",
100
+ "\n",
101
+ " output = self.decoder(features)\n",
102
+ " return output\n",
103
+ "\n",
104
+ " def _to_channels_first(self, feature):\n",
105
+ " if feature.dim() == 4:\n",
106
+ " return feature.permute(0, 3, 1, 2).contiguous()\n",
107
+ " elif feature.dim() == 3:\n",
108
+ " B, N, C = feature.shape\n",
109
+ " H = W = int(N ** 0.5)\n",
110
+ " feature = feature.permute(0, 2, 1).contiguous()\n",
111
+ " return feature.view(B, C, H, W)\n",
112
+ " else:\n",
113
+ " raise ValueError(f\"Unexpected feature shape: {feature.shape}\")\n",
114
+ "\n",
115
+ "# ----------- Load Swin-UNet -----------\n",
116
+ "swinunet_model = SwinUNet()\n",
117
+ "swinunet_model.load_state_dict(torch.load(\"./swinunet.pth\", map_location = device))\n",
118
+ "swinunet_model = swinunet_model.to(device)\n",
119
+ "swinunet_model.eval()\n",
120
+ "\n",
121
+ "# ----------- Load Classifier Model -----------\n",
122
+ "classifier_model = tf.keras.models.load_model(\"./cnn-swinunet.keras\")\n",
123
+ "\n",
124
+ "# ----------- Transform -----------\n",
125
+ "transform = T.Compose([\n",
126
+ " T.Resize((224, 224)),\n",
127
+ " T.ToTensor()\n",
128
+ "])\n",
129
+ "\n",
130
+ "# ----------- Segmentation -----------\n",
131
+ "def segmentation(image: Image.Image) -> np.ndarray:\n",
132
+ " # Convert to grayscale and tensor\n",
133
+ " image = image.convert(\"L\")\n",
134
+ " input_tensor = transform(image).unsqueeze(0).to(device) # [1, 1, 224, 224]\n",
135
+ "\n",
136
+ " with torch.no_grad():\n",
137
+ " mask_pred = swinunet_model(input_tensor)\n",
138
+ " mask_pred = F.interpolate(mask_pred, size=(224, 224), mode=\"bilinear\", align_corners=False)\n",
139
+ " mask_pred = (mask_pred > 0.5).float()\n",
140
+ "\n",
141
+ " image_np = input_tensor.squeeze().cpu().numpy() # [224, 224]\n",
142
+ " mask_np = mask_pred.squeeze().cpu().numpy() # [224, 224]\n",
143
+ " \n",
144
+ " combined = np.stack([image_np, mask_np], axis=-1) # [224, 224, 2]\n",
145
+ " return combined\n",
146
+ "\n",
147
+ "def predict(image: Image.Image):\n",
148
+ " combined = segmentation(image)\n",
149
+ " combined = np.expand_dims(combined, axis=0) # Shape: (1, 224, 224, 2)\n",
150
+ "\n",
151
+ " probs = classifier_model.predict(combined)[0]\n",
152
+ "\n",
153
+ " return CLASSES[int(np.argmax(probs, axis=1)[0])]\n",
154
+ "\n",
155
+ "demo = gr.Interface(\n",
156
+ " fn = predict,\n",
157
+ " inputs = gr.Image(type=\"pil\", label=\"Brain MRI\"),\n",
158
+ " outputs = gr.Label(num_top_classes=4),\n",
159
+ " title = \"Brain‑Tumor Classifier (.tflite)\",\n",
160
+ " description = \"Returns: Glioma, Meningioma, No Tumor, Pituitary\"\n",
161
+ ")\n",
162
+ "\n",
163
+ "\n",
164
+ "demo.launch()\n"
165
+ ]
166
+ }
167
+ ],
168
+ "metadata": {
169
+ "kernelspec": {
170
+ "display_name": "main-gpu",
171
+ "language": "python",
172
+ "name": "python3"
173
+ },
174
+ "language_info": {
175
+ "codemirror_mode": {
176
+ "name": "ipython",
177
+ "version": 3
178
+ },
179
+ "file_extension": ".py",
180
+ "mimetype": "text/x-python",
181
+ "name": "python",
182
+ "nbconvert_exporter": "python",
183
+ "pygments_lexer": "ipython3",
184
+ "version": "3.10.16"
185
+ }
186
+ },
187
+ "nbformat": 4,
188
+ "nbformat_minor": 5
189
+ }
app.py CHANGED
@@ -1,35 +1,144 @@
1
  import gradio as gr
2
- import tensorflow as tf
3
  import numpy as np
 
 
 
 
 
 
 
4
  from PIL import Image
 
5
 
6
- interpreter = tf.lite.Interpreter(model_path = "cnn.tflite")
7
- interpreter.allocate_tensors()
8
- input_details = interpreter.get_input_details()
9
- output_details = interpreter.get_output_details()
10
-
11
  CLASSES = ["Glioma", "Meningioma", "No Tumor", "Pituitary"]
12
  IMG_SIZE = (224, 224)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
 
14
- def preprocess(img: Image.Image) -> np.ndarray:
15
- img = img.resize(IMG_SIZE)
16
- arr = np.asarray(img, dtype=np.float32) / 255.0
17
- return np.expand_dims(arr, 0)
18
 
19
- def predict(image):
20
- x = preprocess(image)
21
- interpreter.set_tensor(input_details[0]["index"], x)
22
- interpreter.invoke()
23
- probs = interpreter.get_tensor(output_details[0]["index"])
24
- return CLASSES[int(np.argmax(probs, axis=1)[0])]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
 
26
  demo = gr.Interface(
27
- fn=predict,
28
- inputs=gr.Image(type="pil", label="Brain MRI"),
29
- outputs=gr.Label(num_top_classes=4),
30
- title="Brain‑Tumor Classifier (.tflite)",
31
- description="Returns: Glioma, Meningioma, No Tumor, Pituitary"
32
  )
33
 
34
- if __name__ == "__main__":
 
 
35
  demo.launch()
 
1
  import gradio as gr
 
2
  import numpy as np
3
+ import timm
4
+ import torch
5
+ import torch.nn as nn
6
+ import torch.nn.functional as F
7
+ import torchvision.transforms as T
8
+ import keras
9
+ import traceback
10
  from PIL import Image
11
+ from skimage.transform import resize
12
 
13
+ # ----------- Constants -----------
 
 
 
 
14
  CLASSES = ["Glioma", "Meningioma", "No Tumor", "Pituitary"]
15
  IMG_SIZE = (224, 224)
16
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
17
+
18
+ # ----------- Segmentation Model Definition -----------
19
+ swin = timm.create_model('swin_base_patch4_window7_224', pretrained = False, features_only = True)
20
+
21
+ class UNetDecoder(nn.Module):
22
+ def __init__(self):
23
+ super().__init__()
24
+
25
+ def conv_block(in_c, out_c):
26
+ return nn.Sequential(
27
+ nn.Conv2d(in_c, out_c, kernel_size=3, padding=1),
28
+ nn.ReLU(inplace=True),
29
+ nn.Conv2d(out_c, out_c, kernel_size=3, padding=1),
30
+ nn.ReLU(inplace=True)
31
+ )
32
+
33
+ self.up3 = nn.ConvTranspose2d(512, 256, kernel_size=2, stride=2)
34
+ self.dec3 = conv_block(768, 256)
35
+
36
+ self.up2 = nn.ConvTranspose2d(256, 128, kernel_size=2, stride=2)
37
+ self.dec2 = conv_block(384, 128)
38
+
39
+ self.up1 = nn.ConvTranspose2d(128, 64, kernel_size=2, stride=2)
40
+ self.dec1 = conv_block(192, 64)
41
+
42
+ self.final = nn.Conv2d(64, 1, kernel_size=1)
43
+
44
+ def forward(self, features):
45
+ e1, e2, e3, e4 = features # e4 is reduced 512 channels
46
+
47
+ d3 = self.up3(e4)
48
+ d3 = self.dec3(torch.cat([d3, e3], dim=1)) # concat 256 + 512 = 768
49
+
50
+ d2 = self.up2(d3)
51
+ d2 = self.dec2(torch.cat([d2, e2], dim=1)) # concat 128 + 256 = 384
52
+
53
+ d1 = self.up1(d2)
54
+ d1 = self.dec1(torch.cat([d1, e1], dim=1)) # concat 64 + 128 = 192
55
+
56
+ out = F.interpolate(d1, scale_factor=4, mode='bilinear', align_corners=False)
57
+ return torch.sigmoid(self.final(out))
58
+
59
+ class SwinUNet(nn.Module):
60
+ def __init__(self):
61
+ super().__init__()
62
+ self.encoder = swin
63
+ self.channel_reducer = nn.Conv2d(1024, 512, kernel_size=1)
64
+ self.decoder = UNetDecoder()
65
 
66
+ def forward(self, x):
67
+ if x.shape[1] == 1:
68
+ x = x.repeat(1, 3, 1, 1)
 
69
 
70
+ features = self.encoder(x)
71
+ features = [self._to_channels_first(f) for f in features]
72
+
73
+ features[3] = self.channel_reducer(features[3])
74
+
75
+ output = self.decoder(features)
76
+ return output
77
+
78
+ def _to_channels_first(self, feature):
79
+ if feature.dim() == 4:
80
+ return feature.permute(0, 3, 1, 2).contiguous()
81
+ elif feature.dim() == 3:
82
+ B, N, C = feature.shape
83
+ H = W = int(N ** 0.5)
84
+ feature = feature.permute(0, 2, 1).contiguous()
85
+ return feature.view(B, C, H, W)
86
+ else:
87
+ raise ValueError(f"Unexpected feature shape: {feature.shape}")
88
+
89
+ # ----------- Load Swin-UNet -----------
90
+ swinunet_model = SwinUNet()
91
+ swinunet_model.load_state_dict(torch.load("swinunet.pth", map_location = device))
92
+ swinunet_model = swinunet_model.to(device)
93
+ swinunet_model.eval()
94
+
95
+ # ----------- Load Classifier Model -----------
96
+ classifier_model = keras.models.load_model("cnn-swinunet")
97
+
98
+ # ----------- Transform -----------
99
+ transform = T.Compose([
100
+ T.Resize((224, 224)),
101
+ T.ToTensor()
102
+ ])
103
+
104
+ # ----------- Segmentation -----------
105
+ def segmentation(image: Image.Image) -> np.ndarray:
106
+ # Convert to grayscale and tensor
107
+ image = image.convert("L")
108
+ input_tensor = transform(image).unsqueeze(0).to(device) # [1, 1, 224, 224]
109
+
110
+ with torch.no_grad():
111
+ mask_pred = swinunet_model(input_tensor)
112
+ mask_pred = F.interpolate(mask_pred, size=(224, 224), mode="bilinear", align_corners=False)
113
+ mask_pred = (mask_pred > 0.5).float()
114
+
115
+ image_np = input_tensor.squeeze().cpu().numpy() # [224, 224]
116
+ mask_np = mask_pred.squeeze().cpu().numpy() # [224, 224]
117
+
118
+ combined = np.stack([image_np, mask_np], axis=-1) # [224, 224, 2]
119
+ return combined
120
+
121
+ def predict(image: Image.Image):
122
+ try:
123
+ combined = segmentation(image)
124
+ combined = np.expand_dims(combined, axis=0) # Shape: (1, 224, 224, 2)
125
+
126
+ probs = classifier_model.predict(combined)[0]
127
+ return CLASSES[int(np.argmax(probs))]
128
+ except Exception as e:
129
+ traceback_str = traceback.format_exc()
130
+ print(traceback_str)
131
+ return traceback_str
132
 
133
  demo = gr.Interface(
134
+ fn = predict,
135
+ inputs = gr.Image(type = "pil", label = "Brain MRI"),
136
+ outputs = gr.Label(num_top_classes = 4),
137
+ title = "Brain‑Tumor Net)",
138
+ description = "Returns: Glioma, Meningioma, No Tumor, Pituitary"
139
  )
140
 
141
+ demo.launch()
142
+
143
+ if __name__ == "main":
144
  demo.launch()
cnn-swinunet/config.json ADDED
@@ -0,0 +1 @@
 
 
1
+ {"module": "keras", "class_name": "Sequential", "config": {"name": "sequential_2", "trainable": true, "dtype": {"module": "keras", "class_name": "DTypePolicy", "config": {"name": "float32"}, "registered_name": null, "shared_object_id": 2872295962608}, "layers": [{"module": "keras.layers", "class_name": "InputLayer", "config": {"batch_shape": [null, 224, 224, 2], "dtype": "float32", "sparse": false, "ragged": false, "name": "input_layer_1"}, "registered_name": null}, {"module": "keras.layers", "class_name": "Conv2D", "config": {"name": "conv2d_2", "trainable": true, "dtype": {"module": "keras", "class_name": "DTypePolicy", "config": {"name": "float32"}, "registered_name": null}, "filters": 32, "kernel_size": [3, 3], "strides": [1, 1], "padding": "same", "data_format": "channels_last", "dilation_rate": [1, 1], "groups": 1, "activation": "linear", "use_bias": true, "kernel_initializer": {"module": "keras.initializers", "class_name": "GlorotUniform", "config": {"seed": null}, "registered_name": null}, "bias_initializer": {"module": "keras.initializers", "class_name": "Zeros", "config": {}, "registered_name": null}, "kernel_regularizer": {"module": "keras.regularizers", "class_name": "L2", "config": {"l2": 5e-05}, "registered_name": null}, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "registered_name": null, "build_config": {"input_shape": [null, 224, 224, 2]}}, {"module": "keras.layers", "class_name": "BatchNormalization", "config": {"name": "batch_normalization_2", "trainable": true, "dtype": {"module": "keras", "class_name": "DTypePolicy", "config": {"name": "float32"}, "registered_name": null, "shared_object_id": 2872295962608}, "axis": -1, "momentum": 0.99, "epsilon": 0.001, "center": true, "scale": true, "beta_initializer": {"module": "keras.initializers", "class_name": "Zeros", "config": {}, "registered_name": null}, "gamma_initializer": {"module": "keras.initializers", "class_name": "Ones", "config": {}, "registered_name": null}, "moving_mean_initializer": {"module": "keras.initializers", "class_name": "Zeros", "config": {}, "registered_name": null}, "moving_variance_initializer": {"module": "keras.initializers", "class_name": "Ones", "config": {}, "registered_name": null}, "beta_regularizer": null, "gamma_regularizer": null, "beta_constraint": null, "gamma_constraint": null, "synchronized": false}, "registered_name": null, "build_config": {"input_shape": [null, 224, 224, 32]}}, {"module": "keras.layers", "class_name": "ReLU", "config": {"name": "re_lu_2", "trainable": true, "dtype": {"module": "keras", "class_name": "DTypePolicy", "config": {"name": "float32"}, "registered_name": null, "shared_object_id": 2872295962608}, "max_value": null, "negative_slope": 0.0, "threshold": 0.0}, "registered_name": null}, {"module": "keras.layers", "class_name": "MaxPooling2D", "config": {"name": "max_pooling2d_2", "trainable": true, "dtype": {"module": "keras", "class_name": "DTypePolicy", "config": {"name": "float32"}, "registered_name": null, "shared_object_id": 2872295962608}, "pool_size": [2, 2], "padding": "valid", "strides": [2, 2], "data_format": "channels_last"}, "registered_name": null}, {"module": "keras.layers", "class_name": "Conv2D", "config": {"name": "conv2d_3", "trainable": true, "dtype": {"module": "keras", "class_name": "DTypePolicy", "config": {"name": "float32"}, "registered_name": null, "shared_object_id": 2872295962608}, "filters": 64, "kernel_size": [3, 3], "strides": [1, 1], "padding": "same", "data_format": "channels_last", "dilation_rate": [1, 1], "groups": 1, "activation": "linear", "use_bias": true, "kernel_initializer": {"module": "keras.initializers", "class_name": "GlorotUniform", "config": {"seed": null}, "registered_name": null}, "bias_initializer": {"module": "keras.initializers", "class_name": "Zeros", "config": {}, "registered_name": null}, "kernel_regularizer": {"module": "keras.regularizers", "class_name": "L2", "config": {"l2": 5e-05}, "registered_name": null}, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "registered_name": null, "build_config": {"input_shape": [null, 112, 112, 32]}}, {"module": "keras.layers", "class_name": "BatchNormalization", "config": {"name": "batch_normalization_3", "trainable": true, "dtype": {"module": "keras", "class_name": "DTypePolicy", "config": {"name": "float32"}, "registered_name": null, "shared_object_id": 2872295962608}, "axis": -1, "momentum": 0.99, "epsilon": 0.001, "center": true, "scale": true, "beta_initializer": {"module": "keras.initializers", "class_name": "Zeros", "config": {}, "registered_name": null}, "gamma_initializer": {"module": "keras.initializers", "class_name": "Ones", "config": {}, "registered_name": null}, "moving_mean_initializer": {"module": "keras.initializers", "class_name": "Zeros", "config": {}, "registered_name": null}, "moving_variance_initializer": {"module": "keras.initializers", "class_name": "Ones", "config": {}, "registered_name": null}, "beta_regularizer": null, "gamma_regularizer": null, "beta_constraint": null, "gamma_constraint": null, "synchronized": false}, "registered_name": null, "build_config": {"input_shape": [null, 112, 112, 64]}}, {"module": "keras.layers", "class_name": "ReLU", "config": {"name": "re_lu_3", "trainable": true, "dtype": {"module": "keras", "class_name": "DTypePolicy", "config": {"name": "float32"}, "registered_name": null, "shared_object_id": 2872295962608}, "max_value": null, "negative_slope": 0.0, "threshold": 0.0}, "registered_name": null}, {"module": "keras.layers", "class_name": "MaxPooling2D", "config": {"name": "max_pooling2d_3", "trainable": true, "dtype": {"module": "keras", "class_name": "DTypePolicy", "config": {"name": "float32"}, "registered_name": null, "shared_object_id": 2872295962608}, "pool_size": [2, 2], "padding": "valid", "strides": [2, 2], "data_format": "channels_last"}, "registered_name": null}, {"module": "keras.layers", "class_name": "Conv2D", "config": {"name": "conv2d_4", "trainable": true, "dtype": {"module": "keras", "class_name": "DTypePolicy", "config": {"name": "float32"}, "registered_name": null, "shared_object_id": 2872295962608}, "filters": 128, "kernel_size": [3, 3], "strides": [1, 1], "padding": "same", "data_format": "channels_last", "dilation_rate": [1, 1], "groups": 1, "activation": "linear", "use_bias": true, "kernel_initializer": {"module": "keras.initializers", "class_name": "GlorotUniform", "config": {"seed": null}, "registered_name": null}, "bias_initializer": {"module": "keras.initializers", "class_name": "Zeros", "config": {}, "registered_name": null}, "kernel_regularizer": {"module": "keras.regularizers", "class_name": "L2", "config": {"l2": 5e-05}, "registered_name": null}, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "registered_name": null, "build_config": {"input_shape": [null, 56, 56, 64]}}, {"module": "keras.layers", "class_name": "BatchNormalization", "config": {"name": "batch_normalization_4", "trainable": true, "dtype": {"module": "keras", "class_name": "DTypePolicy", "config": {"name": "float32"}, "registered_name": null, "shared_object_id": 2872295962608}, "axis": -1, "momentum": 0.99, "epsilon": 0.001, "center": true, "scale": true, "beta_initializer": {"module": "keras.initializers", "class_name": "Zeros", "config": {}, "registered_name": null}, "gamma_initializer": {"module": "keras.initializers", "class_name": "Ones", "config": {}, "registered_name": null}, "moving_mean_initializer": {"module": "keras.initializers", "class_name": "Zeros", "config": {}, "registered_name": null}, "moving_variance_initializer": {"module": "keras.initializers", "class_name": "Ones", "config": {}, "registered_name": null}, "beta_regularizer": null, "gamma_regularizer": null, "beta_constraint": null, "gamma_constraint": null, "synchronized": false}, "registered_name": null, "build_config": {"input_shape": [null, 56, 56, 128]}}, {"module": "keras.layers", "class_name": "ReLU", "config": {"name": "re_lu_4", "trainable": true, "dtype": {"module": "keras", "class_name": "DTypePolicy", "config": {"name": "float32"}, "registered_name": null, "shared_object_id": 2872295962608}, "max_value": null, "negative_slope": 0.0, "threshold": 0.0}, "registered_name": null}, {"module": "keras.layers", "class_name": "MaxPooling2D", "config": {"name": "max_pooling2d_4", "trainable": true, "dtype": {"module": "keras", "class_name": "DTypePolicy", "config": {"name": "float32"}, "registered_name": null, "shared_object_id": 2872295962608}, "pool_size": [2, 2], "padding": "valid", "strides": [2, 2], "data_format": "channels_last"}, "registered_name": null}, {"module": "keras.layers", "class_name": "Conv2D", "config": {"name": "conv2d_5", "trainable": true, "dtype": {"module": "keras", "class_name": "DTypePolicy", "config": {"name": "float32"}, "registered_name": null, "shared_object_id": 2872295962608}, "filters": 128, "kernel_size": [3, 3], "strides": [1, 1], "padding": "same", "data_format": "channels_last", "dilation_rate": [1, 1], "groups": 1, "activation": "linear", "use_bias": true, "kernel_initializer": {"module": "keras.initializers", "class_name": "GlorotUniform", "config": {"seed": null}, "registered_name": null}, "bias_initializer": {"module": "keras.initializers", "class_name": "Zeros", "config": {}, "registered_name": null}, "kernel_regularizer": {"module": "keras.regularizers", "class_name": "L2", "config": {"l2": 5e-05}, "registered_name": null}, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "registered_name": null, "build_config": {"input_shape": [null, 28, 28, 128]}}, {"module": "keras.layers", "class_name": "BatchNormalization", "config": {"name": "batch_normalization_5", "trainable": true, "dtype": {"module": "keras", "class_name": "DTypePolicy", "config": {"name": "float32"}, "registered_name": null, "shared_object_id": 2872295962608}, "axis": -1, "momentum": 0.99, "epsilon": 0.001, "center": true, "scale": true, "beta_initializer": {"module": "keras.initializers", "class_name": "Zeros", "config": {}, "registered_name": null}, "gamma_initializer": {"module": "keras.initializers", "class_name": "Ones", "config": {}, "registered_name": null}, "moving_mean_initializer": {"module": "keras.initializers", "class_name": "Zeros", "config": {}, "registered_name": null}, "moving_variance_initializer": {"module": "keras.initializers", "class_name": "Ones", "config": {}, "registered_name": null}, "beta_regularizer": null, "gamma_regularizer": null, "beta_constraint": null, "gamma_constraint": null, "synchronized": false}, "registered_name": null, "build_config": {"input_shape": [null, 28, 28, 128]}}, {"module": "keras.layers", "class_name": "ReLU", "config": {"name": "re_lu_5", "trainable": true, "dtype": {"module": "keras", "class_name": "DTypePolicy", "config": {"name": "float32"}, "registered_name": null, "shared_object_id": 2872295962608}, "max_value": null, "negative_slope": 0.0, "threshold": 0.0}, "registered_name": null}, {"module": "keras.layers", "class_name": "MaxPooling2D", "config": {"name": "max_pooling2d_5", "trainable": true, "dtype": {"module": "keras", "class_name": "DTypePolicy", "config": {"name": "float32"}, "registered_name": null, "shared_object_id": 2872295962608}, "pool_size": [2, 2], "padding": "valid", "strides": [2, 2], "data_format": "channels_last"}, "registered_name": null}, {"module": "keras.layers", "class_name": "Flatten", "config": {"name": "flatten", "trainable": true, "dtype": {"module": "keras", "class_name": "DTypePolicy", "config": {"name": "float32"}, "registered_name": null, "shared_object_id": 2872295962608}, "data_format": "channels_last"}, "registered_name": null, "build_config": {"input_shape": [null, 14, 14, 128]}}, {"module": "keras.layers", "class_name": "Dense", "config": {"name": "dense", "trainable": true, "dtype": {"module": "keras", "class_name": "DTypePolicy", "config": {"name": "float32"}, "registered_name": null, "shared_object_id": 2872295962608}, "units": 128, "activation": "linear", "use_bias": true, "kernel_initializer": {"module": "keras.initializers", "class_name": "GlorotUniform", "config": {"seed": null}, "registered_name": null}, "bias_initializer": {"module": "keras.initializers", "class_name": "Zeros", "config": {}, "registered_name": null}, "kernel_regularizer": {"module": "keras.regularizers", "class_name": "L2", "config": {"l2": 5e-05}, "registered_name": null}, "bias_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "registered_name": null, "build_config": {"input_shape": [null, 25088]}}, {"module": "keras.layers", "class_name": "BatchNormalization", "config": {"name": "batch_normalization_6", "trainable": true, "dtype": {"module": "keras", "class_name": "DTypePolicy", "config": {"name": "float32"}, "registered_name": null, "shared_object_id": 2872295962608}, "axis": -1, "momentum": 0.99, "epsilon": 0.001, "center": true, "scale": true, "beta_initializer": {"module": "keras.initializers", "class_name": "Zeros", "config": {}, "registered_name": null}, "gamma_initializer": {"module": "keras.initializers", "class_name": "Ones", "config": {}, "registered_name": null}, "moving_mean_initializer": {"module": "keras.initializers", "class_name": "Zeros", "config": {}, "registered_name": null}, "moving_variance_initializer": {"module": "keras.initializers", "class_name": "Ones", "config": {}, "registered_name": null}, "beta_regularizer": null, "gamma_regularizer": null, "beta_constraint": null, "gamma_constraint": null, "synchronized": false}, "registered_name": null, "build_config": {"input_shape": [null, 128]}}, {"module": "keras.layers", "class_name": "ReLU", "config": {"name": "re_lu_6", "trainable": true, "dtype": {"module": "keras", "class_name": "DTypePolicy", "config": {"name": "float32"}, "registered_name": null, "shared_object_id": 2872295962608}, "max_value": null, "negative_slope": 0.0, "threshold": 0.0}, "registered_name": null}, {"module": "keras.layers", "class_name": "Dropout", "config": {"name": "dropout", "trainable": true, "dtype": {"module": "keras", "class_name": "DTypePolicy", "config": {"name": "float32"}, "registered_name": null, "shared_object_id": 2872295962608}, "rate": 0.4, "seed": null, "noise_shape": null}, "registered_name": null}, {"module": "keras.layers", "class_name": "Dense", "config": {"name": "dense_1", "trainable": true, "dtype": {"module": "keras", "class_name": "DTypePolicy", "config": {"name": "float32"}, "registered_name": null, "shared_object_id": 2872295962608}, "units": 4, "activation": "softmax", "use_bias": true, "kernel_initializer": {"module": "keras.initializers", "class_name": "GlorotUniform", "config": {"seed": null}, "registered_name": null}, "bias_initializer": {"module": "keras.initializers", "class_name": "Zeros", "config": {}, "registered_name": null}, "kernel_regularizer": null, "bias_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "registered_name": null, "build_config": {"input_shape": [null, 128]}}], "build_input_shape": [null, 224, 224, 2]}, "registered_name": null, "build_config": {"input_shape": [null, 224, 224, 2]}, "compile_config": {"optimizer": {"module": "keras.optimizers", "class_name": "Adam", "config": {"name": "adam", "learning_rate": {"module": "keras.optimizers.schedules", "class_name": "ExponentialDecay", "config": {"initial_learning_rate": 0.0001, "decay_steps": 1000, "decay_rate": 0.95, "staircase": false, "name": "ExponentialDecay"}, "registered_name": null}, "weight_decay": null, "clipnorm": null, "global_clipnorm": null, "clipvalue": null, "use_ema": false, "ema_momentum": 0.99, "ema_overwrite_frequency": null, "loss_scale_factor": null, "gradient_accumulation_steps": null, "beta_1": 0.9, "beta_2": 0.999, "epsilon": 1e-07, "amsgrad": false}, "registered_name": null}, "loss": "categorical_crossentropy", "loss_weights": null, "metrics": [{"module": "keras.metrics", "class_name": "Recall", "config": {"name": "recall", "dtype": "float32", "thresholds": null, "top_k": null, "class_id": null}, "registered_name": null}], "weighted_metrics": null, "run_eagerly": false, "steps_per_execution": 1, "jit_compile": false}}
cnn-swinunet/metadata.json ADDED
@@ -0,0 +1 @@
 
 
1
+ {"keras_version": "3.9.2", "date_saved": "2025-06-01@08:04:02"}
cnn.tflite → cnn-swinunet/model.weights.h5 RENAMED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:d621e23d2e705ed9a44696e02be7d93d312ba6ed3e21360e3795973cde31fb49
3
- size 51427444
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:21a824cb97431d12f42cc1f154ef073566ad84b933b002b97bd0911a8d04f7d1
3
+ size 41524048
requirements.txt CHANGED
@@ -1,4 +1,8 @@
1
- tensorflow==2.15.0
2
  gradio>=4.31,<5
3
- pillow
4
- numpy
 
 
 
 
 
 
 
1
  gradio>=4.31,<5
2
+ numpy==1.26.4
3
+ timm==1.0.15
4
+ torch==2.6.0
5
+ torchvision==0.21.0
6
+ keras==3.9.2
7
+ pillow==10.4.0
8
+ scikit-image==0.25.2
swinunet.pth ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:043efac3101c1b1ad3d73b4d8f043bb2e8058f1ebe8e860009de418f2d8e07c9
3
+ size 364350107