import torch import torch.nn as nn class UNetBlock(nn.Module): def __init__(self, in_channels, out_channels, down=True, use_dropout=False): super().__init__() if down: self.block = nn.Sequential( nn.Conv2d(in_channels, out_channels, 4, 2, 1, bias=False), nn.BatchNorm2d(out_channels), nn.LeakyReLU(0.2, inplace=True) ) else: self.block = nn.Sequential( nn.ConvTranspose2d(in_channels, out_channels, 4, 2, 1, bias=False), nn.BatchNorm2d(out_channels), nn.ReLU(inplace=True) ) self.use_dropout = use_dropout if use_dropout: self.dropout = nn.Dropout(0.5) def forward(self, x): x = self.block(x) return self.dropout(x) if self.use_dropout else x class UNetGenerator(nn.Module): def __init__(self, in_channels=3, out_channels=3): super().__init__() # Encoder self.down1 = UNetBlock(in_channels, 64, down=True, use_dropout=False) self.down2 = UNetBlock(64, 128) self.down3 = UNetBlock(128, 256) self.down4 = UNetBlock(256, 512) self.down5 = UNetBlock(512, 512) self.down6 = UNetBlock(512, 512) self.down7 = UNetBlock(512, 512) self.down8 = nn.Sequential( nn.Conv2d(512, 512, 4, 2, 1), nn.ReLU() ) # Decoder self.up1 = UNetBlock(512, 512, down=False, use_dropout=True) self.up2 = UNetBlock(1024, 512, down=False, use_dropout=True) self.up3 = UNetBlock(1024, 512, down=False, use_dropout=True) self.up4 = UNetBlock(1024, 512, down=False) self.up5 = UNetBlock(1024, 256, down=False) self.up6 = UNetBlock(512, 128, down=False) self.up7 = UNetBlock(256, 64, down=False) self.final = nn.Sequential( nn.ConvTranspose2d(128, out_channels, 4, 2, 1), nn.Tanh() ) def forward(self, x): # Encoder d1 = self.down1(x) d2 = self.down2(d1) d3 = self.down3(d2) d4 = self.down4(d3) d5 = self.down5(d4) d6 = self.down6(d5) d7 = self.down7(d6) bottleneck = self.down8(d7) # Decoder with skip connections u1 = self.up1(bottleneck) u2 = self.up2(torch.cat([u1, d7], dim=1)) u3 = self.up3(torch.cat([u2, d6], dim=1)) u4 = self.up4(torch.cat([u3, d5], dim=1)) u5 = self.up5(torch.cat([u4, d4], dim=1)) u6 = self.up6(torch.cat([u5, d3], dim=1)) u7 = self.up7(torch.cat([u6, d2], dim=1)) out = self.final(torch.cat([u7, d1], dim=1)) return out