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.
- Class indices. The target shape differs from the input shape. For input (N, C) the target is (N), dtype
torch.long, values in [0, C). - Class probabilities. The target shape equals the input shape. The target must be floating point, and each value should be in [0, 1]. This is the mode for soft labels and label smoothing.
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.
| Loss | Output | Target | dtype | Result |
|---|---|---|---|---|
| CrossEntropyLoss | (32, 10) | (32) | long | Valid |
| CrossEntropyLoss | (32, 10) | (32, 1) | long | RuntimeError: 0D or 1D target tensor expected, multi-target not supported |
| CrossEntropyLoss | (32, 10) | (32, 10) | long | RuntimeError: Expected floating point type for target with class probabilities, got Long |
| CrossEntropyLoss | (32, 10) | (32, 10) | float32 | Valid, class probability mode |
| CrossEntropyLoss | (32, 10) | (32) | float32 | RuntimeError: expected scalar type Long but found Float |
| CrossEntropyLoss | (32, 10) | (16) | long | ValueError: Expected input batch_size (32) to match target batch_size (16). |
| CrossEntropyLoss | (10) | () | long | Valid, unbatched |
| CrossEntropyLoss | (10) | (1) | long | RuntimeError: size mismatch (got input: [10], target: [1]) |
| CrossEntropyLoss | (4, 3, 8, 8) | (4, 8, 8) | long | Valid, K-dimensional |
| CrossEntropyLoss | (4, 3, 8, 8) | (4, 8, 8, 1) | long | RuntimeError: only batches of spatial targets supported (3D tensors) but got targets of dimension: 4 |
| CrossEntropyLoss | (2, 3, 4) | (2, 4, 1) | long | RuntimeError: Expected target size [2, 4], got [2, 4, 1] |
| NLLLoss | (32, 10) | (32, 10) | float32 | RuntimeError: 0D or 1D target tensor expected, multi-target not supported |
| BCELoss | (32, 1) | (32) | float32 | ValueError: 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) | float32 | ValueError: Target size (torch.Size([32])) must be the same as input size (torch.Size([32, 1])) |
| BCEWithLogitsLoss | (32, 1) | (32, 1) | long | RuntimeError: result type Float can't be cast to the desired output type Long |
| MSELoss | (32, 1) | (32) | float32 | Runs. Warns about broadcasting and returns a wrong number. |
| MSELoss | (32, 10) | (32) | float32 | RuntimeError: 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
| Loss | Target 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.BCELoss | same as input, exactly | torch.float32, input in [0, 1] |
nn.BCEWithLogitsLoss | same as input, exactly | floating point, input is raw logits |
nn.MSELoss | same as input, or it broadcasts | floating 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.
Built by Michael Lip. Behaviour verified against torch 2.8.0 on 26 August 2026.