[CNN IMAGE SEGMENTATION] RuntimeError: only batches of spatial targets supported (3D tensors) but got targets of size: : [10, 3, 388, 388]

DiWarp: <p>Hi there! I’m trying to code a CNN for a Rabbin Dataset and got some issues.</p>
<p>My dataset is looks like this: <a href="https://lh3.googleusercontent.com/_gCuIdNUnRDE-f9mkOYZyQzd3BePBM6SMPP06KFe3okDjxrWJ-9fBj6jTxoWN9h7nXW-ETYFlNqcEmsHdijrEkaqfAv0YscAu-B-5HVEuHGI9NwnVKvrsdGcVRjxeeR6SVOQfrQs8QTY9scvlTceLH-n-M-r7E_d6BjMAdP0D6BGub2ffQ7q-8kyyxSEXfkJipfTwEUS-GDEh_sNhvYl0BKLaE2SjkytTiHUeieV16Zd1m8GG7LXKEZnBbfDFwzapJOO2fFbM6I39eD6SHg7bX5shVaBYgR-Rgp3qaq1a0ZwuC1qSElAT5mbXwv-qj_bPz6cK1nfKBAjsXfwE5uOdpCA5RsrlcOvtLHEaC__kGsLmhGHFPEPGgl3fqTFPWVW4_3GKrv-zaPGetnRpIZzJXLH19fvPh8oD3zb3zDz0rLpXYVvrTpYl-i6SRC0YTEThDezKjKGRuweVUiyh5rRhLxoYpJRPWDqM7eh5-V9D6ww2tgLSaoYUUhk8OCWtPWoXSs_CjTPsnkZOVqos3YIcd-Cx89MpVaz8c-TgWy5w_Y7oumieTJGreQXLfxjVk--mb3n2JMNKzCTBDyCYKFaH1I2X_SC1amJmr9NPoUSW2iKcjq5WoBMCFwiQVQyG4KF3uzNlDeQuzuadZOi8IkmYXJIrY49NvIGycbUUlVgON235Yhy2za3FnsJneVKWMzvW3tA6PIF0qJ5U0BEbzzQO48EO3JYrbzkuevybFmK7Nvpn9sg-DPQ5UYx-Vzm6wXEJa1Ddocp5MTSm4CYtq9cLfvqCXI9NDFwwXYw=w498-h251-no?authuser=0" rel="noopener nofollow ugc">Example</a></p>
<p>I’m using the UNet Architecture, the input image is 572x572 and the output image is 388x388.</p>
<p>My Dataset class is like this:</p>
<pre><code class="lang-auto">learning_rate = 1e-3
batch_size = 10
epochs = 10

class MyDataset(Dataset):

  def __init__(self, root_dir, transform = None, transform2 = None):

    self.root_dir = root_dir
    self.names = os.listdir(os.path.join(self.root_dir, "Original"))
    self.transform = transform
    self.transform2 = transform2

  def __len__(self):
    return len(self.names)

  def classes(self):
    return torch.Tensor([0,1,2]) 

  def __getitem__(self, idx):

    if torch.is_tensor(idx):
      idx = idx.tolist()

    image_name = self.names[idx]
    image = io.imread(os.path.join(self.root_dir, "Original", image_name))

    label = io.imread(os.path.join(self.root_dir, "Ground Truth", image_name))

    if self.transform is not None:
      image = self.transform(image)

    if self.transform2 is not None:
      label = self.transform2(label)
        
    return image, label

transformations = transforms.Compose(
    [transforms.ToTensor(),
     transforms.CenterCrop(572)]
)

transformations2 = transforms.Compose(
    [transforms.ToTensor(),
     transforms.CenterCrop(388)]
)

</code></pre>
<p>And my training function:</p>
<pre><code class="lang-auto">def training(model, dataloader, lossFn, opt):

  model.train()

  totalTrainLoss = 0
  trainCorrect = 0

  for x, y in dataloader:
    x = x.to(device)
    y = y.to(device)

    pred = model(x)
    loss = lossFn(pred, y)

    opt.zero_grad()

    loss.backward()
  
    opt.step()
  
    totalTrainLoss += loss
    trainCorrect += (pred.argmax(1) == y).type(torch.float).sum().item()
  
  return totalTrainLoss, trainCorrect

</code></pre>
<p>I’m using this as an optimizer and loss funciton:</p>
<pre><code class="lang-auto">opt = Adam(model.parameters(), lr = learning_rate)
lossFn = nn.NLLLoss()
</code></pre>
<p>I call the training function on a for loop to run the epochs.:</p>
<pre><code class="lang-auto">for e in range(0, epochs):

  (totalTrainLoss, trainCorrect) = training(model, train_dataLoader, lossFn, opt)
  (totalValLoss, valCorrect) = validation(model, train_dataLoader, lossFn)
  
  avgTrainLoss = totalTrainLoss / train_Steps
  avgValLoss = totalValLoss / val_Steps
  
  trainCorrect = trainCorrect / len(train_dataLoader.dataset)
  valCorrect = valCorrect / len(val_dataLoader.dataset)

  print("[INFO] EPOCH: {}/{}".format(e + 1, epochs))
  print("Train loss: {:.6f}, Train accuracy: {:.4f}".format(avgTrainLoss, trainCorrect))
  print("Val loss: {:.6f}, Val accuracy: {:.4f}\n".format(avgValLoss, valCorrect))
</code></pre>
<p>But everytime it gives the same error message on the <code>loss = lossFn(pred, y)</code> : <strong>“RuntimeError: only batches of spatial targets supported (3D tensors) but got targets of size: : [10, 3, 388, 388]”</strong>. How can I solve it?</p>
<p>Any help would be deeply appreciated! <img src="https://discuss.pytorch.org/images/emoji/apple/slight_smile.png?v=12" title=":slight_smile:" class="emoji" alt=":slight_smile:" loading="lazy" width="20" height="20"></p>

ptrblck: <p>Your target should have the shape <code>[batch_size, height, width]</code> and contain class indices in the range <code>[0, nb_classes-1]</code> for a multi-class segmentation use case as seen here:</p>
<pre><code class="lang-python">
criterion = nn.NLLLoss()

batch_size = 2
height = width = 24
nb_classes = 10
output = torch.randn(batch_size, nb_classes, height, width, requires_grad=True)

# works
target = torch.randint(0, nb_classes, (batch_size, height, width))
loss = criterion(output, target)

# fails
target = torch.randint(0, nb_classes, (batch_size, nb_classes, height, width))
loss = criterion(output, target)
# RuntimeError: only batches of spatial targets supported (3D tensors) but got targets of dimension: 4
</code></pre>
<p>while your current target has 4 dimensions.</p>

DiWarp: <p>Hello <a class="mention" href="/u/ptrblck">@ptrblck</a>, thanks for your reply. But I still didn’t get it how to shrink my target, which in my case is the variable y, to these 3 dimensions only.</p>
<p>I forgot to say that my cnn segments 3 regions.</p>

DiWarp: <p>If I write:</p>
<pre><code class="lang-auto">for e in range(0, epochs):
   
   model.train()
   
   
   totalTrainLoss = 0
   totalValidLoss = 0
   
   
   trainCorrect = 0
   validCorrect = 0
   
   # Loop over training set
   for i, batch in enumerate(train_dataLoader):

       x, y = batch

       x, y = x.to(device), y.to(device)

       print(y.size())
       opt.zero_grad()
       
       pred = model(x)

       y = torch.randint(0, 3, (batch_size, 388, 388))


       loss = lossFn(pred, y)
       
       loss.backward()
       opt.step()
       
       totalTrainLoss += loss
       trainCorrect += (pred.argmax(1)==y).type(torch.float).sum().item()
</code></pre>
<p>The error message dissapears, but, I don’t understand one thing: <code>y</code> will still be my label by calling it as <code>y = torch.randint(0, 3, (batch_size, 388, 388))</code>? It will still be the same label imported in my dataset?</p>

ptrblck: <p>No, you are creating <code>y</code> with random values in <code>[0, 2]</code> now which are not your true class targets.<br>
My code snippet uses random tensors to show the needed shape and value range since I do not have access to your real dataset.<br>
As previously described: the target should have the the shape <code>[batch_size, height, width]</code> and contain class indices in the range <code>[0, nb_classes-1]</code> for a multi-class segmentation use case. If your true target still has 4 dimensions, you might be using a one-hot encoded target. In that case, use <code>target = torch.argmax(target, dim=1)</code> to create the expected target tensor.</p>

DiWarp: <p><a class="mention" href="/u/ptrblck">@ptrblck</a> Thank you. It solved the error message!</p>