Model is Stucking at One Category

Xeonen: <p>I have been working on PyTorch for quite a while, I’ve read several books, investigated other books but no matter what I do models I make try to predict the same output and never leave that area. Here is the latest example. The original model (made in Tensorflow) reaches 92% accuracy but when I copy it exactly as it is… I get stuck in a single category. I’ve been working on this for 3 months. I’ve thrown the towel and decided to search for external help.</p>
<p>This is the code.</p>
<h1>
<a name="h-1" class="anchor" href="#h-1"></a>%%</h1>
<p>import torch<br>
import torch.nn as nn<br>
from torchvision import datasets, transforms<br>
from torch.utils.data import DataLoader</p>
<h1>
<a name="h-2" class="anchor" href="#h-2"></a>%%</h1>
<p>train_path = “D:\Datasets\Pnemonia\train_set\”<br>
val_path = “D:\Datasets\Pnemonia\val_set\”<br>
test_path = “D:\Datasets\Pnemonia\test\”<br>
train_transform = transforms.Compose([transforms.Resize((224, 224)),<br>
transforms.Grayscale(),<br>
transforms.ToTensor(),<br>
transforms.RandomHorizontalFlip(0.3),<br>
transforms.RandomRotation(30),<br>
transforms.Normalize(mean=[0.4799], std=[0.05077])<br>
])</p>
<p>val_transform = transforms.Compose([transforms.Resize((224, 224)),<br>
transforms.Grayscale(),<br>
transforms.ToTensor(),<br>
transforms.Normalize(mean=[0.4799], std=[0.05077])<br>
])</p>
<p>trainset = datasets.ImageFolder(train_path, transform=train_transform) # TODO: create the ImageFolder<br>
trainloader = DataLoader(trainset, batch_size=32, shuffle=True)</p>
<p>valset = datasets.ImageFolder(val_path, transform=val_transform) # TODO: create the ImageFolder<br>
valloader = DataLoader(valset, batch_size=32, shuffle=True)</p>
<p>testset = datasets.ImageFolder(test_path, transform=val_transform) # TODO: create the ImageFolder<br>
testloader = DataLoader(testset, batch_size=32, shuffle=True)</p>
<h1>
<a name="h-3" class="anchor" href="#h-3"></a>%%</h1>
<p>class PneModel(nn.Module):<br>
def <strong>init</strong>(self) → None:<br>
super(PneModel, self).<strong>init</strong>()<br>
self.convBlock01 = self.convBlock(1, 32, (3, 3), 1)<br>
self.convBlock02 = self.convBlock(32, 64, (3, 3), 1, 0.1)<br>
self.convBlock03 = self.convBlock(64, 64, (3, 3), 1)<br>
self.convBlock04 = self.convBlock(64, 128, (3, 3), 1, 0.2)<br>
self.convBlock05 = self.convBlock(128, 256, (3, 3), 1, 0.2)<br>
self.flatten = nn.Flatten()<br>
self.linear01 = nn.Linear(12544, 128)<br>
self.act01 = nn.ReLU()<br>
self.dropout01 = nn.Dropout(0.2)<br>
self.linear02 = nn.Linear(128, 2)<br>
self.out = nn.Softmax(dim=1)</p>
<pre><code>def forward(self, x):
    x = self.convBlock01(x)
    x = self.convBlock02(x)
    x = self.convBlock03(x)
    x = self.convBlock04(x)
    x = self.convBlock05(x)
    x = self.flatten(x)
    x = self.linear01(x)
    x = self.act01(x)
    x = self.dropout01(x)
    x = self.linear02(x)
    return(self.out(x))

def convBlock(self, ic, oc, ks, s, dropout=None):
    if dropout == None:
        model = nn.Sequential(nn.Conv2d(in_channels=ic, out_channels=oc, kernel_size=ks, stride=s, padding="same"),
                          nn.ReLU(), nn.BatchNorm2d(oc), nn.MaxPool2d((2, 2), stride=2))
    else:
        model = nn.Sequential(nn.Conv2d(in_channels=ic, out_channels=oc, kernel_size=ks, stride=s, padding="same"),
                          nn.ReLU(), nn.Dropout(dropout), nn.BatchNorm2d(oc), nn.MaxPool2d((2, 2), stride=2))
    return(model)
</code></pre>
<h1>
<a name="h-4" class="anchor" href="#h-4"></a>%%</h1>
<p>images, labels = next(iter(valloader))</p>
<p>model = PneModel()<br>
device = torch.device(“cuda:0” if torch.cuda.is_available() else “cpu”)<br>
model = model.to(device)</p>
<h1>
<a name="h-5" class="anchor" href="#h-5"></a>%%</h1>
<p>from fastai.vision.all import *<br>
data = DataLoaders(trainloader, valloader)<br>
learn = Learner(data, model, loss_func=F.nll_loss, opt_func=RMSProp, metrics=accuracy)</p>
<h1>
<a name="h-6" class="anchor" href="#h-6"></a>%%</h1>
<p>learn.fit(5, 1e-3)</p>
<h1>
<a name="h-7" class="anchor" href="#h-7"></a>%%</h1>

KFrank: <p>Hi Salih!</p>
<aside class="quote no-group" data-username="Xeonen" data-post="1" data-topic="163105" 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/xeonen/48/53310_2.png" class="avatar"> Xeonen:</div>
<blockquote>
<p>The original model (made in Tensorflow) reaches 92% accuracy but when I copy it exactly as it is…</p>
</blockquote>
</aside>
<p>As I’m sure you are aware, but just to be clear, you can’t copy a tensorflow<br>
model “exactly as it is” and have it work in pytorch.</p>
<p>Pytorch and tensorflow do similar things, but do them differently in detail,<br>
so you have to <em>translate</em> a tensorflow model into pytorch.  Make sure that<br>
you understand how the tensorflow features that you are using work.  Find<br>
the pytorch features that do <em>approximately</em> the same thing, make sure that<br>
you understand how they work, and then modify your code to account for<br>
any differences.</p>
<aside class="quote no-group">
<blockquote>
<pre><code>    self.linear02 = nn.Linear(128, 2)
    self.out = nn.Softmax(dim=1)
</code></pre>
<p>…</p>
<p>learn = Learner(data, model, loss_func=F.nll_loss, opt_func=RMSProp, metrics=accuracy)</p>
</blockquote>
</aside>
<p>It appears that you are passing the two outputs of a <code>Linear</code> through<br>
<code>Softmax</code> and then using the “probabilities” produced by <code>Softmax</code> as your<br>
model’s predictions that then get passed into your loss functions, <code>nll_loss()</code>.</p>
<p>According to the documentation for <a href="https://pytorch.org/docs/1.12/generated/torch.nn.NLLLoss.html#torch.nn.NLLLoss" rel="noopener nofollow ugc">NLLLoss</a> (which fills in the details<br>
for <code>nll_loss()</code>), <code>nll_loss()</code> expects <em>log-probabilities</em> (not probabilities)<br>
for the predictions you pass in.  You should therefore use <code>LogSoftmax</code><br>
(instead of <code>Softmax</code>) for your <code>self.out</code> layer.</p>
<p>Also print out the shape, type, and some sample values for the predictions<br>
and targets that get passed into <code>nll_loss()</code> – similar-looking loss functions<br>
in tensorflow and pytorch often have different requirements for the inputs<br>
they expect.</p>
<p>Good luck!</p>
<p>K. Frank</p>