Target Size different to Input Size when computing discriminator loss for DCGAN

kpullela10: <p>I’m a high schooler who’s (very!) new to machine learning and PyTorch, so I’ve been trying to build a DCGAN following the PyTorch official tutorial to replicate samples of melanoma lesions from the SIIM-ISIC Melanoma Classification dataset. However, I keep getting this error when trying to compute my discriminator loss on real data:</p>
<pre><code class="lang-auto">
Using a target size (torch.Size([64])) that is different to the input size (torch.Size([14400])) is deprecated. Please ensure they have the same size.
</code></pre>
<p>Turns out my ‘output’ shape is 14400, but I’m not sure how it got there, although I’d guess it’s an issue from the way I load data or the layers in my discriminator. I’ve tried looking at some of the other related posts on here, but I’m not quite certain that those match my situation. I’m also inclined to believe that the issue is more likely with the way I’m loading data, as the main generator/discriminator/train code I followed from the aforementioned PyTorch DCGAN tutorial. I was wondering if I could get a few pointers in the right direction? Anything would help! Also, if there’s anything I should amend or add to this post, apologies in advance, please let me know.</p>
<p>I’m using a batch size of 64, a BCELoss function, and I’m not sure if this would help, but here is my train_transform:</p>
<pre><code class="lang-auto">train_transform = transforms.Compose([
        transforms.Grayscale(num_output_channels=3),
        transforms.Resize((299, 299)),
        transforms.RandomHorizontalFlip(),
        transforms.RandomVerticalFlip(),
        transforms.ToTensor(),
        transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
    ])
</code></pre>
<p>Here’s a row of the csv file I use (each ISIC_number corresponds to a jpg image with the same number), with the columns (image_name, patient_id, sex, age_approx, anatom_site_general_challenge, diagnosis, benign_malignant, target):</p>
<p><code>ISIC_0149568    IP_0962375    female        55.0     torso       melanoma       malignant       1</code></p>
<p>I’m also using this to create, initialize, and load my dataset:</p>
<pre><code class="lang-auto">class PreGANDataset(torch.utils.data.Dataset):
  def __init__(self, csv_file_path, root_path, transform=None):
    self.annotations = pd.read_csv(csv_file_path)
    self.root_path = root_path
    self.transform = transform
  def __len__(self):
    return len(self.annotations)
  def __getitem__(self, index):
    img_path = os.path.join(self.root_path, self.annotations.iloc[index, 0] + ".jpg")
    img = Image.open(img_path)
    y_label = torch.tensor(int(self.annotations.iloc[index, 7]))
    if self.transform:
      img = self.transform(img)
    return img, y_label

train_dataset = PreGANDataset(csv_file_path="/content/malignant.csv", root_path="/content/train_and_test_folder/train",
                              transform=train_transform)
train_dataloader = DataLoader(train_dataset, batch_size=BATCH_SIZE, shuffle=True)
</code></pre>
<p>Here is my discriminator and train function code:</p>
<pre><code class="lang-auto">class Discriminator(nn.Module):
    def __init__(self, NUM_GPU):
        super(Discriminator, self).__init__()
        self.NUM_GPU = NUM_GPU
        self.main = nn.Sequential(
            nn.Conv2d(3, 64, 4, 2, 1, bias=False),
            nn.LeakyReLU(0.2, inplace=True),
            nn.Conv2d(64, 64 * 2, 4, 2, 1, bias=False),
            nn.BatchNorm2d(64 * 2),
            nn.LeakyReLU(0.2, inplace=True),
            nn.Conv2d(64 * 2, 64 * 4, 4, 2, 1, bias=False),
            nn.BatchNorm2d(64 * 4),
            nn.LeakyReLU(0.2, inplace=True),
            nn.Conv2d(64 * 4, 64 * 8, 4, 2, 1, bias=False),
            nn.BatchNorm2d(64 * 8),
            nn.LeakyReLU(0.2, inplace=True),
            nn.Conv2d(64 * 8, 1, 4, 1, 0, bias=False), 
            nn.Sigmoid()
        )

    def forward(self, input):
        return self.main(input)

DISCRIM = Discriminator(NUM_GPU).to(DEVICE)
if (DEVICE.type == 'cuda') and (NUM_GPU &gt; 1):
    DISCRIM = nn.DataParallel(DISCRIM, list(range(NUM_GPU)))
DISCRIM.apply(weights_initialization)
print(DISCRIM)

FIXED_NOISE = torch.randn(64, Z_SIZE, 1, 1, device=DEVICE)
GEN_OPTIMIZER = torch.optim.Adam(
    MODEL.parameters(), lr=LEARNING_RATE, betas=(BETA1, 0.999))
DIS_OPTIMIZER = torch.optim.Adam(
    DISCRIM.parameters(), lr=LEARNING_RATE, betas=(BETA1, 0.999))


def train():
    img_list = []
    G_losses = []
    D_losses = []
    iters = 0

    for epoch in range(NUM_EPOCHS):
        for i, data in enumerate(train_dataloader, 0):
            DISCRIM.zero_grad()
            rg = data[0].to(DEVICE)
            bs = rg.size(0)
            label = torch.full((bs,), REAL_LABEL,
                               dtype=torch.float, device=DEVICE) #REAL_LABEL is set to 1
            output = DISCRIM(rg).view(-1)
            dis_cost_real = LOSS_FUNCTION(output, label) # Right here is where this error is raised, my guess is that I'm using the wrong shape for output, but I'm not sure how (since the number referenced in the error in 14400)
            dis_cost_real.backward()
            dx = output.mean().item()

            noise = torch.randn(bs, Z_SIZE, 1, 1, device=DEVICE)
            fake = MODEL(noise)
            label.fill_(FAKE_LABEL) #FAKE_LABEL is set to 0
            output = DISCRIM(fake.detach()).view(-1)
            dis_cost_fake = LOSS_FUNCTION(output, label)
            dis_cost_fake.backward()
            dgz = output.mean().item()
            dis_cost = dis_cost_fake + dis_cost_real
            DIS_OPTIMIZER.step()

            MODEL.zero_grad()
            label.fill_(REAL_LABEL)
            output = DISCRIM(fake).view(-1)
            gen_cost = LOSS_FUNCTION(output, label)
            gen_cost.backward()
            dgz2 = output.mean().item()
            GEN_OPTIMIZER.step()

            if i % 50 == 0:
                print('[%d/%d][%d/%d]\tLoss_D: %.4f\tLoss_G: %.4f\tD(x): %.4f\tD(G(z)): %.4f / %.4f'
                      % (epoch, NUM_EPOCHS, i, len(train_dataloader),
                         dis_cost.item(), gen_cost.item(), dx, dgz, dgz2))

            G_losses.append(gen_cost.item())
            D_losses.append(dis_cost.item())

            if (iters % 500 == 0) or ((epoch == NUM_EPOCHS-1) and (i == len(train_dataloader)-1)):
                with torch.no_grad():
                    fake = MODEL(FIXED_NOISE).detach().to(DEVICE)
                img_list.append(torchvision.utils.make_grid(
                    fake, padding=2, normalize=True))

            iters += 1

train()
</code></pre>

KFrank: <p>Hi kpullela!</p>
<aside class="quote no-group" data-username="kpullela10" data-post="1" data-topic="173451" data-full="true">
<div class="title">
<div class="quote-controls"></div>
<img loading="lazy" alt="" width="24" height="24" src="https://discuss.pytorch.org/user_avatar/discuss.pytorch.org/kpullela10/48/57707_2.png" class="avatar"> kpullela10:</div>
<blockquote>
<p>I keep getting this error when trying to compute my discriminator loss on real data:</p>
<pre><code class="lang-auto">Using a target size (torch.Size([64])) that is different to the input size (torch.Size([14400])) is deprecated. Please ensure they have the same size.
</code></pre>
<p>Turns out my ‘output’ shape is 14400</p>
</blockquote>
</aside>
<p><code>14400</code> is <code>64 * 15**2</code>, so I expect that your discriminator is returning batches<br>
of “images” of shape <code>[nBatch = 64, nChannels = 1, H = 15, W = 15]</code>.</p>
<aside class="quote no-group">
<blockquote>
<pre><code class="lang-auto">class Discriminator(nn.Module):
    def __init__(self, NUM_GPU):
        super(Discriminator, self).__init__()
        self.NUM_GPU = NUM_GPU
        self.main = nn.Sequential(
            nn.Conv2d(3, 64, 4, 2, 1, bias=False),
            nn.LeakyReLU(0.2, inplace=True),
            nn.Conv2d(64, 64 * 2, 4, 2, 1, bias=False),
            nn.BatchNorm2d(64 * 2),
            nn.LeakyReLU(0.2, inplace=True),
            nn.Conv2d(64 * 2, 64 * 4, 4, 2, 1, bias=False),
            nn.BatchNorm2d(64 * 4),
            nn.LeakyReLU(0.2, inplace=True),
            nn.Conv2d(64 * 4, 64 * 8, 4, 2, 1, bias=False),
            nn.BatchNorm2d(64 * 8),
            nn.LeakyReLU(0.2, inplace=True),
            nn.Conv2d(64 * 8, 1, 4, 1, 0, bias=False), 
            nn.Sigmoid()
        )

    def forward(self, input):
        return self.main(input)
</code></pre>
</blockquote>
</aside>
<p>Your <code>Discriminator</code> is fully convolutional, so the height and width of its output<br>
will depend on the height and width of its input.  Looking through the numbers,<br>
I expect that you are passing in batches of samples that have shapes equal to<br>
<code>[nBatch = 64, nChannels = 3, H = 512, W = 512]</code>.</p>
<p>If you know that your input images will always have this size (or you can ensure<br>
it by resizing, padding, etc.) then you know what the shape of the output will be.</p>
<p>In any event, you want your <code>Discriminator</code> to output a single value for each<br>
sample in the batch, so a shape of <code>[64]</code> for a batch size of 64.</p>
<p>Let’s assume that you do always pass in batches of images of shape<br>
<code>[nBatch, 3, 512, 512]</code> (<code>nBatch</code> can vary, but the number of channels,<br>
height, and width have to be fixed) and that <code>Discriminator</code> therefore outputs<br>
(batches of) images of height and width both <code>15</code>.</p>
<p>You should add a <code>Flatten (1)</code> layer to the end your network to “flatten” all<br>
but the <code>nBatch</code> dimension (giving a shape of <code>[nBatch, 225]</code>) followed by<br>
a <code>Linear (255, 1)</code> (giving a shape of <code>[nBatch, 1]</code>, after which you would<br>
likely <code>squeeze (-1)</code> the trailing singleton dimension away).  This will output a<br>
shape of <code>[nBatch]</code>, that is, a single predicted value for each sample in the<br>
batch, that will match the shape of the <code>target</code> that you are passing to your<br>
<code>LOSS_FUNCTION</code>.</p>
<p>(<code>output = DISCRIM (rg)</code> will suffice without the <code>.view(-1)</code>.)</p>
<p>Last, use <code>BCEWithLogitsLoss</code> (instead of <code>BCELoss</code>) for better numerical<br>
stability, and, correspondingly, get rid of the <code>Sigmoid()</code>.</p>
<p>So, something like:</p>
<pre data-code-wrap="python"><code class="lang-python">        self.main = nn.Sequential(
            nn.Conv2d(3, 64, 4, 2, 1, bias=False),
            nn.LeakyReLU(0.2, inplace=True),
            nn.Conv2d(64, 64 * 2, 4, 2, 1, bias=False),
            nn.BatchNorm2d(64 * 2),
            nn.LeakyReLU(0.2, inplace=True),
            nn.Conv2d(64 * 2, 64 * 4, 4, 2, 1, bias=False),
            nn.BatchNorm2d(64 * 4),
            nn.LeakyReLU(0.2, inplace=True),
            nn.Conv2d(64 * 4, 64 * 8, 4, 2, 1, bias=False),
            nn.BatchNorm2d(64 * 8),
            nn.LeakyReLU(0.2, inplace=True),
            nn.Conv2d(64 * 8, 1, 4, 1, 0, bias=False), 
            nn.Flatten (1)
            nn.Linear (255, 1)
        )
</code></pre>
<p>Good luck!</p>
<p>K. Frank</p>

kpullela10: <p>Hi KFrank!</p>
<p>First off, just wanted to say that I really appreciate the in-depth response, as I’ve definitely gained some new insight into my code from it.</p>
<p>So, I went through my code and made some edits. I changed my train_transform to resize my image to<br>
<code>512, 512,</code> and updated my discriminator with the <code>Flatten(1)</code> and linear layer instead of <code>Sigmoid()</code> (in addition to changing the loss function and removing <code>.view(-1)</code> - thanks for the tips!).</p>
<p>However, it seems that <code>Flatten(1)</code> gives a shape of <code>64, 841</code> (which I’d assume to be the result of 29*29 that comes from the previous layer - but please correct me if I’m mistaken), and therefore throws an error since the <code>64, 841</code> and <code>255, 1</code> matrices cannot be multiplied.</p>
<p>Is my understanding correct so far? Or have I perhaps missed something else that led to this multiplication error? Apologies if this is a fairly straightforward question, and again, thanks for your guidance.</p>

KFrank: <p>Hi kpullela!</p>
<aside class="quote no-group" data-username="kpullela10" data-post="3" data-topic="173451" data-full="true">
<div class="title">
<div class="quote-controls"></div>
<img loading="lazy" alt="" width="24" height="24" src="https://discuss.pytorch.org/user_avatar/discuss.pytorch.org/kpullela10/48/57707_2.png" class="avatar"> kpullela10:</div>
<blockquote>
<p>I changed my train_transform to resize my image to<br>
<code>512, 512,</code></p>
</blockquote>
</aside>
<p>That was my mistake – you do want your input images to have <code>H = W = 299</code>.<br>
(I had miscalculated the output size of the last <code>Conv2</code> layer and overlooked<br>
the <code>transforms.Resize((299, 299))</code> in your original post.)</p>
<aside class="quote no-group">
<blockquote>
<p>However, it seems that <code>Flatten(1)</code> gives a shape of <code>64, 841</code> (which I’d assume to be the result of 29*29 that comes from the previous layer - but please correct me if I’m mistaken), and therefore throws an error since the <code>64, 841</code> and <code>255, 1</code> matrices cannot be multiplied.</p>
</blockquote>
</aside>
<p>Yes, you are correct.  <code>512 * 512</code> input images lead to <code>29 * 29</code> images after the<br>
final <code>Conv2</code> so you should stick with your original <code>299 * 299</code> input images to<br>
get <code>15 * 15</code> after the final <code>Conv2</code> which will match the <code>255</code> of the <code>Linear</code> layer<br>
after <code>Flatten</code>.</p>
<p>Best.</p>
<p>K. Frank</p>

J_Johnson: <p><a class="mention" href="/u/kpullela10">@kpullela10</a>  Just to add to the excellent answer from <a class="mention" href="/u/kfrank">@KFrank</a> , you can dynamically resize the images as a layer by using <code>nn.AdaptivePool2d</code> either before the conv2d layers, after, or somewhere in the middle. The way it works is that you specify the size you want out. For example:</p>
<pre><code class="lang-auto">...
self.NUM_GPU = NUM_GPU
self.ap=nn.AdaptivePool2d((299,299))
self.main = nn.Sequential( 
...
def forward(self, input):
        input=self.ap(input)
        return self.main(input)
...
</code></pre>
<p>Each location to place this layer has it’s advantages and disadvantages. Placing it at the beginning will make the model stronger on the macro picture feature representations/detection but weaker on learning textures.</p>
<p>At the end will make the model good on textures but weaker on macro detection.</p>
<p>In the middle gives you a better mix of both macro and texture detection.</p>

kpullela10: <p>Hi KFrank,</p>
<p>Once again, thanks for the clarification. It’s now working, thanks to your suggestions.</p>
<p>Just a quick follow-up however, it’s with my generator.<br>
(for reference, my generator code):</p>
<pre><code class="lang-auto">class Generator(nn.Module):
    def __init__(self, NUM_GPU):
        super(Generator, self).__init__()
        self.NUM_GPU = NUM_GPU
        self.main = nn.Sequential(
            nn.ConvTranspose2d(100, 64 * 8, 4, 1, 0, bias=False),
            nn.BatchNorm2d(64 * 8),
            nn.ReLU(True),
            nn.ConvTranspose2d(64 * 8, 64 * \
                               4, 4, 2, 1, bias=False),
            nn.BatchNorm2d(64 * 4),
            nn.ReLU(True),
            nn.ConvTranspose2d(64 * 4, 64 * \
                               2, 4, 2, 1, bias=False),
            nn.BatchNorm2d(64 * 2),
            nn.ReLU(True),
            nn.ConvTranspose2d(64 * 2, 64, 4, 2, 1, bias=False),
            nn.BatchNorm2d(64),
            nn.ReLU(True),
            nn.ConvTranspose2d(64, 3, 4, 2, 1, bias=False),
            nn.Tanh()
        )

    def forward(self, input):
        return self.main(input)
</code></pre>
<p>(the place where I’m passing the generator’s results into the discriminator, inside of my train function):</p>
<pre><code class="lang-auto">            noise = torch.randn(64, 100, 1, 1, device=DEVICE)
  
            print(noise.shape) # ---&gt; torch.Size([64, 100, 1, 1])
            fake = MODEL(noise)
            print(fake.shape) # ---&gt; torch.Size([64, 3, 64, 64])
            label.fill_(FAKE_LABEL)
            output = DISCRIM(fake.detach())
</code></pre>
<p>I’ve assumed that I need to make similar changes since when I try to pass the fake data generated by the generator into the discriminator, I get a matrix multiplication error in the last linear of the discriminator: <code>64x1</code> against <code>225x1</code> (also, I presume you meant 225 instead of 255 above for 15^2?).</p>
<p>After looking at the shape of the fake data generated, its height and width are both <code>64</code>, whereas I should be expecting <code>H = W = 299</code> if I’ve understood this correctly.</p>
<p>I’ve been playing around with resizing <code>fake</code> to <code>299x299</code>, but that doesn’t seem to be a great approach, as errors were raised since <code>64x3x64x64 (786,432 items)</code> can’t be reshaped into <code>299x299 (89401 items)</code>.</p>
<p>My next step was to then change the layers of the generator, but this is where I got stuck, as I’m not sure how to change my layers to get 299.</p>
<p>I guess my question is, am I looking in the right direction? Or is the error actually a result of something else, and not my generator?</p>
<p>Again, really appreciate the help. Please let me know if I can clarify anything!</p>

kpullela10: <p>Hi J_Johnson,</p>
<p>Thanks for the tip! I think I’m currently running into some shape misalignments with my generator, so I’ll try this out, and see how it goes.</p>

J_Johnson: <p>There are two approaches for getting the exact size out of your layers:</p>
<ol>
<li>Just use a print statement at the point in question - i.e. trial and error.</li>
<li>Calculate for each layer using the docs. For example, for Conv2d it is:</li>
</ol>
<p><div class="lightbox-wrapper"><a class="lightbox" href="https://discuss.pytorch.org/uploads/default/original/3X/a/0/a0c41aac1724fc63702ea28fc9c462d7f964c23a.jpeg" data-download-href="https://discuss.pytorch.org/uploads/default/a0c41aac1724fc63702ea28fc9c462d7f964c23a" title="Screenshot_2023-02-26-21-14-08-06_40deb401b9ffe8e1df2f1cc5ba480b12"><img src="https://discuss.pytorch.org/uploads/default/optimized/3X/a/0/a0c41aac1724fc63702ea28fc9c462d7f964c23a_2_690x310.jpeg" alt="Screenshot_2023-02-26-21-14-08-06_40deb401b9ffe8e1df2f1cc5ba480b12" data-base62-sha1="mWcxSY16hUZGuukoylSi3xtUa1A" width="690" height="310" srcset="https://discuss.pytorch.org/uploads/default/optimized/3X/a/0/a0c41aac1724fc63702ea28fc9c462d7f964c23a_2_690x310.jpeg, https://discuss.pytorch.org/uploads/default/optimized/3X/a/0/a0c41aac1724fc63702ea28fc9c462d7f964c23a_2_1035x465.jpeg 1.5x, https://discuss.pytorch.org/uploads/default/optimized/3X/a/0/a0c41aac1724fc63702ea28fc9c462d7f964c23a_2_1380x620.jpeg 2x" data-dominant-color="D6D5D5"><div class="meta"><svg class="fa d-icon d-icon-far-image svg-icon" aria-hidden="true"><use href="#far-image"></use></svg><span class="filename">Screenshot_2023-02-26-21-14-08-06_40deb401b9ffe8e1df2f1cc5ba480b12</span><span class="informations">2400×1080 162 KB</span><svg class="fa d-icon d-icon-discourse-expand svg-icon" aria-hidden="true"><use href="#discourse-expand"></use></svg></div></a></div></p>

KFrank: <p>Hi kpullela!</p>
<aside class="quote no-group" data-username="kpullela10" data-post="6" data-topic="173451" data-full="true">
<div class="title">
<div class="quote-controls"></div>
<img loading="lazy" alt="" width="24" height="24" src="https://discuss.pytorch.org/user_avatar/discuss.pytorch.org/kpullela10/48/57707_2.png" class="avatar"> kpullela10:</div>
<blockquote>
<p>Or is the error actually a result of something else, and not my generator?</p>
</blockquote>
</aside>
<p>I wouldn’t say that the error is in your generator, per se.  Rather, your generator<br>
and discriminator don’t match, in that your generator produces images with<br>
spatial size <code>H = W = 64</code>, while your discriminator expects <code>H = W = 299</code>.</p>
<p>Some perspective on what is going on:</p>
<p>Your discriminator has a number of <code>Con2d</code> layers.  Because that have <code>stride</code><br>
greater than <code>1</code>, they are, in sense, down-sampling your images, reducing <code>H</code><br>
and <code>W</code> (while encoding some of the spatial information into the increasingly<br>
large channels dimension).</p>
<p>Conversely, the <code>ConvTranspose2d</code> layers are up-sampling the (initially <code>1 * 1</code>)<br>
“noise” images you pass in (moving channels information into the increasing<br>
spatial extent).</p>
<p>The main driver in the change in image size is the <code>stride</code> parameter, but the<br>
<code>kernel_size</code> and <code>padding</code> parameters also affect the spatial size of the output<br>
of the convolutional layers.</p>
<p>You need to chain together the appropriate up-sampling (generator) and<br>
down-sampling (discriminator) layers together to get your generator and<br>
discriminator to get sizes that are consistent with one another.</p>
<p>For debugging and development purposes, I would get rid the <code>Sequential</code>s<br>
that wrap your layers and chain them together explicitly in your <code>forward()</code><br>
methods.  This way you can add <code>print()</code> statements that track the image<br>
sizes as they pass through the layers.</p>
<p>Here is a simple illustration of this:</p>
<pre><code class="lang-plaintext">&gt;&gt;&gt; import torch
&gt;&gt;&gt; print (torch.__version__)
1.13.1
&gt;&gt;&gt;
&gt;&gt;&gt; _ = torch.manual_seed (2023)
&gt;&gt;&gt;
&gt;&gt;&gt; class Model (torch.nn.Module):
...     def __init__(self):
...         super().__init__()
...         self.conv1 = torch.nn.Conv2d(3, 64, 4, 2, 1, bias=False)
...         self.relu1 = torch.nn.LeakyReLU(0.2, inplace=True)
...         self.conv2 = torch.nn.Conv2d(64, 64 * 2, 4, 2, 1, bias=False)
...         self.relu2 = torch.nn.LeakyReLU(0.2, inplace=True)
...         self.conv3 = torch.nn.Conv2d(64 * 2, 64 * 4, 4, 2, 1, bias=False)
...
...     def forward (self, x):
...         print (x.shape)
...         x = self.conv1 (x)
...         print (x.shape)
...         x = self.relu1 (x)
...         x = self.conv2 (x)
...         print (x.shape)
...         x = self.relu2 (x)
...         x = self.conv3 (x)
...         print (x.shape)
...         return x
...
&gt;&gt;&gt; model = Model()
&gt;&gt;&gt;
&gt;&gt;&gt; input = torch.randn (1, 3, 299, 299)
&gt;&gt;&gt;
&gt;&gt;&gt; y = model (input)
torch.Size([1, 3, 299, 299])
torch.Size([1, 64, 149, 149])
torch.Size([1, 128, 74, 74])
torch.Size([1, 256, 37, 37])
</code></pre>
<p>I assume that you have a dataset of real images.  If these are all of the same<br>
size, I would use that size for the generator output size and discriminator input<br>
size, unless that size in unwieldy.  (There’s nothing special about <code>299 * 299</code>.)<br>
If the sizes of your real images vary, then using <code>Resize()</code> makes sense, but I<br>
would resize to a spatial extent that is “typical” of your real images.</p>
<p>As Jay suggested, look at the documentation for <code>Conv2d</code> and <code>ConvTranspose2d</code><br>
to get a sense of how the interplay between the various parameters determines<br>
the size of the output image.  That way, you can design your layers in an informed<br>
way to do what you want.</p>
<p>As an aside, remember that you will be training your generator to generate images<br>
that look like whatever gets input to your discriminator as “real” images.  So if you<br>
use various transforms as part of your dataloader pipeline, you will be training your<br>
generator to mimic the results of those transforms (rather than the raw images in<br>
your untransformed dataset).</p>
<p>Best.</p>
<p>K. Frank</p>

kpullela10: <p>Got it. Thanks, will do.</p>

kpullela10: <p>Ah, ok. I’m going to then reduce the amount of transforming I do before passing images to the discriminator. Thanks!</p>