add D3 = ResnetGenerator9Plain (no dilation, no wing ResBlock, bilinear upsample) for 1024^2 + DAB loss
Browse files
scripts/src_ds_her2_thunder_v2.py
CHANGED
|
@@ -774,6 +774,78 @@ class ResnetGenerator9Dilated(nn.Module):
|
|
| 774 |
return self.head(x)
|
| 775 |
|
| 776 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 777 |
class SkipFreeAE(nn.Module):
|
| 778 |
"""Encoder-decoder with pluggable downsample block (strided or DWT).
|
| 779 |
Used for Exp 2 (arch A vs B) at ds_factor=1.
|
|
@@ -1190,6 +1262,8 @@ def train_one(arch: str, ds_factor: int, files_train, files_val,
|
|
| 1190 |
elif arch == "D2":
|
| 1191 |
G = ResnetGenerator9Dilated(base_ch=args.dilated_ch,
|
| 1192 |
dilations=tuple(args.d2_dilations)).to(device)
|
|
|
|
|
|
|
| 1193 |
elif arch == "C":
|
| 1194 |
G = WaveletJointAE(base_ch=args.wavelet_ch,
|
| 1195 |
wavelet=args.wavelet).to(device)
|
|
|
|
| 774 |
return self.head(x)
|
| 775 |
|
| 776 |
|
| 777 |
+
class ResnetGenerator9Plain(nn.Module):
|
| 778 |
+
"""Arch D3: 1024^2 CycleGAN-style Resnet 9-block generator, NO dilation.
|
| 779 |
+
|
| 780 |
+
Standard Pyramid-Pix2Pix / CycleGAN template adapted to our stack:
|
| 781 |
+
- GroupNorm + GELU + zero pad throughout (NOT InstanceNorm + ReLU + reflection).
|
| 782 |
+
- Bilinear x2 + Conv3x3 for upsampling (NOT ConvTranspose, avoids checkerboard).
|
| 783 |
+
- Wing blocks are lean (Conv3x3+GN+GELU only, NO ResBlock) so we fit 1024^2 at
|
| 784 |
+
bs=8 on A100 80GB. All the ResBlocks live in the bottleneck.
|
| 785 |
+
- Bottleneck: 9 x ResBlock(base_ch*4), dilation=1 (plain), same class as A3/C.
|
| 786 |
+
|
| 787 |
+
Topology:
|
| 788 |
+
stem: Conv7x7(3->c1) + GN + GELU (1024^2)
|
| 789 |
+
down1: Conv3x3(c1->c2, s=2) + GN + GELU (512^2)
|
| 790 |
+
down2: Conv3x3(c2->c3, s=2) + GN + GELU (256^2)
|
| 791 |
+
bottleneck: 9 x ResBlock(c3, dilation=1) (256^2)
|
| 792 |
+
up1: Bilinear x2 + Conv3x3(c3->c2) + GN + GELU (512^2)
|
| 793 |
+
up2: Bilinear x2 + Conv3x3(c2->c1) + GN + GELU (1024^2)
|
| 794 |
+
head: Conv7x7(c1->3) + Tanh (1024^2)
|
| 795 |
+
|
| 796 |
+
~10.4M params at base_ch=64. Works at any resolution divisible by 4.
|
| 797 |
+
"""
|
| 798 |
+
|
| 799 |
+
def __init__(self, base_ch: int = 64, groups: int = 8, n_bottleneck: int = 9):
|
| 800 |
+
super().__init__()
|
| 801 |
+
c1, c2, c3 = base_ch, base_ch * 2, base_ch * 4
|
| 802 |
+
g1 = min(groups, c1); g2 = min(groups, c2); g3 = min(groups, c3)
|
| 803 |
+
self.stem = nn.Sequential(
|
| 804 |
+
nn.Conv2d(3, c1, 7, padding=3),
|
| 805 |
+
nn.GroupNorm(g1, c1),
|
| 806 |
+
nn.GELU(),
|
| 807 |
+
)
|
| 808 |
+
self.down1 = nn.Sequential(
|
| 809 |
+
nn.Conv2d(c1, c2, 3, stride=2, padding=1),
|
| 810 |
+
nn.GroupNorm(g2, c2),
|
| 811 |
+
nn.GELU(),
|
| 812 |
+
)
|
| 813 |
+
self.down2 = nn.Sequential(
|
| 814 |
+
nn.Conv2d(c2, c3, 3, stride=2, padding=1),
|
| 815 |
+
nn.GroupNorm(g3, c3),
|
| 816 |
+
nn.GELU(),
|
| 817 |
+
)
|
| 818 |
+
# Plain 9-block bottleneck (dilation=1), same ResBlock class as A3/C.
|
| 819 |
+
self.bottleneck = nn.Sequential(
|
| 820 |
+
*[ResBlock(c3, groups=groups) for _ in range(n_bottleneck)]
|
| 821 |
+
)
|
| 822 |
+
self.up1 = nn.Sequential(
|
| 823 |
+
nn.Upsample(scale_factor=2, mode="bilinear", align_corners=False),
|
| 824 |
+
nn.Conv2d(c3, c2, 3, padding=1),
|
| 825 |
+
nn.GroupNorm(g2, c2),
|
| 826 |
+
nn.GELU(),
|
| 827 |
+
)
|
| 828 |
+
self.up2 = nn.Sequential(
|
| 829 |
+
nn.Upsample(scale_factor=2, mode="bilinear", align_corners=False),
|
| 830 |
+
nn.Conv2d(c2, c1, 3, padding=1),
|
| 831 |
+
nn.GroupNorm(g1, c1),
|
| 832 |
+
nn.GELU(),
|
| 833 |
+
)
|
| 834 |
+
self.head = nn.Sequential(
|
| 835 |
+
nn.Conv2d(c1, 3, 7, padding=3),
|
| 836 |
+
nn.Tanh(),
|
| 837 |
+
)
|
| 838 |
+
|
| 839 |
+
def forward(self, x):
|
| 840 |
+
x = self.stem(x)
|
| 841 |
+
x = self.down1(x)
|
| 842 |
+
x = self.down2(x)
|
| 843 |
+
x = self.bottleneck(x)
|
| 844 |
+
x = self.up1(x)
|
| 845 |
+
x = self.up2(x)
|
| 846 |
+
return self.head(x)
|
| 847 |
+
|
| 848 |
+
|
| 849 |
class SkipFreeAE(nn.Module):
|
| 850 |
"""Encoder-decoder with pluggable downsample block (strided or DWT).
|
| 851 |
Used for Exp 2 (arch A vs B) at ds_factor=1.
|
|
|
|
| 1262 |
elif arch == "D2":
|
| 1263 |
G = ResnetGenerator9Dilated(base_ch=args.dilated_ch,
|
| 1264 |
dilations=tuple(args.d2_dilations)).to(device)
|
| 1265 |
+
elif arch == "D3":
|
| 1266 |
+
G = ResnetGenerator9Plain(base_ch=args.dilated_ch).to(device)
|
| 1267 |
elif arch == "C":
|
| 1268 |
G = WaveletJointAE(base_ch=args.wavelet_ch,
|
| 1269 |
wavelet=args.wavelet).to(device)
|