I'm having an extremely hard time trying to implement a simple Autoencoder where the encoder and the decoder are 1D CNNs: import torch import torch.nn as nn import torch.nn.functional as F import numpy as np class IrAutoencoder(nn.Module): def __init__(self, input_dim=1800, latent_dim=128, channels=[1, 16, 32, 64], pool_kernel=2): super().__init__() self.dims = [input_dim] # Encoder self.conv1 = nn.Conv1d(channels[0], channels[1], kernel_size=10, stride=2, padding=4) self.dims.append(self._conv_out_dim(input_dim, kernel_size=10, stride=2, padding=4, dilation=1)) self.norm1 = nn.BatchNorm1d(channels[1]) self.pool1 = nn.AvgPool1d(kernel_size=pool_kernel, stride=pool_kernel) self.dims.append(self._conv_out_dim(self.dims[-1], pool_kernel, pool_kernel, 0, 0)) self.conv2 = nn.Conv1d(channels[1], channels[2], kernel_size=5, stride=2, padding=2) self.dims.append(self._conv_out_dim(self.dims[-1], kernel_size=5, stride=2, padding=2, dilation=1)) self.norm2 = nn.BatchNorm1d(channels[2]) self.pool2 = nn.AvgPool1d(kernel_size=pool_kernel, stride=pool_kernel) self.dims.append(self._conv_out_dim(self.dims[-1], pool_kernel, pool_kernel, 0, 0)) self.conv3 = nn.Conv1d(channels[2], channels[3], kernel_size=2, stride=1, padding=1) self.dims.append(self._conv_out_dim(self.dims[-1], kernel_size=2, stride=1, padding=1, dilation=1)) self.norm3 = nn.BatchNorm1d(channels[3]) self.pool3 = nn.AvgPool1d(kernel_size=pool_kernel, stride=pool_kernel) self.dims.append(self._conv_out_dim(self.dims[-1], pool_kernel, pool_kernel, 0, 0)) # Bottleneck self.bottleneck = nn.Sequential( nn.Linear(channels[3] * self.dims[-1], latent_dim), nn.BatchNorm1d(latent_dim), nn.ReLU() ) # Decoder ... @staticmethod def _conv_out_dim(dim_in, kernel_size, stride, padding, dilation): return (dim_in + 2 * padding - dilation * (kernel_size - 1) - 1) // stride + 1 def forward(self, x): # Encoder x = self.pool1(F.relu(self.norm1(self.conv1(x)))) x = self.pool2(F.relu(self.norm2(self.conv2(x)))) x = self.pool3(F.relu(self.norm3(self.conv3(x)))) x = x.view(x.size(0), -1) # Flatten before bottleneck x = self.bottleneck(x) # decoder ... if __name__ == '__main__': #Double checking dimensions input_tensor = torch.randn(10, 1, 1800) # Initialize and run the autoencoder autoencoder = IrAutoencoder(input_dim=1800, latent_dim=128) output = autoencoder(input_tensor) print("Input shape:", input_tensor.shape) # Expected: [10, 1, 1800] print("Output shape:", output.shape) # Expected: [10, 1, 1800] First of all I'm not too sure about this but there might be problems with self.bottleneck. To be sure, I compute the dimension at every nn.Conv1d and nn.AvgPool1D layer in order to extract the signal dimension and I obtain self.dims [1800, 900, 450, 225, 113, 114, 57] but then when it gets to self.bottleneck x has shape [10,64,56]. I guess this might be related to a problem with the other parameters I'm currently using, i.e. kernel_size, stride and so on? Additionally, I find it very difficult now to implement the decoder and I don't know how should I select the same parameters in order to obtain a signal with the input dimension (i.e. 1800). In general I'm finding quite difficult to implement this type of model and it seems you just have to rely on tweaking all these parameters until getting the right shape. Could you please help me with this, and eventually also suggesting best practices to follow when implementing this kind of architectures? Thanks. Continue reading...