Can't find RuntimeError: only batches of spatial targets supported (3D tensors) but got targets of dimension: 1

Hello, I’ve got a following error:

    RuntimeError                              Traceback (most recent call last)
    <timed exec> in <module>

    /var/folders/m8/5njk8q3d30v78xxjn6n610km0000gn/T/ipykernel_12796/1284205556.py in train(model,              opt, n_epochs)
     63     for epoch in range(n_epochs):
     64         print("Epoch {} of {}".format(epoch, n_epochs))
---> 65         train_loss, train_acc = train_epoch(model, opt, batchsize=batchsize)
     66 
     67         val_loss, val_acc = test(model)

    /var/folders/m8/5njk8q3d30v78xxjn6n610km0000gn/T/ipykernel_12796/1284205556.py in     train_epoch(model, optimizer, batchsize)
     15         acc_log.append(acc)
     16 
---> 17         loss = F.nll_loss(output, target)
     18         loss.backward()
     19         optimizer.step()

~/opt/anaconda3/lib/python3.9/site-packages/torch/nn/functional.py in nll_loss(input, target, weight, size_average, ignore_index, reduce, reduction)
   2530     if size_average is not None or reduce is not None:
   2531         reduction = _Reduction.legacy_get_string(size_average, reduce)
-> 2532     return torch._C._nn.nll_loss_nd(input, target, weight, _Reduction.get_enum(reduction), ignore_index)
   2533 
   2534 

RuntimeError: only batches of spatial targets supported (3D tensors) but got targets of dimension: 1

My model is:

class ConvNet(nn.Module):
    def __init__(self):
        super().__init__()
    
    self.features = nn.Sequential(
        nn.Conv2d(in_channels=1, out_channels=6, kernel_size=5, stride=1),
        nn.ReLU(),
        nn.MaxPool2d((2, 2)),
        nn.Conv2d(in_channels=6, out_channels=4, kernel_size=5, stride=1),
        nn.ReLU(),
        nn.MaxPool2d((2, 2)),
        nn.Linear(4, 4 * 4 * 16),
    )
    
    self.classifier = nn.Linear(4 * 4 * 16, 10)

    
def forward(self, x):
    print(x.size())
    x = x.reshape(32, 28, 28)[:, None, :, :]
    print(x.size())
    x = self.features(x)
    #x = torch.flatten(x, 1)
    print(x.size())
    out = self.classifier(x)
    print(out.size())

    return F.log_softmax(out, dim=-1)

With the following code:

from util import iterate_minibatches

def train_epoch(model, optimizer, batchsize=32):
loss_log, acc_log = [], []
model.train()
    for x_batch, y_batch in iterate_minibatches(X_train, y_train, batchsize=batchsize, shuffle=True):
        data = torch.from_numpy(x_batch.astype(np.float32))
        target = torch.from_numpy(y_batch.astype(np.int64))

        optimizer.zero_grad()
        output = model(data)
    
        pred = torch.max(output, 1)[1].numpy()
        acc = np.mean(pred == y_batch)
        acc_log.append(acc)
    
        loss = F.nll_loss(output, target)
        loss.backward()
        optimizer.step()
        loss = loss.item()
        loss_log.append(loss)
    return loss_log, acc_log

def test(model):
    loss_log, acc_log = [], []
    model.eval()
    for x_batch, y_batch in iterate_minibatches(X_val, y_val, batchsize=32, shuffle=True):
        data = torch.from_numpy(x_batch.astype(np.float32))
        target = torch.from_numpy(y_batch.astype(np.int64))

        output = model(data)
        loss = F.nll_loss(output, target)
    
        pred = torch.max(output, 1)[1].numpy()
        acc = np.mean(pred == y_batch)
        acc_log.append(acc)
    
        loss = loss.item()
        loss_log.append(loss)
    return loss_log, acc_log

def plot_history(train_history, val_history, title='loss'):
    plt.figure()
    plt.title('{}'.format(title))
    plt.plot(train_history, label='train', zorder=1)

    points = np.array(val_history)

    plt.scatter(points[:, 0], points[:, 1], marker='+', s=180, c='orange', label='val', zorder=2)
    plt.xlabel('train steps')
    
    plt.legend(loc='best')
    plt.grid()

    plt.show()

def train(model, opt, n_epochs):
    train_log, train_acc_log = [], []
    val_log, val_acc_log = [], []

    batchsize = 32

    for epoch in range(n_epochs):
        print("Epoch {} of {}".format(epoch, n_epochs))
        train_loss, train_acc = train_epoch(model, opt, batchsize=batchsize)

       val_loss, val_acc = test(model)

        train_log.extend(train_loss)
        train_acc_log.extend(train_acc)

        steps = len(X_train) / batchsize
        val_log.append((steps * (epoch + 1), np.mean(val_loss)))
        val_acc_log.append((steps * (epoch + 1), np.mean(val_acc)))

        clear_output()
        plot_history(train_log, val_log)    
        plot_history(train_acc_log, val_acc_log, title='accuracy')
        print("Epoch {} error = {:.2%}".format(epoch, 1 - val_acc_log[-1][1]))
        
    print("Final error: {:.2%}".format(1 - val_acc_log[-1][1]))

I am running model with:

model = ConvNet()
opt = torch.optim.RMSprop(model.parameters(), lr=0.001)
train(model, opt, 5)

Dataset is MNIST:

  from util import load_mnist
  X_train, y_train, X_val, y_val, X_test, y_test = load_mnist(flatten=True)

  plt.figure(figsize=[6, 6])
  for i in range(4):
     plt.subplot(2, 2, i + 1)
     plt.title("Label: %i" % y_train[i])
     plt.imshow(X_train[i].reshape([28, 28]), cmap='gray');

I can’t find an answer in other topics :frowning:

Based on the error message it seems your model output might be 4-dimensional as seen here:

criterion = nn.NLLLoss()

output = torch.randn(2, 3, 4, 4, requires_grad=True)
target = torch.randint(0, 3, (2,))
loss = criterion(output, target)
# RuntimeError: only batches of spatial targets supported (3D tensors) but got targets of dimension: 1

output = torch.randn(2, 3, requires_grad=True)
loss = criterion(output, target) # works

However, I cannot find any obvious issues in your code as it seems you are properly flattening the activation, so could you post a minimal, executable code snippet reproducing the error, please?

I have updated and posted literally all the code that I have

Your code is unfortunately still not executable, but I just saw that you’ve commented out the flattening operation:

#x = torch.flatten(x, 1)

Use it again, check for shape mismatches in linear layers, fix these (if applicable), and it should work.

I realized that I’ve got 2 dense layers and I deleted the raw

nn.Linear(4, 4 * 4 * 16),

in my model.

But now I have with matrices:
RuntimeError: mat1 and mat2 shapes cannot be multiplied (672x7 and 256x10)

How should I choose parameters to fix it? I haven’t been able to select them for quite a while now.

The shape sounds wrong, since you were previously using a batch size of 32 based on your code.
You should also not use a linear layer in the features pat without flattening the activation unless you really want to apply the linear layer sequentially only on the width dimension of the forward activation.
This code should work:

class ConvNet(nn.Module):
    def __init__(self):
        super().__init__()
        self.features = nn.Sequential(
            nn.Conv2d(in_channels=1, out_channels=6, kernel_size=5, stride=1),
            nn.ReLU(),
            nn.MaxPool2d((2, 2)),
            nn.Conv2d(in_channels=6, out_channels=4, kernel_size=5, stride=1),
            nn.ReLU(),
            nn.MaxPool2d((2, 2)),
        )
        self.classifier = nn.Linear(64, 10)
        
    def forward(self, x):
        x = self.features(x)
        x = torch.flatten(x, 1)
        out = self.classifier(x)
        return F.log_softmax(out, dim=-1)
    
model = ConvNet()
x = torch.randn(32, 1, 28, 28)
out = model(x)

Yeah, this works! Thanks a lot!