nitinvig commited on
Commit
dc9e606
·
verified ·
1 Parent(s): 3230905

Upload 6 files

Browse files
model.py ADDED
@@ -0,0 +1,198 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import torch.nn as nn
3
+ import torch.nn.functional as F
4
+
5
+ class DoubleConv(nn.Module):
6
+ """
7
+ DoubleConv Module
8
+ =================
9
+ A standard building block for UNet, consisting of two consecutive convolution layers.
10
+ Each 3x3 convolution is followed by Batch Normalization and ReLU activation.
11
+
12
+ Structure:
13
+ Input -> [Conv3x3 -> BatchNorm -> ReLU] -> [Conv3x3 -> BatchNorm -> ReLU] -> Output
14
+ """
15
+ def __init__(self, in_channels, out_channels):
16
+ super().__init__()
17
+ self.double_conv = nn.Sequential(
18
+ nn.Conv2d(in_channels, out_channels, kernel_size=3, padding=1),
19
+ nn.BatchNorm2d(out_channels),
20
+ nn.ReLU(inplace=True),
21
+ nn.Conv2d(out_channels, out_channels, kernel_size=3, padding=1),
22
+ nn.BatchNorm2d(out_channels),
23
+ nn.ReLU(inplace=True)
24
+ )
25
+
26
+ def forward(self, x):
27
+ return self.double_conv(x)
28
+
29
+ class Down(nn.Module):
30
+ """
31
+ Down Module
32
+ ===========
33
+ Handles the downsampling step in the encoder part of the UNet.
34
+ It supports two modes of downsampling:
35
+
36
+ 1. 'maxpool': Uses MaxPool2d(2) to halve the spatial dimensions.
37
+ 2. 'strided': Uses a Strided Conv (kernel=3, stride=2) to halve dimensions while learning features.
38
+
39
+ After downsampling, a DoubleConv block processes the features.
40
+ """
41
+ def __init__(self, in_channels, out_channels, mode='maxpool'):
42
+ super().__init__()
43
+ self.mode = mode
44
+ if mode == 'maxpool':
45
+ # Option 1: MaxPool downsampling (Standard UNet)
46
+ self.down_layer = nn.MaxPool2d(2)
47
+ self.conv = DoubleConv(in_channels, out_channels)
48
+ elif mode == 'strided':
49
+ # Option 2: Strided Convolution downsampling
50
+ # Replaces the pooling operation with a learnable strided convolution
51
+ self.down_layer = nn.Sequential(
52
+ nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=2, padding=1),
53
+ nn.BatchNorm2d(out_channels),
54
+ nn.ReLU(inplace=True)
55
+ )
56
+ # The strided conv handles the channel change (in -> out).
57
+ # The following DoubleConv refines these features (out -> out).
58
+ self.conv = DoubleConv(out_channels, out_channels)
59
+ else:
60
+ raise ValueError(f"Unknown downsample mode: {mode}")
61
+
62
+ def forward(self, x):
63
+ if self.mode == 'maxpool':
64
+ x = self.down_layer(x)
65
+ return self.conv(x)
66
+ else:
67
+ # Strided path
68
+ x = self.down_layer(x) # [B, OutCh, H/2, W/2]
69
+ return self.conv(x) # [B, OutCh, H/2, W/2]
70
+
71
+ class Up(nn.Module):
72
+ """
73
+ Up Module
74
+ =========
75
+ Handles the upsampling step in the decoder part of the UNet.
76
+ It supports two modes of upsampling:
77
+
78
+ 1. 'transpose': Uses ConvTranspose2d to learn how to upsample.
79
+ 2. 'upsample': Uses bilinear interpolation (nn.Upsample).
80
+
81
+ Steps:
82
+ 1. Upsample the input tensor (x1) from the previous lower layer.
83
+ 2. Concatenate it with the corresponding feature map from the encoder (x2) (Skip Connection).
84
+ - Handles padding if dimensions don't match perfectly.
85
+ 3. Process the combined features with a DoubleConv block.
86
+ """
87
+ def __init__(self, in_channels, out_channels, mode='transpose'):
88
+ super().__init__()
89
+
90
+ if mode == 'transpose':
91
+ # Option 1: Transpose Convolution
92
+ # Typical for original UNet. Upsamples and reduces channels by half.
93
+ # in_channels is the dimension of the deep feature map coming UP.
94
+ self.up = nn.ConvTranspose2d(in_channels, in_channels // 2, kernel_size=2, stride=2)
95
+ self.up_mode = 'transpose'
96
+ elif mode == 'upsample':
97
+ # Option 2: Bilinear Upsampling
98
+ # Does not reduce channels itself, so we need a 1x1 conv to reduce channels
99
+ # to match the skip connection size before DoubleConv.
100
+ self.up = nn.Upsample(scale_factor=2, mode='bilinear', align_corners=True)
101
+ self.conv_adjust = nn.Conv2d(in_channels, in_channels // 2, kernel_size=1)
102
+ self.up_mode = 'upsample'
103
+ else:
104
+ raise ValueError(f"Unknown upsample mode: {mode}")
105
+
106
+ # DoubleConv takes the concatenated input.
107
+ # Channels = (in_channels // 2 from Up) + (in_channels // 2 from Skip) = in_channels
108
+ # Outputs count = out_channels
109
+ self.conv = DoubleConv(in_channels, out_channels)
110
+
111
+
112
+ def forward(self, x1, x2):
113
+ """
114
+ x1: Input from the previous decoder layer (to be upsampled)
115
+ x2: Input from the encoder layer (skip connection)
116
+ """
117
+ x1 = self.up(x1)
118
+
119
+ if hasattr(self, 'conv_adjust'):
120
+ x1 = self.conv_adjust(x1)
121
+
122
+ # Handle padding if x1 and x2 have slightly different sizes due to odd dimensions
123
+ # input is CHW
124
+ diffY = x2.size()[2] - x1.size()[2]
125
+ diffX = x2.size()[3] - x1.size()[3]
126
+
127
+ x1 = F.pad(x1, [diffX // 2, diffX - diffX // 2,
128
+ diffY // 2, diffY - diffY // 2])
129
+
130
+ # Concatenate x2 (skip) and x1 (upsampled) along the channel dimension
131
+ x = torch.cat([x2, x1], dim=1)
132
+ return self.conv(x)
133
+
134
+
135
+ class UNet(nn.Module):
136
+ """
137
+ UNet Architecture
138
+ =================
139
+ A U-shaped encoder-decoder architecture for image segmentation.
140
+
141
+ Configurable Parameters:
142
+ - n_channels: Number of input image channels (e.g., 3 for RGB).
143
+ - n_classes: Number of output classes (e.g., 1 for binary mask).
144
+ - downsample_mode: 'maxpool' or 'strided'.
145
+ - upsample_mode: 'transpose' or 'upsample' (bilinear).
146
+ """
147
+ def __init__(self, n_channels, n_classes, downsample_mode='maxpool', upsample_mode='transpose'):
148
+ super(UNet, self).__init__()
149
+ self.n_channels = n_channels
150
+ self.n_classes = n_classes
151
+ self.downsample_mode = downsample_mode
152
+ self.upsample_mode = upsample_mode
153
+
154
+ # Initial Feature Extraction
155
+ # Input: [B, n_channels, H, W] -> Output: [B, 64, H, W]
156
+ self.inc = DoubleConv(n_channels, 64)
157
+
158
+ # Encoder (Downsampling Path)
159
+ # Each step reduces H,W by 2 and doubles Channels
160
+ # Down 1: 64 -> 128
161
+ self.down1 = Down(64, 128, mode=downsample_mode)
162
+ # Down 2: 128 -> 256
163
+ self.down2 = Down(128, 256, mode=downsample_mode)
164
+ # Down 3: 256 -> 512
165
+ self.down3 = Down(256, 512, mode=downsample_mode)
166
+
167
+ # Bridge / Bottleneck
168
+ # Standard UNet goes to 1024.
169
+ self.down4 = Down(512, 1024, mode=downsample_mode)
170
+
171
+ # Decoder (Upsampling Path)
172
+ # Each step doubles H,W and halves Channels (logic handled in Up block)
173
+ self.up1 = Up(1024, 512, mode=upsample_mode)
174
+ self.up2 = Up(512, 256, mode=upsample_mode)
175
+ self.up3 = Up(256, 128, mode=upsample_mode)
176
+ self.up4 = Up(128, 64, mode=upsample_mode)
177
+
178
+ # Final Classification Layer
179
+ # Reduces 64 channels to n_classes (1 per pixel for binary)
180
+ self.outc = nn.Conv2d(64, n_classes, kernel_size=1)
181
+
182
+ def forward(self, x):
183
+ # Encoder Path with Skip Connections
184
+ x1 = self.inc(x) # [B, 64, H, W]
185
+ x2 = self.down1(x1) # [B, 128, H/2, W/2]
186
+ x3 = self.down2(x2) # [B, 256, H/4, W/4]
187
+ x4 = self.down3(x3) # [B, 512, H/8, W/8]
188
+ x5 = self.down4(x4) # [B, 1024, H/16, W/16] (Bottleneck)
189
+
190
+ # Decoder Path
191
+ # Pass skip connections (x4, x3, x2, x1) to Up modules
192
+ x = self.up1(x5, x4) # [B, 512, H/8, W/8]
193
+ x = self.up2(x, x3) # [B, 256, H/4, W/4]
194
+ x = self.up3(x, x2) # [B, 128, H/2, W/2]
195
+ x = self.up4(x, x1) # [B, 64, H, W]
196
+
197
+ logits = self.outc(x) # [B, n_classes, H, W]
198
+ return logits
requirements.txt ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ torch
2
+ torchvision
3
+ gradio==3.50.2
4
+ numpy
5
+ Pillow
unet_MP_Tr_BCE.pth ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:9a5290535881586cf771726cc69a8f62c0921779046a0e0d5d642d53a4bf5585
3
+ size 124267793
unet_MP_Tr_Dice.pth ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:e7c6779289817795727af96febbf36bb3981cef03b1fe4a19245e3c60d0c4bc7
3
+ size 124267935
unet_StrConv_Tr_BCE.pth ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:a6e6083407260f497c4cb87439bb4ae0049a5567e85e945043d3a06a879c772a
3
+ size 174451247
unet_StrConv_Ups_Dice.pth ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:5b630832cbc086d80335cf4f231f3e1a7e1000705b110604d3bd238597e6de67
3
+ size 166096003