How to Fix "0D or 1D Target Tensor Expected, Multi-Target Not Supported"

Your target tensor has 2 or more dimensions where PyTorch wants 0 or 1. For a model output of shape (N, C), nn.CrossEntropyLoss needs a target of shape (N) holding one class index per sample. A target of shape (N, 1) raises this error. Fix it with target = target.squeeze().

The class dimension belongs to the input, never to an index target. Output (32, 10) pairs with target (32), not (32, 1) and not (32, 10).

Check your own shapes

Enter the shape your model returns, the shape of your labels, the dtype of those labels, and the loss you call. The tool names the exact error PyTorch raises, or confirms the pair is valid. Every rule below was checked against torch 2.8.0 on CPU, and the error strings are copied from the real exceptions.

Runs entirely in your browser. Nothing you type is sent anywhere. The tool assumes a float32 model output. Leave the target box empty to mean a 0-dim scalar target.

The error

RuntimeError: 0D or 1D target tensor expected, multi-target not supported

This message comes from the ATen kernel behind nll_loss, which both nn.NLLLoss and nn.CrossEntropyLoss call. It appears on no PyTorch documentation page, which is why searching for it turns up forum threads instead of an answer.

The check is narrow. It fires only when the input has 1 or 2 dimensions and the target has 2 or more. A 4-dimensional segmentation output raises a different message, and the tool above tells you which one.

Cause 1, the target is (N, 1) instead of (N)

This is the common case. A label column arrives from a dataframe, or a stray unsqueeze(1) survives from an earlier experiment, and the batch dimension gains a companion.

output = model(x)              # (32, 10)
target = labels.unsqueeze(1)   # (32, 1)  wrong
loss = nn.CrossEntropyLoss()(output, target)
# RuntimeError: 0D or 1D target tensor expected, multi-target not supported

target = target.squeeze()      # (32)  correct
loss = nn.CrossEntropyLoss()(output, target)

Use squeeze() when the extra dimension is size 1. Use reshape(-1) when you want to flatten whatever arrived.

Cause 2, one-hot labels with NLLLoss

People one-hot encode labels because other frameworks want them that way. nn.NLLLoss has only one target mode, class indices, so a one-hot target of shape (N, C) raises the same error.

target = F.one_hot(labels, num_classes=10)   # (32, 10)
loss = nn.NLLLoss()(log_probs, target)
# RuntimeError: 0D or 1D target tensor expected, multi-target not supported

loss = nn.NLLLoss()(log_probs, labels)       # (32) long

nn.CrossEntropyLoss behaves differently here, and that difference confuses people. Read on.

Cause 3, the two target conventions of CrossEntropyLoss

Since PyTorch 1.10, nn.CrossEntropyLoss has two target modes and picks between them by comparing shapes.

The shape comparison happens first, so a one-hot torch.long target of shape (32, 10) never reaches the 0D or 1D check. It is routed to the probability branch and rejected on dtype instead:

RuntimeError: Expected floating point type for target with class probabilities, got Long

That is a useful signal. If you see the dtype message you passed a same-shape target. If you see the 0D or 1D message you passed a target that is neither the index shape nor the input shape.

Cause 4, the target is float when it should be long

Get the shape right and the next check is dtype. Class index targets must be int64.

RuntimeError: expected scalar type Long but found Float
RuntimeError: expected scalar type Long but found Int   # int32 labels

target = target.long()

On CUDA the same mistake surfaces as "nll_loss_forward_reduce_cuda_kernel_2d_index" not implemented for 'Float'. Same cause, different kernel.

What PyTorch 2.8.0 actually raises

Every row below was produced by running the pair through the loss on torch 2.8.0, CPU, and copying the exception. The model output is float32 in all rows. The tool at the top of this page reproduces all of them.

LossOutputTargetdtypeResult
CrossEntropyLoss(32, 10)(32)longValid
CrossEntropyLoss(32, 10)(32, 1)longRuntimeError: 0D or 1D target tensor expected, multi-target not supported
CrossEntropyLoss(32, 10)(32, 10)longRuntimeError: Expected floating point type for target with class probabilities, got Long
CrossEntropyLoss(32, 10)(32, 10)float32Valid, class probability mode
CrossEntropyLoss(32, 10)(32)float32RuntimeError: expected scalar type Long but found Float
CrossEntropyLoss(32, 10)(16)longValueError: Expected input batch_size (32) to match target batch_size (16).
CrossEntropyLoss(10)()longValid, unbatched
CrossEntropyLoss(10)(1)longRuntimeError: size mismatch (got input: [10], target: [1])
CrossEntropyLoss(4, 3, 8, 8)(4, 8, 8)longValid, K-dimensional
CrossEntropyLoss(4, 3, 8, 8)(4, 8, 8, 1)longRuntimeError: only batches of spatial targets supported (3D tensors) but got targets of dimension: 4
CrossEntropyLoss(2, 3, 4)(2, 4, 1)longRuntimeError: Expected target size [2, 4], got [2, 4, 1]
NLLLoss(32, 10)(32, 10)float32RuntimeError: 0D or 1D target tensor expected, multi-target not supported
BCELoss(32, 1)(32)float32ValueError: Using a target size (torch.Size([32])) that is different to the input size (torch.Size([32, 1])) is deprecated. Please ensure they have the same size.
BCEWithLogitsLoss(32, 1)(32)float32ValueError: Target size (torch.Size([32])) must be the same as input size (torch.Size([32, 1]))
BCEWithLogitsLoss(32, 1)(32, 1)longRuntimeError: result type Float can't be cast to the desired output type Long
MSELoss(32, 1)(32)float32Runs. Warns about broadcasting and returns a wrong number.
MSELoss(32, 10)(32)float32RuntimeError: The size of tensor a (10) must match the size of tensor b (32) at non-singleton dimension 1

Two of these are worth a second look. The batch size mismatch is a ValueError, not a RuntimeError, so an except RuntimeError block will not catch it. And the 4-dimensional size mismatch message in torch 2.8.0 is missing its closing parenthesis, which is a real quirk of the source string rather than a typo here.

The trap that raises nothing

The MSELoss row above is the dangerous one. An output of (32, 1) against a target of (32) does not raise. PyTorch broadcasts the pair to (32, 32), computes a mean over 1024 numbers instead of 32, and prints a warning that is easy to miss in a busy training log.

UserWarning: Using a target size (torch.Size([32])) that is different to the input size
(torch.Size([32, 1])). This will likely lead to incorrect results due to broadcasting.
Please ensure they have the same size.

Your loss curve still moves, so nothing looks broken. Set output = output.squeeze(1) or target = target.view(32, 1) and the number becomes correct.

Quick reference

LossTarget shape for input (N, C)Target dtype
nn.CrossEntropyLoss indices(N)torch.long
nn.CrossEntropyLoss probabilities(N, C)floating point
nn.NLLLoss(N)torch.long
nn.BCELosssame as input, exactlytorch.float32, input in [0, 1]
nn.BCEWithLogitsLosssame as input, exactlyfloating point, input is raw logits
nn.MSELosssame as input, or it broadcastsfloating point for .backward()

The documented shape contract for the first three lives in the PyTorch reference: torch.nn.CrossEntropyLoss and torch.nn.NLLLoss. The error strings are not documented anywhere, so treat those as observed behaviour on torch 2.8.0.

Try the Loss Target Shape Checker

Built by Michael Lip. Behaviour verified against torch 2.8.0 on 26 August 2026.

By the same builder: GitHub, theluckystrike BeLikeNative, Grammar AI EarlyThunder, Dev Blog Bug Bounty Reality Zovo, AI Dev Tools