JustAGeek commited on
Commit
52dfd85
·
verified ·
1 Parent(s): 1fdd233

Upload scripts/student_tinycnn.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. scripts/student_tinycnn.py +103 -0
scripts/student_tinycnn.py ADDED
@@ -0,0 +1,103 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ student_tinycnn.py
3
+ Tiny CNN student model for DLoc knowledge distillation.
4
+
5
+ Architecture (from professor's spec):
6
+ Block 1: Conv(4->16) + DepthwiseSep(16->16) + MaxPool
7
+ Block 2: DepthwiseSep(16->32) + DepthwiseSep(32->32) + MaxPool
8
+ Block 3: DepthwiseSep(32->64)
9
+ Decoder 1: ConvTranspose(64->32, stride=2)
10
+ Decoder 2: ConvTranspose(32->16, stride=2)
11
+ Output: Conv(16->1, 1x1) + Sigmoid
12
+
13
+ Adapted for 161x361 input (professor's spec used 64x64).
14
+ ~30K params — extremely lightweight.
15
+ """
16
+ import torch
17
+ import torch.nn as nn
18
+
19
+
20
+ class DepthwiseSeparableConv(nn.Module):
21
+ """Depthwise separable convolution: depthwise + pointwise."""
22
+ def __init__(self, in_ch, out_ch, kernel_size=3, padding=1):
23
+ super().__init__()
24
+ self.depthwise = nn.Conv2d(in_ch, in_ch, kernel_size, padding=padding, groups=in_ch, bias=False)
25
+ self.pointwise = nn.Conv2d(in_ch, out_ch, 1, bias=False)
26
+ self.bn = nn.BatchNorm2d(out_ch)
27
+ self.relu = nn.ReLU(inplace=True)
28
+
29
+ def forward(self, x):
30
+ return self.relu(self.bn(self.pointwise(self.depthwise(x))))
31
+
32
+
33
+ class TinyCNNStudent(nn.Module):
34
+ OUTPUT_SIZE = (161, 361)
35
+
36
+ def __init__(self, input_nc=4):
37
+ super().__init__()
38
+
39
+ # Block 1: 4 -> 16, downsample 2x
40
+ self.block1 = nn.Sequential(
41
+ nn.Conv2d(input_nc, 16, kernel_size=3, padding=1, bias=False),
42
+ nn.BatchNorm2d(16),
43
+ nn.ReLU(inplace=True),
44
+ DepthwiseSeparableConv(16, 16),
45
+ nn.MaxPool2d(2),
46
+ )
47
+
48
+ # Block 2: 16 -> 32, downsample 2x
49
+ self.block2 = nn.Sequential(
50
+ DepthwiseSeparableConv(16, 32),
51
+ DepthwiseSeparableConv(32, 32),
52
+ nn.MaxPool2d(2),
53
+ )
54
+
55
+ # Block 3: 32 -> 64 (no downsample)
56
+ self.block3 = nn.Sequential(
57
+ DepthwiseSeparableConv(32, 64),
58
+ )
59
+
60
+ # Decoder 1: 64 -> 32, upsample 2x
61
+ self.dec1 = nn.Sequential(
62
+ nn.ConvTranspose2d(64, 32, kernel_size=4, stride=2, padding=1, bias=False),
63
+ nn.BatchNorm2d(32),
64
+ nn.ReLU(inplace=True),
65
+ )
66
+
67
+ # Decoder 2: 32 -> 16, upsample 2x
68
+ self.dec2 = nn.Sequential(
69
+ nn.ConvTranspose2d(32, 16, kernel_size=4, stride=2, padding=1, bias=False),
70
+ nn.BatchNorm2d(16),
71
+ nn.ReLU(inplace=True),
72
+ )
73
+
74
+ # Output head
75
+ self.head = nn.Sequential(
76
+ nn.Conv2d(16, 1, kernel_size=1),
77
+ nn.Sigmoid(),
78
+ )
79
+
80
+ def forward(self, x):
81
+ x = self.block1(x) # [B,16, H/2, W/2]
82
+ x = self.block2(x) # [B,32, H/4, W/4]
83
+ x = self.block3(x) # [B,64, H/4, W/4]
84
+ x = self.dec1(x) # [B,32, H/2, W/2]
85
+ x = self.dec2(x) # [B,16, H, W]
86
+ x = self.head(x) # [B,1, H, W]
87
+ # Ensure exact output size
88
+ if x.shape[2:] != self.OUTPUT_SIZE:
89
+ x = nn.functional.interpolate(x, size=self.OUTPUT_SIZE, mode='bilinear', align_corners=False)
90
+ return x
91
+
92
+
93
+ if __name__ == "__main__":
94
+ model = TinyCNNStudent(input_nc=4)
95
+ n = sum(p.numel() for p in model.parameters())
96
+ print(f"Parameters: {n:,} ({n/1e6:.2f}M)")
97
+ x = torch.randn(2, 4, 161, 361)
98
+ with torch.no_grad():
99
+ y = model(x)
100
+ print(f"Input: {x.shape}")
101
+ print(f"Output: {y.shape}")
102
+ assert y.shape == (2, 1, 161, 361), f"Wrong shape: {y.shape}"
103
+ print("OK")