TheAlgorithms/Python · error · ValueError

Sentence length of y_true and y_pred must be equal.

Error message

Sentence length of y_true and y_pred must be equal.

What it means

Thrown by perplexity_loss when the sentence-length dimension (shape[1]) of y_true and y_pred differ. Each row of y_true must have one token id per timestep that y_pred scores over the vocabulary, so the sequence lengths must match exactly.

Source

Thrown at machine_learning/loss_functions.py:558

    >>> y_true = np.array([[1, 4]])
    >>> y_pred = np.array(
    ...    [[[0.28, 0.19, 0.21 , 0.15, 0.15],
    ...      [0.24, 0.19, 0.09, 0.18, 0.27]],
    ...      [[0.03, 0.26, 0.21, 0.18, 0.30],
    ...       [0.28, 0.10, 0.33, 0.15, 0.12]]]
    ... )
    >>> perplexity_loss(y_true, y_pred)
    Traceback (most recent call last):
    ...
    ValueError: Batch size of y_true and y_pred must be equal.
    """

    vocab_size = y_pred.shape[2]

    if y_true.shape[0] != y_pred.shape[0]:
        raise ValueError("Batch size of y_true and y_pred must be equal.")
    if y_true.shape[1] != y_pred.shape[1]:
        raise ValueError("Sentence length of y_true and y_pred must be equal.")
    if np.max(y_true) > vocab_size:
        raise ValueError("Label value must not be greater than vocabulary size.")

    # Matrix to select prediction value only for true class
    filter_matrix = np.array(
        [[list(np.eye(vocab_size)[word]) for word in sentence] for sentence in y_true]
    )

    # Getting the matrix containing prediction for only true class
    true_class_pred = np.sum(y_pred * filter_matrix, axis=2).clip(epsilon, 1)

    # Calculating perplexity for each sentence
    perp_losses = np.exp(np.negative(np.mean(np.log(true_class_pred), axis=1)))

    return np.mean(perp_losses)


def smooth_l1_loss(y_true: np.ndarray, y_pred: np.ndarray, beta: float = 1.0) -> float:

View on GitHub (pinned to f5988cc097)

Solutions

  1. Pad or truncate y_true to the same length as y_pred's timestep axis (or regenerate both with one shared max_length).
  2. Check the tokenizer/padding config: the same seq_len must be used for references and model outputs.
  3. Trim to the shorter length if the extra steps are padding: y_pred = y_pred[:, :y_true.shape[1], :].

Example fix

# before
loss = perplexity_loss(y_true, y_pred)  # y_true len 4, y_pred timesteps 5

# after
y_pred = y_pred[:, : y_true.shape[1], :]
loss = perplexity_loss(y_true, y_pred)
Defensive patterns

Strategy: validation

Validate before calling

if y_true.shape[1] != y_pred.shape[1]:
    y_pred = y_pred[:, : y_true.shape[1], :]
loss = perplexity_loss(y_true, y_pred)

Type guard

def perplexity_shapes_ok(y_true: np.ndarray, y_pred: np.ndarray) -> bool:
    return (
        y_pred.ndim == 3
        and y_true.ndim == 2
        and y_true.shape == y_pred.shape[:2]
    )

Prevention

When it happens

Trigger: Calling perplexity_loss where y_true.shape[1] != y_pred.shape[1], e.g. 4 reference tokens against 5 prediction timesteps (often after truncation/padding applied to one side only).

Common situations: Padding reference sequences to a different max_length than the model input; truncation strategies (keep-first vs keep-last) applied inconsistently; BOS/EOS token added to one array but not the other.

Related errors


AI-assisted analysis of TheAlgorithms/Python@f5988cc097 (2026-08-14). Data as JSON: /api/errors/5bd0a70c3c217a9b. Report an issue: GitHub.