IndexError: Target N is out of bounds (CrossEntropyLoss)
A class label is outside the range your output layer allows — labels must run 0 to C-1. Usually labels start at 1, or the output layer has too few units.
Updated
The error
IndexError: Target 5 is out of bounds.
On GPU, the identical bug surfaces as the cryptic device-side assert instead — which is why re-running on CPU to get this readable message is a standard debugging move.
What it means
CrossEntropyLoss receives your model's outputs — one score per class — and a target class index per sample. With an output layer of size C, valid targets are 0 through C-1. A target of 5 arrived when the output layer has 5 units (indices 0-4) or fewer. The loss cannot look up a score for a class the model does not produce.
Why it happens
Two mismatches cover nearly every case:
- Labels start at 1. Datasets labelled 1..N are everywhere. With
num_classes=N, label N is out of bounds by one. - The output layer is too small. You counted classes wrongly, or a new class appeared in the data after the model was defined.
A third: sentinel values like -1 for "unlabelled" reaching the loss unfiltered. Negative targets raise the same family of errors.
How to fix it
1. Print the actual label range and the output size — the diff is the bug.
print(targets.min().item(), targets.max().item())
print(model.fc.out_features) # or your final layer's name1 5 5
Labels 1-5 with 5 outputs: off by one.
2. Shift 1-based labels down to 0-based.
targets = targets - 1Do it once, in the Dataset, so every consumer sees consistent labels.
3. Or size the output layer from the data, not from memory.
num_classes = int(targets.max().item()) + 1
model.fc = nn.Linear(model.fc.in_features, num_classes)Counting distinct labels with len(torch.unique(targets)) is a cross-check — if the two numbers differ, some class indices are unused or out of range.
4. Handle sentinel labels explicitly.
criterion = nn.CrossEntropyLoss(ignore_index=-1)Or filter those rows out before the loss.
5. Remember what CrossEntropyLoss wants. Raw logits of shape [N, C], and Long targets of shape [N] holding class indices — not one-hot vectors, and no softmax applied by you.
How to prevent it
Build a single label-mapping step into data loading: map raw labels to 0..C-1, store the mapping, and derive num_classes from it. Assert once per epoch during development: assert targets.max() < C and targets.min() >= 0. Cheap, and it turns a mid-training crash into an immediate clear failure.
Related errors
- CUDA error: device-side assert triggered — the same bug's GPU disguise
- expected scalar type Float but found Double — the other CrossEntropyLoss target complaint
- mat1 and mat2 shapes cannot be multiplied