Spaces:
Runtime error
Runtime error
| import torch | |
| import torch.nn as nn | |
| import torch.nn.functional as F | |
| def get_crop_config(crop): | |
| """ | |
| Get configuration parameters based on crop size. | |
| Args: | |
| crop: List of [height, width] or None | |
| Returns: | |
| dict: Configuration including alpha, h, w, diffx, diffy | |
| """ | |
| if crop is None: | |
| # Default values for TIP dataset (56x40) | |
| return { | |
| 'alpha': 6, | |
| 'h': 3, | |
| 'w': 2, | |
| 'diffx': [1, 0, 0, 0], | |
| 'diffy': [1, 0, 0, 0] | |
| } | |
| elif crop == [64, 27]: # PressurePose dataset | |
| return { | |
| 'alpha': 4, | |
| 'h': 4, | |
| 'w': 1, | |
| 'diffx': [1, 0, 1, 1], | |
| 'diffy': [0, 0, 0, 0] | |
| } | |
| elif crop == [110, 37]: # MOYO dataset | |
| return { | |
| 'alpha': 12, | |
| 'h': 6, | |
| 'w': 2, | |
| 'diffx': [0, 1, 0, 1], | |
| 'diffy': [1, 1, 1, 0] | |
| } | |
| else: # Default for other sizes | |
| return { | |
| 'alpha': 6, | |
| 'h': 3, | |
| 'w': 2, | |
| 'diffx': [1, 0, 0, 0], | |
| 'diffy': [1, 0, 0, 0] | |
| } | |
| class DoubleConv(nn.Module): | |
| """Double Convolutional Block with BN and ReLU""" | |
| def __init__(self, in_channels, out_channels, mid_channels=None): | |
| super().__init__() | |
| if not mid_channels: | |
| mid_channels = out_channels | |
| self.double_conv = nn.Sequential( | |
| nn.Conv2d(in_channels, mid_channels, kernel_size=3, padding=1, bias=False), | |
| nn.BatchNorm2d(mid_channels), | |
| nn.ReLU(inplace=True), | |
| nn.Conv2d(mid_channels, out_channels, kernel_size=3, padding=1, bias=False), | |
| nn.BatchNorm2d(out_channels), | |
| nn.ReLU(inplace=True) | |
| ) | |
| def forward(self, x): | |
| return self.double_conv(x) | |
| class Down(nn.Module): | |
| """Downscaling with maxpool then double conv""" | |
| def __init__(self, in_channels, out_channels): | |
| super().__init__() | |
| self.maxpool_conv = nn.Sequential( | |
| nn.MaxPool2d(2), | |
| DoubleConv(in_channels, out_channels) | |
| ) | |
| def forward(self, x): | |
| return self.maxpool_conv(x) | |
| class Up(nn.Module): | |
| """Upscaling then double conv""" | |
| def __init__(self, in_channels, out_channels, bilinear=True): | |
| super().__init__() | |
| if bilinear: | |
| self.up = nn.Upsample(scale_factor=2, mode='bilinear', align_corners=True) | |
| self.conv = DoubleConv(in_channels, out_channels, in_channels // 2) | |
| else: | |
| self.up = nn.ConvTranspose2d(in_channels, in_channels // 2, kernel_size=2, stride=2) | |
| self.conv = DoubleConv(in_channels, out_channels) | |
| def forward(self, x1, x2): | |
| x1 = self.up(x1) | |
| diffY = x2.size()[2] - x1.size()[2] | |
| diffX = x2.size()[3] - x1.size()[3] | |
| x1 = F.pad(x1, [diffX // 2, diffX - diffX // 2, diffY // 2, diffY - diffY // 2]) | |
| x = torch.cat([x2, x1], dim=1) | |
| return self.conv(x) | |
| class OutConv(nn.Module): | |
| def __init__(self, in_channels, out_channels): | |
| super(OutConv, self).__init__() | |
| self.conv = nn.Conv2d(in_channels, out_channels, kernel_size=1) | |
| def forward(self, x): | |
| return self.conv(x) | |
| class ConditionalBatchNorm2d(nn.Module): | |
| """Conditional BatchNorm2d to modulate output with condition vector""" | |
| def __init__(self, num_features, cond_dim): | |
| super(ConditionalBatchNorm2d, self).__init__() | |
| self.num_features = num_features | |
| self.bn = nn.BatchNorm2d(num_features, affine=False) | |
| self.gamma = nn.Linear(cond_dim, num_features) | |
| self.beta = nn.Linear(cond_dim, num_features) | |
| def forward(self, x, cond): | |
| gamma = self.gamma(cond).view(-1, self.num_features, 1, 1) | |
| beta = self.beta(cond).view(-1, self.num_features, 1, 1) | |
| return self.bn(x) * gamma + beta | |
| class UpWithCondition(nn.Module): | |
| """Upscaling then double conv with condition modulation""" | |
| def __init__(self, in_channels, out_channels, cond_dim, diffX, diffY, bilinear=True): | |
| super(UpWithCondition, self).__init__() | |
| self.diffX = diffX | |
| self.diffY = diffY | |
| if bilinear: | |
| self.up = nn.Upsample(scale_factor=2, mode='bilinear', align_corners=True) | |
| self.conv = DoubleConv(in_channels, out_channels, in_channels // 2) | |
| else: | |
| self.up = nn.ConvTranspose2d(in_channels, in_channels // 2, kernel_size=2, stride=2) | |
| self.conv = DoubleConv(in_channels // 2, out_channels) | |
| # Conditional batch norm for output modulation | |
| self.cond_bn = ConditionalBatchNorm2d(out_channels, cond_dim) | |
| def forward(self, x, cond): | |
| x = self.up(x) | |
| x = F.pad(x, [self.diffX // 2, self.diffX - self.diffX // 2, self.diffY // 2, self.diffY - self.diffY // 2]) | |
| x = self.conv(x) | |
| x = self.cond_bn(x, cond) # Modulate with condition | |
| return x | |
| class UNetEncoder(nn.Module): | |
| def __init__(self, cond_dim=256, embed_dim=256, dp_rate=0.0, bilinear=False, crop=None): | |
| super(UNetEncoder, self).__init__() | |
| self.cond_dim = cond_dim | |
| self.crop = crop | |
| # Get crop-specific configuration | |
| crop_config = get_crop_config(crop) | |
| alpha = crop_config['alpha'] | |
| # Encoder | |
| self.inc = DoubleConv(1, 64) | |
| self.down1 = Down(64, 128) | |
| self.down2 = Down(128, 256) | |
| self.down3 = Down(256, 512) | |
| factor = 2 if bilinear else 1 | |
| self.down4 = Down(512, 1024 // factor) | |
| self.dropout = nn.Dropout(dp_rate) | |
| # VAE latent space parameters | |
| self.fc_mu = nn.Linear((1024 // factor) * alpha + cond_dim, embed_dim) | |
| self.fc_log_var = nn.Linear((1024 // factor) * alpha + cond_dim, embed_dim) | |
| def forward(self, x, cond): | |
| # Encoder path | |
| x1 = self.inc(x) | |
| x2 = self.down1(x1) | |
| x3 = self.down2(x2) | |
| x4 = self.down3(x3) | |
| x5 = self.down4(x4) # B x (1024 // factor) x H x W | |
| # Flatten and concatenate with condition vector | |
| x5_flat = x5.view(x5.size(0), -1) | |
| x5_cond = torch.cat([x5_flat, cond], dim=1) | |
| # Compute mu and log_var for latent space | |
| mu = self.fc_mu(x5_cond) | |
| log_var = self.fc_log_var(x5_cond) | |
| return mu, log_var | |
| class UNetDecoder(nn.Module): | |
| def __init__(self, cond_dim=256, embed_dim=256, dp_rate=0.0, bilinear=False, crop=None): | |
| super(UNetDecoder, self).__init__() | |
| self.bilinear = bilinear | |
| self.cond_dim = cond_dim | |
| self.crop = crop | |
| # Get crop-specific configuration | |
| crop_config = get_crop_config(crop) | |
| alpha = crop_config['alpha'] | |
| self.h = crop_config['h'] | |
| self.w = crop_config['w'] | |
| diffx = crop_config['diffx'] | |
| diffy = crop_config['diffy'] | |
| factor = 2 if bilinear else 1 | |
| # Map latent vector and condition back to decoder size | |
| self.fc_z = nn.Linear(embed_dim + cond_dim, (1024 // factor) * alpha) | |
| self.dropout = nn.Dropout(dp_rate) | |
| # Decoder with conditional batch norm | |
| self.up1 = UpWithCondition(1024, 512 // factor, cond_dim, diffX=diffx[0], diffY=diffy[0], bilinear=bilinear) | |
| self.up2 = UpWithCondition(512, 256 // factor, cond_dim, diffX=diffx[1], diffY=diffy[1], bilinear=bilinear) | |
| self.up3 = UpWithCondition(256, 128 // factor, cond_dim, diffX=diffx[2], diffY=diffy[2], bilinear=bilinear) | |
| self.up4 = UpWithCondition(128, 64, cond_dim, diffX=diffx[3], diffY=diffy[3], bilinear=bilinear) | |
| self.outc = OutConv(64, 1) | |
| def forward(self, z, cond): | |
| b, _ = z.shape | |
| factor = 2 if self.bilinear else 1 | |
| # Decode latent vector concatenated with condition | |
| z_cond = torch.cat([z, cond], dim=1) | |
| z_decoded = self.fc_z(z_cond).view(b, 1024 // factor, self.h, self.w) | |
| z_decoded = self.dropout(z_decoded) | |
| # Decoder path with conditional modulation | |
| x = self.up1(z_decoded, cond) | |
| x = self.up2(x, cond) | |
| x = self.up3(x, cond) | |
| x = self.up4(x, cond) | |
| x = self.outc(x) | |
| return x.view(b, self.crop[0], self.crop[1]) | |
| if __name__ == "__main__": | |
| def reparameterize(mu, logvar): | |
| """VAE reparameterization trick""" | |
| std = torch.exp(0.5 * logvar) | |
| eps = torch.randn_like(std) | |
| return mu + eps * std | |
| # Test data | |
| data = torch.randn(4, 1, 56, 40) | |
| condition = torch.randn(4, 85) | |
| # Initialize encoder and decoder | |
| encoder = UNetEncoder(cond_dim=85, embed_dim=256, bilinear=False, crop=[56, 40]) | |
| decoder = UNetDecoder(cond_dim=85, embed_dim=256, bilinear=False, crop=[56, 40]) | |
| # Forward pass through encoder | |
| mu, logvar = encoder(data, condition) | |
| print(f"Mu shape: {mu.shape}, Logvar shape: {logvar.shape}") | |
| # Reparameterization trick | |
| z = reparameterize(mu, logvar) | |
| print(f"Latent z shape: {z.shape}") | |
| # Forward pass through decoder | |
| reconstructed = decoder(z, condition) | |
| print(f"Reconstructed shape: {reconstructed.shape}") | |
| print(f"Expected shape: [4, 56, 40]") | |
| assert reconstructed.shape == (4, 56, 40), f"Shape mismatch: {reconstructed.shape} vs (4, 56, 40)" | |
| print("Test passed!") | |