Sumera_Rounaq:

I also want to debug the neural network build inside to understand the flow of values of “hidden_dim”.


I am not exactly sure what you mean. But if you want to debug the shape (and hidden dim) of the tensor between each block, I like to use a simple “PrintBlock”:
class PrintBlock(nn.Module):
    def forward(self, x):
        print(x.shape)
        return x

Putting it into your code:
class Generator(nn.Module):
    '''
    Generator Class
    Values:
        z_dim: the dimension of the noise vector, a scalar
        im_chan: the number of channels in the images, fitted for the dataset used, a scalar
              (MNIST is black-and-white, so 1 channel is your default)
        hidden_dim: the inner dimension, a scalar
    '''
    def __init__(self, z_dim=64, im_chan=1, hidden_dim=64):
        super(Generator, self).__init__()
        self.z_dim = z_dim
        # Build the neural network
        self.gen = nn.Sequential(
            PrintBlock(),
            self.make_gen_block(z_dim, hidden_dim * 4), 
            PrintBlock(),
            self.make_gen_block(hidden_dim * 4, hidden_dim * 2, kernel_size=4, stride=1),
            PrintBlock(),
            self.make_gen_block(hidden_dim * 2, hidden_dim),
            PrintBlock(),
            self.make_gen_block(hidden_dim, im_chan, kernel_size=4, final_layer=True),
            PrintBlock(),
        )

    ...

Assuming you are using a noise vector of shape [50, 54]:
net = Generator()
out = net.forward(torch.rand([50, 64]))

prints:
torch.Size([50, 64, 1, 1])
torch.Size([50, 256, 3, 3])
torch.Size([50, 128, 6, 6])
torch.Size([50, 64, 13, 13])
torch.Size([50, 1, 28, 28])

Maybe from here you can understand how to change the convolution kernels, strides, and padding to get the desired output shape.