Mikecode123 commited on
Commit
31986d9
·
verified ·
1 Parent(s): 9d729a1

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +342 -111
app.py CHANGED
@@ -1,10 +1,11 @@
1
  # =========================================
2
  # IMPORTS
3
  # =========================================
4
- import io
5
  import cv2
6
  import nibabel as nib
7
  import numpy as np
 
8
  import torch
9
  import torch.nn as nn
10
  import torchvision.models as models
@@ -33,42 +34,67 @@ print("Using device:", DEVICE)
33
  # FASTAPI
34
  # =========================================
35
  app = FastAPI(
36
- title="Parkinsons DATSCAN Ensemble API",
37
  version="1.0"
38
  )
39
 
40
  # =========================================
41
- # PREPROCESSING
42
  # =========================================
43
  def load_nifti_from_bytes(file_bytes):
44
- temp_path = "temp.nii"
 
45
 
46
  with open(temp_path, "wb") as f:
47
  f.write(file_bytes)
48
 
49
  volume = nib.load(temp_path).get_fdata()
 
50
  volume = np.squeeze(volume)
51
 
52
  return volume
53
 
54
-
 
 
55
  def preprocess_2d(volume):
 
56
  depth = volume.shape[2]
57
 
58
- idx1 = np.linspace(0, depth//3 - 1, 10).astype(int)
59
- idx2 = np.linspace(depth//3, 2*depth//3 - 1, 10).astype(int)
60
- idx3 = np.linspace(2*depth//3, depth - 1, 12).astype(int)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61
 
62
  def make_channel(indices):
 
63
  slices = []
64
 
65
  for i in indices:
 
66
  sl = volume[:, :, i]
67
 
68
  sl = sl - sl.min()
69
  sl = sl / (sl.max() + 1e-6)
70
 
71
- sl = cv2.resize(sl, (IMG_SIZE, IMG_SIZE))
 
 
 
 
72
  slices.append(sl)
73
 
74
  return np.mean(slices, axis=0)
@@ -79,50 +105,67 @@ def preprocess_2d(volume):
79
 
80
  img = np.stack([r, g, b], axis=0)
81
 
82
- return torch.tensor(img, dtype=torch.float32).unsqueeze(0)
 
 
 
 
 
83
 
 
84
 
 
 
 
85
  def preprocess_3d(volume):
 
86
  depth = volume.shape[2]
87
 
88
- indices = np.linspace(0, depth - 1, NUM_SLICES).astype(int)
 
 
 
 
89
 
90
  slices = []
91
 
92
  for i in indices:
 
93
  sl = volume[:, :, i]
94
 
95
  sl = sl - sl.min()
96
  sl = sl / (sl.max() + 1e-6)
97
 
98
- sl = cv2.resize(sl, (IMG_SIZE, IMG_SIZE))
 
 
 
 
99
  slices.append(sl)
100
 
101
  vol = np.stack(slices)
102
 
103
- vol = torch.tensor(vol, dtype=torch.float32)
104
-
105
- vol = vol.unsqueeze(0).unsqueeze(0)
 
106
 
107
- return vol
 
108
 
 
109
 
110
  # =========================================
111
- # DENSENET MODELS
112
  # =========================================
113
  class DenseNet121Model(nn.Module):
 
114
  def __init__(self):
115
- super().__init__()
116
 
117
- self.base = models.densenet121(weights=None)
118
 
119
- self.base.features.conv0 = nn.Conv2d(
120
- 3,
121
- 64,
122
- kernel_size=7,
123
- stride=2,
124
- padding=3,
125
- bias=False
126
  )
127
 
128
  self.base.classifier = nn.Linear(
@@ -131,22 +174,20 @@ class DenseNet121Model(nn.Module):
131
  )
132
 
133
  def forward(self, x):
134
- return self.base(x)
135
 
 
136
 
 
 
 
137
  class DenseNet169Model(nn.Module):
 
138
  def __init__(self):
139
- super().__init__()
140
 
141
- self.base = models.densenet169(weights=None)
142
 
143
- self.base.features.conv0 = nn.Conv2d(
144
- 3,
145
- 64,
146
- kernel_size=7,
147
- stride=2,
148
- padding=3,
149
- bias=False
150
  )
151
 
152
  self.base.classifier = nn.Linear(
@@ -155,22 +196,20 @@ class DenseNet169Model(nn.Module):
155
  )
156
 
157
  def forward(self, x):
158
- return self.base(x)
159
 
 
160
 
 
 
 
161
  class DenseNet201Model(nn.Module):
 
162
  def __init__(self):
163
- super().__init__()
164
 
165
- self.base = models.densenet201(weights=None)
166
 
167
- self.base.features.conv0 = nn.Conv2d(
168
- 3,
169
- 64,
170
- kernel_size=7,
171
- stride=2,
172
- padding=3,
173
- bias=False
174
  )
175
 
176
  self.base.classifier = nn.Linear(
@@ -179,188 +218,380 @@ class DenseNet201Model(nn.Module):
179
  )
180
 
181
  def forward(self, x):
182
- return self.base(x)
183
 
 
184
 
185
  # =========================================
186
  # 3D CNN
187
  # =========================================
188
  class CNN3D(nn.Module):
 
189
  def __init__(self):
 
190
  super().__init__()
191
 
192
  self.net = nn.Sequential(
193
 
194
- nn.Conv3d(1, 16, 3, padding=1),
 
 
 
 
 
 
195
  nn.ReLU(),
 
196
  nn.MaxPool3d(2),
197
 
198
- nn.Conv3d(16, 32, 3, padding=1),
 
 
 
 
 
 
199
  nn.ReLU(),
 
200
  nn.MaxPool3d(2),
201
 
202
- nn.Conv3d(32, 64, 3, padding=1),
 
 
 
 
 
 
203
  nn.ReLU(),
204
- nn.MaxPool3d(2)
205
 
 
206
  )
207
 
208
  self.fc = nn.Sequential(
209
- nn.Linear(64 * 4 * 16 * 16, 256),
 
 
 
 
 
210
  nn.ReLU(),
 
211
  nn.Dropout(0.3),
212
- nn.Linear(256, NUM_CLASSES)
 
 
 
 
213
  )
214
 
215
  def forward(self, x):
 
216
  x = self.net(x)
217
- x = x.view(x.size(0), -1)
218
- return self.fc(x)
219
 
 
 
 
 
 
 
 
 
220
 
221
  # =========================================
222
  # LOAD MODELS
223
  # =========================================
224
  def load_model(model, path):
 
 
 
 
 
 
 
 
225
  model.load_state_dict(
226
- torch.load(path, map_location=DEVICE)
 
227
  )
228
 
229
  model.to(DEVICE)
 
230
  model.eval()
231
 
232
- print(f"Loaded: {path}")
233
 
234
  return model
235
 
 
 
 
 
 
 
 
 
 
 
 
 
236
 
237
- model121 = load_model(DenseNet121Model(), "densenet121.pth")
238
- model169 = load_model(DenseNet169Model(), "densenet169.pth")
239
- model201 = load_model(DenseNet201Model(), "densenet201.pth")
240
- model3d = load_model(CNN3D(), "cnn3d.pth")
241
 
 
 
 
 
242
 
243
  # =========================================
244
- # PREDICTION HELPERS
245
  # =========================================
246
  def predict_model(model, tensor):
 
247
  tensor = tensor.to(DEVICE)
248
 
249
  with torch.no_grad():
 
250
  out = model(tensor)
251
 
252
- probs = torch.softmax(out, dim=1)[0]
 
 
 
253
 
254
- pred_idx = torch.argmax(probs).item()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
255
 
256
- return {
257
- "prediction": LABELS[pred_idx],
258
- "class_id": pred_idx,
259
- "confidence": round(float(probs[pred_idx]) * 100, 2),
260
  "probabilities": {
261
- LABELS[i]: round(float(probs[i]) * 100, 2)
 
 
 
 
 
 
 
 
262
  for i in range(NUM_CLASSES)
263
  }
264
- }, probs
265
 
 
266
 
267
  # =========================================
268
  # ROOT
269
  # =========================================
270
  @app.get("/")
271
  def home():
 
272
  return {
273
- "message": "Parkinson DATSCAN Ensemble API Running",
274
- "classes": LABELS
275
- }
276
 
 
 
 
 
 
 
277
 
278
  # =========================================
279
- # INDIVIDUAL ENDPOINTS
280
  # =========================================
281
  @app.post("/predict/densenet121")
282
- async def predict_121(file: UploadFile = File(...)):
 
 
 
 
 
 
 
 
283
 
284
- volume = load_nifti_from_bytes(await file.read())
285
  tensor = preprocess_2d(volume)
286
 
287
- result, _ = predict_model(model121, tensor)
 
 
 
288
 
289
  return JSONResponse(result)
290
 
291
-
 
 
292
  @app.post("/predict/densenet169")
293
- async def predict_169(file: UploadFile = File(...)):
 
 
 
 
 
 
 
 
294
 
295
- volume = load_nifti_from_bytes(await file.read())
296
  tensor = preprocess_2d(volume)
297
 
298
- result, _ = predict_model(model169, tensor)
 
 
 
299
 
300
  return JSONResponse(result)
301
 
302
-
 
 
303
  @app.post("/predict/densenet201")
304
- async def predict_201(file: UploadFile = File(...)):
 
 
 
 
 
 
 
 
305
 
306
- volume = load_nifti_from_bytes(await file.read())
307
  tensor = preprocess_2d(volume)
308
 
309
- result, _ = predict_model(model201, tensor)
 
 
 
310
 
311
  return JSONResponse(result)
312
 
313
-
 
 
314
  @app.post("/predict/cnn3d")
315
- async def predict_3d(file: UploadFile = File(...)):
 
 
 
 
 
 
 
 
316
 
317
- volume = load_nifti_from_bytes(await file.read())
318
  tensor = preprocess_3d(volume)
319
 
320
- result, _ = predict_model(model3d, tensor)
 
 
 
321
 
322
  return JSONResponse(result)
323
 
324
-
325
  # =========================================
326
- # ENSEMBLE
327
  # =========================================
328
  @app.post("/predict/ensemble")
329
- async def predict_ensemble(file: UploadFile = File(...)):
 
 
330
 
331
- volume = load_nifti_from_bytes(await file.read())
 
 
 
 
332
 
333
  tensor2d = preprocess_2d(volume)
 
334
  tensor3d = preprocess_3d(volume)
335
 
336
- r121, p121 = predict_model(model121, tensor2d)
337
- r169, p169 = predict_model(model169, tensor2d)
338
- r201, p201 = predict_model(model201, tensor2d)
339
- r3d, p3d = predict_model(model3d, tensor3d)
 
 
 
 
 
 
 
 
 
 
340
 
341
- avg_probs = (p121 + p169 + p201 + p3d) / 4
 
 
 
342
 
343
- pred_idx = torch.argmax(avg_probs).item()
 
 
 
 
 
344
 
345
- return {
 
 
346
 
347
- "ensemble_prediction": LABELS[pred_idx],
348
 
349
- "ensemble_confidence": round(
350
- float(avg_probs[pred_idx]) * 100,
351
- 2
352
- ),
 
 
 
 
 
 
353
 
354
  "ensemble_probabilities": {
355
- LABELS[i]: round(float(avg_probs[i]) * 100, 2)
 
 
 
 
 
 
 
 
356
  for i in range(NUM_CLASSES)
357
  },
358
 
359
  "individual_models": {
360
 
361
- "DenseNet121": r121,
362
- "DenseNet169": r169,
363
- "DenseNet201": r201,
364
- "CNN3D": r3d
 
 
 
 
 
 
 
365
  }
366
- }
 
 
 
1
  # =========================================
2
  # IMPORTS
3
  # =========================================
4
+ import os
5
  import cv2
6
  import nibabel as nib
7
  import numpy as np
8
+
9
  import torch
10
  import torch.nn as nn
11
  import torchvision.models as models
 
34
  # FASTAPI
35
  # =========================================
36
  app = FastAPI(
37
+ title="Parkinson DATSCAN Ensemble API",
38
  version="1.0"
39
  )
40
 
41
  # =========================================
42
+ # LOAD NIFTI
43
  # =========================================
44
  def load_nifti_from_bytes(file_bytes):
45
+
46
+ temp_path = "temp_upload.nii"
47
 
48
  with open(temp_path, "wb") as f:
49
  f.write(file_bytes)
50
 
51
  volume = nib.load(temp_path).get_fdata()
52
+
53
  volume = np.squeeze(volume)
54
 
55
  return volume
56
 
57
+ # =========================================
58
+ # PREPROCESS 2D
59
+ # =========================================
60
  def preprocess_2d(volume):
61
+
62
  depth = volume.shape[2]
63
 
64
+ idx1 = np.linspace(
65
+ 0,
66
+ depth // 3 - 1,
67
+ 10
68
+ ).astype(int)
69
+
70
+ idx2 = np.linspace(
71
+ depth // 3,
72
+ 2 * depth // 3 - 1,
73
+ 10
74
+ ).astype(int)
75
+
76
+ idx3 = np.linspace(
77
+ 2 * depth // 3,
78
+ depth - 1,
79
+ 12
80
+ ).astype(int)
81
 
82
  def make_channel(indices):
83
+
84
  slices = []
85
 
86
  for i in indices:
87
+
88
  sl = volume[:, :, i]
89
 
90
  sl = sl - sl.min()
91
  sl = sl / (sl.max() + 1e-6)
92
 
93
+ sl = cv2.resize(
94
+ sl,
95
+ (IMG_SIZE, IMG_SIZE)
96
+ )
97
+
98
  slices.append(sl)
99
 
100
  return np.mean(slices, axis=0)
 
105
 
106
  img = np.stack([r, g, b], axis=0)
107
 
108
+ tensor = torch.tensor(
109
+ img,
110
+ dtype=torch.float32
111
+ )
112
+
113
+ tensor = tensor.unsqueeze(0)
114
 
115
+ return tensor
116
 
117
+ # =========================================
118
+ # PREPROCESS 3D
119
+ # =========================================
120
  def preprocess_3d(volume):
121
+
122
  depth = volume.shape[2]
123
 
124
+ indices = np.linspace(
125
+ 0,
126
+ depth - 1,
127
+ NUM_SLICES
128
+ ).astype(int)
129
 
130
  slices = []
131
 
132
  for i in indices:
133
+
134
  sl = volume[:, :, i]
135
 
136
  sl = sl - sl.min()
137
  sl = sl / (sl.max() + 1e-6)
138
 
139
+ sl = cv2.resize(
140
+ sl,
141
+ (IMG_SIZE, IMG_SIZE)
142
+ )
143
+
144
  slices.append(sl)
145
 
146
  vol = np.stack(slices)
147
 
148
+ tensor = torch.tensor(
149
+ vol,
150
+ dtype=torch.float32
151
+ )
152
 
153
+ tensor = tensor.unsqueeze(0)
154
+ tensor = tensor.unsqueeze(0)
155
 
156
+ return tensor
157
 
158
  # =========================================
159
+ # DENSENET121
160
  # =========================================
161
  class DenseNet121Model(nn.Module):
162
+
163
  def __init__(self):
 
164
 
165
+ super().__init__()
166
 
167
+ self.base = models.densenet121(
168
+ weights=None
 
 
 
 
 
169
  )
170
 
171
  self.base.classifier = nn.Linear(
 
174
  )
175
 
176
  def forward(self, x):
 
177
 
178
+ return self.base(x)
179
 
180
+ # =========================================
181
+ # DENSENET169
182
+ # =========================================
183
  class DenseNet169Model(nn.Module):
184
+
185
  def __init__(self):
 
186
 
187
+ super().__init__()
188
 
189
+ self.base = models.densenet169(
190
+ weights=None
 
 
 
 
 
191
  )
192
 
193
  self.base.classifier = nn.Linear(
 
196
  )
197
 
198
  def forward(self, x):
 
199
 
200
+ return self.base(x)
201
 
202
+ # =========================================
203
+ # DENSENET201
204
+ # =========================================
205
  class DenseNet201Model(nn.Module):
206
+
207
  def __init__(self):
 
208
 
209
+ super().__init__()
210
 
211
+ self.base = models.densenet201(
212
+ weights=None
 
 
 
 
 
213
  )
214
 
215
  self.base.classifier = nn.Linear(
 
218
  )
219
 
220
  def forward(self, x):
 
221
 
222
+ return self.base(x)
223
 
224
  # =========================================
225
  # 3D CNN
226
  # =========================================
227
  class CNN3D(nn.Module):
228
+
229
  def __init__(self):
230
+
231
  super().__init__()
232
 
233
  self.net = nn.Sequential(
234
 
235
+ nn.Conv3d(
236
+ 1,
237
+ 16,
238
+ kernel_size=3,
239
+ padding=1
240
+ ),
241
+
242
  nn.ReLU(),
243
+
244
  nn.MaxPool3d(2),
245
 
246
+ nn.Conv3d(
247
+ 16,
248
+ 32,
249
+ kernel_size=3,
250
+ padding=1
251
+ ),
252
+
253
  nn.ReLU(),
254
+
255
  nn.MaxPool3d(2),
256
 
257
+ nn.Conv3d(
258
+ 32,
259
+ 64,
260
+ kernel_size=3,
261
+ padding=1
262
+ ),
263
+
264
  nn.ReLU(),
 
265
 
266
+ nn.MaxPool3d(2)
267
  )
268
 
269
  self.fc = nn.Sequential(
270
+
271
+ nn.Linear(
272
+ 64 * 4 * 16 * 16,
273
+ 256
274
+ ),
275
+
276
  nn.ReLU(),
277
+
278
  nn.Dropout(0.3),
279
+
280
+ nn.Linear(
281
+ 256,
282
+ NUM_CLASSES
283
+ )
284
  )
285
 
286
  def forward(self, x):
287
+
288
  x = self.net(x)
 
 
289
 
290
+ x = x.view(
291
+ x.size(0),
292
+ -1
293
+ )
294
+
295
+ x = self.fc(x)
296
+
297
+ return x
298
 
299
  # =========================================
300
  # LOAD MODELS
301
  # =========================================
302
  def load_model(model, path):
303
+
304
+ print(f"Loading {path}")
305
+
306
+ state = torch.load(
307
+ path,
308
+ map_location=DEVICE
309
+ )
310
+
311
  model.load_state_dict(
312
+ state,
313
+ strict=False
314
  )
315
 
316
  model.to(DEVICE)
317
+
318
  model.eval()
319
 
320
+ print(f"Loaded {path}")
321
 
322
  return model
323
 
324
+ # =========================================
325
+ # LOAD ALL
326
+ # =========================================
327
+ model121 = load_model(
328
+ DenseNet121Model(),
329
+ "densenet121.pth"
330
+ )
331
+
332
+ model169 = load_model(
333
+ DenseNet169Model(),
334
+ "densenet169.pth"
335
+ )
336
 
337
+ model201 = load_model(
338
+ DenseNet201Model(),
339
+ "densenet201.pth"
340
+ )
341
 
342
+ model3d = load_model(
343
+ CNN3D(),
344
+ "cnn3d.pth"
345
+ )
346
 
347
  # =========================================
348
+ # SINGLE PREDICTION
349
  # =========================================
350
  def predict_model(model, tensor):
351
+
352
  tensor = tensor.to(DEVICE)
353
 
354
  with torch.no_grad():
355
+
356
  out = model(tensor)
357
 
358
+ probs = torch.softmax(
359
+ out,
360
+ dim=1
361
+ )[0]
362
 
363
+ pred_idx = torch.argmax(
364
+ probs
365
+ ).item()
366
+
367
+ result = {
368
+
369
+ "prediction":
370
+ LABELS[pred_idx],
371
+
372
+ "class_id":
373
+ pred_idx,
374
+
375
+ "confidence":
376
+ round(
377
+ float(
378
+ probs[pred_idx]
379
+ ) * 100,
380
+ 2
381
+ ),
382
 
 
 
 
 
383
  "probabilities": {
384
+
385
+ LABELS[i]:
386
+ round(
387
+ float(
388
+ probs[i]
389
+ ) * 100,
390
+ 2
391
+ )
392
+
393
  for i in range(NUM_CLASSES)
394
  }
395
+ }
396
 
397
+ return result, probs
398
 
399
  # =========================================
400
  # ROOT
401
  # =========================================
402
  @app.get("/")
403
  def home():
404
+
405
  return {
 
 
 
406
 
407
+ "message":
408
+ "Parkinson DATSCAN Ensemble API Running",
409
+
410
+ "classes":
411
+ LABELS
412
+ }
413
 
414
  # =========================================
415
+ # DENSENET121 ENDPOINT
416
  # =========================================
417
  @app.post("/predict/densenet121")
418
+ async def predict_121(
419
+ file: UploadFile = File(...)
420
+ ):
421
+
422
+ file_bytes = await file.read()
423
+
424
+ volume = load_nifti_from_bytes(
425
+ file_bytes
426
+ )
427
 
 
428
  tensor = preprocess_2d(volume)
429
 
430
+ result, _ = predict_model(
431
+ model121,
432
+ tensor
433
+ )
434
 
435
  return JSONResponse(result)
436
 
437
+ # =========================================
438
+ # DENSENET169 ENDPOINT
439
+ # =========================================
440
  @app.post("/predict/densenet169")
441
+ async def predict_169(
442
+ file: UploadFile = File(...)
443
+ ):
444
+
445
+ file_bytes = await file.read()
446
+
447
+ volume = load_nifti_from_bytes(
448
+ file_bytes
449
+ )
450
 
 
451
  tensor = preprocess_2d(volume)
452
 
453
+ result, _ = predict_model(
454
+ model169,
455
+ tensor
456
+ )
457
 
458
  return JSONResponse(result)
459
 
460
+ # =========================================
461
+ # DENSENET201 ENDPOINT
462
+ # =========================================
463
  @app.post("/predict/densenet201")
464
+ async def predict_201(
465
+ file: UploadFile = File(...)
466
+ ):
467
+
468
+ file_bytes = await file.read()
469
+
470
+ volume = load_nifti_from_bytes(
471
+ file_bytes
472
+ )
473
 
 
474
  tensor = preprocess_2d(volume)
475
 
476
+ result, _ = predict_model(
477
+ model201,
478
+ tensor
479
+ )
480
 
481
  return JSONResponse(result)
482
 
483
+ # =========================================
484
+ # 3D CNN ENDPOINT
485
+ # =========================================
486
  @app.post("/predict/cnn3d")
487
+ async def predict_cnn3d(
488
+ file: UploadFile = File(...)
489
+ ):
490
+
491
+ file_bytes = await file.read()
492
+
493
+ volume = load_nifti_from_bytes(
494
+ file_bytes
495
+ )
496
 
 
497
  tensor = preprocess_3d(volume)
498
 
499
+ result, _ = predict_model(
500
+ model3d,
501
+ tensor
502
+ )
503
 
504
  return JSONResponse(result)
505
 
 
506
  # =========================================
507
+ # ENSEMBLE ENDPOINT
508
  # =========================================
509
  @app.post("/predict/ensemble")
510
+ async def predict_ensemble(
511
+ file: UploadFile = File(...)
512
+ ):
513
 
514
+ file_bytes = await file.read()
515
+
516
+ volume = load_nifti_from_bytes(
517
+ file_bytes
518
+ )
519
 
520
  tensor2d = preprocess_2d(volume)
521
+
522
  tensor3d = preprocess_3d(volume)
523
 
524
+ r121, p121 = predict_model(
525
+ model121,
526
+ tensor2d
527
+ )
528
+
529
+ r169, p169 = predict_model(
530
+ model169,
531
+ tensor2d
532
+ )
533
+
534
+ r201, p201 = predict_model(
535
+ model201,
536
+ tensor2d
537
+ )
538
 
539
+ r3d, p3d = predict_model(
540
+ model3d,
541
+ tensor3d
542
+ )
543
 
544
+ avg_probs = (
545
+ p121 +
546
+ p169 +
547
+ p201 +
548
+ p3d
549
+ ) / 4
550
 
551
+ pred_idx = torch.argmax(
552
+ avg_probs
553
+ ).item()
554
 
555
+ final_result = {
556
 
557
+ "ensemble_prediction":
558
+ LABELS[pred_idx],
559
+
560
+ "ensemble_confidence":
561
+ round(
562
+ float(
563
+ avg_probs[pred_idx]
564
+ ) * 100,
565
+ 2
566
+ ),
567
 
568
  "ensemble_probabilities": {
569
+
570
+ LABELS[i]:
571
+ round(
572
+ float(
573
+ avg_probs[i]
574
+ ) * 100,
575
+ 2
576
+ )
577
+
578
  for i in range(NUM_CLASSES)
579
  },
580
 
581
  "individual_models": {
582
 
583
+ "DenseNet121":
584
+ r121,
585
+
586
+ "DenseNet169":
587
+ r169,
588
+
589
+ "DenseNet201":
590
+ r201,
591
+
592
+ "CNN3D":
593
+ r3d
594
  }
595
+ }
596
+
597
+ return JSONResponse(final_result)