TheAlgorithms/Python · error · ValueError
y_true must be one-hot encoded.
Error message
y_true must be one-hot encoded.
What it means
Raised by categorical_cross_entropy when y_true contains values other than 0/1 or any row does not sum to exactly 1 — i.e. it is not one-hot encoded. The loss -sum(y_true * log(y_pred)) only equals cross-entropy when y_true selects exactly one class per row, so soft or integer labels are rejected.
Source
Thrown at machine_learning/loss_functions.py:142
ValueError: y_true must be one-hot encoded.
>>> true_labels = np.array([[1, 0, 1], [1, 0, 0]])
>>> pred_probs = np.array([[0.9, 0.1, 0.0], [0.2, 0.7, 0.1]])
>>> categorical_cross_entropy(true_labels, pred_probs)
Traceback (most recent call last):
...
ValueError: y_true must be one-hot encoded.
>>> true_labels = np.array([[1, 0, 0], [0, 1, 0]])
>>> pred_probs = np.array([[0.9, 0.1, 0.1], [0.2, 0.7, 0.1]])
>>> categorical_cross_entropy(true_labels, pred_probs)
Traceback (most recent call last):
...
ValueError: Predicted probabilities must sum to approximately 1.
"""
if y_true.shape != y_pred.shape:
raise ValueError("Input arrays must have the same shape.")
if np.any((y_true != 0) & (y_true != 1)) or np.any(y_true.sum(axis=1) != 1):
raise ValueError("y_true must be one-hot encoded.")
if not np.all(np.isclose(np.sum(y_pred, axis=1), 1, rtol=epsilon, atol=epsilon)):
raise ValueError("Predicted probabilities must sum to approximately 1.")
y_pred = np.clip(y_pred, epsilon, 1) # Clip predictions to avoid log(0)
return -np.sum(y_true * np.log(y_pred))
def categorical_focal_cross_entropy(
y_true: np.ndarray,
y_pred: np.ndarray,
alpha: np.ndarray = None,
gamma: float = 2.0,
epsilon: float = 1e-15,
) -> float:
"""
Calculate the mean categorical focal cross-entropy (CFCE) loss between true
labels and predicted probabilities for multi-class classification.View on GitHub (pinned to f5988cc097)
Solutions
- One-hot encode labels: y_true = np.eye(n_classes)[class_indices].
- If rows should already be one-hot, find and fix the bad rows: bad = np.where(y_true.sum(axis=1) != 1).
- If you need soft-label support, use a different loss implementation; this one requires strict one-hot.
Example fix
# before labels = np.array([0, 2, 1]) categorical_cross_entropy(labels.reshape(-1, 1), y_pred) # after labels = np.array([0, 2, 1]) y_true = np.eye(y_pred.shape[1])[labels] categorical_cross_entropy(y_true, y_pred)
Defensive patterns
Strategy: validation
Validate before calling
y_true = np.asarray(y_true)
assert set(np.unique(y_true)) <= {0, 1} and (y_true.sum(axis=1) == 1).all(), "y_true not one-hot"
loss = categorical_cross_entropy(y_true, y_pred) Type guard
def is_one_hot(y_true: np.ndarray) -> bool:
return (
y_true.ndim == 2
and np.isin(y_true, [0, 1]).all()
and np.all(y_true.sum(axis=1) == 1)
) Try / catch
try:
categorical_cross_entropy(y_true, y_pred)
except ValueError as e:
if "one-hot" in str(e):
y_true = np.eye(y_pred.shape[1])[y_true.argmax(axis=1)] if y_true.ndim == 2 else np.eye(y_pred.shape[1])[y_true.ravel()]
return categorical_cross_entropy(y_true, y_pred)
raise Prevention
- Always run np.eye(k)[labels] before calling categorical losses.
- Validate one-hotness in unit tests for your data pipeline.
- Do not reuse softmax outputs as labels.
When it happens
Trigger: Passing raw integer class labels like np.array([[0], [2]]) or [[0, 1, 2], ...]), or soft label distributions whose rows do not sum to 1 (e.g. [0.5, 0.6]).
Common situations: Forgetting the one-hot step after label encoding, using softmax outputs as 'labels', or duplicated 1s in a row from a buggy encoder.
Related errors
- y_true can have values -1 or 1 only.
- Input arrays must have the same length.
- Input arrays must have the same shape.
- Predicted probabilities must sum to approximately 1.
- Shape of y_true and y_pred must be the same.
AI-assisted analysis of TheAlgorithms/Python@f5988cc097 (2026-08-14).
Data as JSON: /api/errors/16cdfb4df31c7074.
Report an issue: GitHub.