nismal1u commited on
Commit
ce593f2
·
verified ·
1 Parent(s): 1fe30c1

Add model code

Browse files
Files changed (1) hide show
  1. model.py +58 -0
model.py ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """DenseNet121 with an MC-Dropout head for chest X-ray classification.
2
+
3
+ The backbone is the CheXNet-standard DenseNet121. We replace the classifier
4
+ with a Dropout -> Linear head. At inference we keep the Dropout layers active
5
+ (see `enable_mc_dropout`) so repeated forward passes give a distribution over
6
+ predictions -- the basis for our uncertainty estimate.
7
+ """
8
+ import torch
9
+ import torch.nn as nn
10
+ from torchvision import models
11
+
12
+
13
+ def build_model(num_classes: int = 1, dropout_p: float = 0.3,
14
+ pretrained: bool = True) -> nn.Module:
15
+ """DenseNet121 with an MC-Dropout classifier head.
16
+
17
+ num_classes=1 -> binary task, use with BCEWithLogitsLoss (sigmoid output).
18
+ num_classes=N (N>1, multi-label e.g. ChestX-ray14) -> also BCEWithLogitsLoss.
19
+ """
20
+ weights = models.DenseNet121_Weights.IMAGENET1K_V1 if pretrained else None
21
+ net = models.densenet121(weights=weights)
22
+ in_features = net.classifier.in_features
23
+ net.classifier = nn.Sequential(
24
+ nn.Dropout(p=dropout_p),
25
+ nn.Linear(in_features, num_classes),
26
+ )
27
+ return net
28
+
29
+
30
+ def enable_mc_dropout(model: nn.Module) -> None:
31
+ """Put the model in eval mode but re-activate Dropout layers.
32
+
33
+ This is what makes MC Dropout work: BatchNorm etc. stay in eval mode
34
+ (using running stats), while Dropout keeps sampling.
35
+ """
36
+ model.eval()
37
+ for m in model.modules():
38
+ if isinstance(m, nn.Dropout):
39
+ m.train()
40
+
41
+
42
+ @torch.no_grad()
43
+ def mc_predict(model: nn.Module, x: torch.Tensor, n_passes: int = 30):
44
+ """Run n stochastic forward passes.
45
+
46
+ Returns:
47
+ mean_prob: (B, C) predictive probability (mean over passes)
48
+ uncertainty:(B, C) predictive std over passes (epistemic signal)
49
+ """
50
+ enable_mc_dropout(model)
51
+ probs = []
52
+ for _ in range(n_passes):
53
+ logits = model(x)
54
+ probs.append(torch.sigmoid(logits))
55
+ probs = torch.stack(probs, dim=0) # (T, B, C)
56
+ mean_prob = probs.mean(dim=0) # (B, C)
57
+ uncertainty = probs.std(dim=0) # (B, C)
58
+ return mean_prob, uncertainty