[SOLVED] GAN with 3 networks

username: Peter_Featherstone
cooked: <p>I have 2 generators. Both are competing against each other in typical GAN fashion.<br>
The 1st generator acts like an auto-encoder and the 2nd generator outputs a different result.<br>
I want to introduce a 3rd network, i.e. a classifier, that classifies the input and output of the 1st generator into 1 of 2 classes: encoded and non-encoded.<br>
When training, all three losses (1st, 2nd generators and classifier losses) decrease nicely, but when evaluating, the classifier loss is high (not the generators’). Now, you want the encoded and non-encoded tensors to be similar but I would expect the classifier to still perform well during evaluation.<br>
Is there any reason why 2 networks (2nd generator and classifier) competing against 1 network (1st generator) wouldn’t work?</p>
<p>Details:<br>
The classifier is an inceptionresnetv2 classifier taken from cadene/pretrainedmodels.<br>
The classifier loss is CrossEntropy (implicit logsoftmax activation function).<br>
All three losses are summed together to give a master loss. I then call loss.backward(), which should back-propagate gradients back through all three networks.</p>

username: tymokvo
cooked: <p>Think you could include a diagram of this setup? And maybe a reference of a similar project? It’s a bit unclear what the goal is.</p>
<p>I don’t think that you can just call <code>.backward()</code> on a summed loss (though I could be wrong) and have it propagate through all three of these networks in order to attribute the correct gradients to the various parameters. But again, it’s hard to tell without a clearer picture of what you are trying to accomplish.</p>
<p>This is a shameless self-reference, but <a href="https://github.com/tymokvo/AEGeAN/blob/50cbb1eed5b7dfca01a421a13c9ac9e8ac3dd421/AEGeAN_run.py#L182" rel="nofollow noopener">here</a> I was working with a GAN/Autoencoder setup that uses two loss calculations. One for the AE’s reconstruction loss, and one for the <code>D(G(z))</code> GAN loss. You may also look up the <a href="https://arxiv.org/pdf/1609.03126.pdf" rel="nofollow noopener">EBGAN paper</a> (Appendix C) which uses an autoencoder as a discriminator.</p>

username: Peter_Featherstone
cooked: <p>So you can call backward on summed loss</p>

username: Peter_Featherstone
cooked: <p>The purpose of the classifier is to act like a discriminator and improve the performance of the 1st generator. It’s also useful for me to know when the input of the 2nd generator is encoded or not encoded.</p>
<p>It’s worth saying that the 1st and 2nd generators still train perfectly fine and achieve similar results to when the classifier is not included. What’s weird is the loss function of the classifier decreases when the model is training, i.e. when classifier.train() is called, but not when it is evaluated, i.e. when classifier.eval() is called.</p>

username: tymokvo
cooked: <aside class="quote no-group" data-username="Peter_Featherstone" data-post="4" data-topic="47559">
<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/peter_featherstone/48/12813_2.png" class="avatar"> Peter_Featherstone:</div>
<blockquote>
<p>What’s weird is the loss function of the classifier decreases when the model is training, i.e. when classifier.train() is called, but not when it is evaluated, i.e. when classifier.eval() is called.</p>
</blockquote>
</aside>
<p>I am pretty sure that this is expected behavior. <code>.eval()</code> changes the behavior of certain <code>Module</code> supertypes. <code>Dropout</code>, for instance, becomes the identity function when that method is called on it.</p>

username: Peter_Featherstone
cooked: <p>Please let me clarify. I don’t expect the loss of the classifier to decrease when evaluating, but I would expect it to be roughly the same as when it is being trained. The loss of the classifier during training is ~ 0.001 using nn.CrossEntropy but is ~ 4.1 when evaluating.</p>

username: Peter_Featherstone
cooked: <p>Also, I checked, .eval() doesn’t affect nn.CrossEntropy</p>

username: tymokvo
cooked: <aside class="quote no-group" data-username="Peter_Featherstone" data-post="6" data-topic="47559">
<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/peter_featherstone/48/12813_2.png" class="avatar"> Peter_Featherstone:</div>
<blockquote>
<p>but I would expect it to be roughly the same as when it is being trained.</p>
</blockquote>
</aside>
<p>I think this is a shaky expectation. If a model does not reduce the value of the objective function on unseen examples after increased training, it is a sign that the model is not effective for the data.</p>
<p>But, it is unclear what “evaluation” means in the context of generative adversarial networks, without seeing the code that you’re working with (or a minimum viable example). GANs (from my knowledge) typically don’t have training/testing/validation passes in the way that a classifier does.</p>
<p>Though, I suppose StyleGAN uses Frechet inception distance to measure similarity of generated examples relative to the dataset.</p>

username: Peter_Featherstone
cooked: <p>Solved it! So when I feed the input and output of the 1st generator into the classifier, I was concatenating them batchwise WITHOUT any shuffling. This is bad. Turns out, this has the effect of training well but validating badly. If you randomise batchwise, it both trains and validates well.</p>

username: Peter_Featherstone
cooked: <p>Rookie mistake really. Hopes this helps someone in the future. ALWAYS randomise your inputs!</p>