def ctc(y_true, y_pred):
    """CTC (Connectionist Temporal Classification) loss.

    Args:
        y_true: A tensor of shape `(batch_size, max_length)` containing
            the true labels in integer format. `0` always represents
            the blank/mask index and should not be used for classes.
        y_pred: A tensor of shape `(batch_size, max_length, num_classes)`
            containing logits (the output of your model).
            They should *not* be normalized via softmax.
    """
    if len(ops.shape(y_true)) != 2:
        raise ValueError(
            "Targets `y_true` are expected to be a tensor of shape "
            "`(batch_size, max_length)` in integer format. "
            f"Received: y_true.shape={ops.shape(y_true)}"
        )
    if len(ops.shape(y_pred)) != 3:
        raise ValueError(
            "Logits `y_pred` are expected to be a tensor of shape "
            "`(batch_size, max_length, num_classes)`. "
            f"Received: y_pred.shape={ops.shape(y_pred)}"
        )

    mask_index = 0
    batch_length = ops.shape(y_pred)[0]
    input_length = ops.shape(y_pred)[1]
    input_length = input_length * ops.ones((batch_length,), dtype="int32")
    label_length = ops.cast(
        ops.sum(y_true != mask_index, axis=-1), dtype="int32"
    )

    return ops.ctc_loss(
        y_true, y_pred, label_length, input_length, mask_index=mask_index
    )
CTC (Connectionist Temporal Classification) loss.

    Args:
        y_true: A tensor of shape `(batch_size, max_length)` containing
            the true labels in integer format. `0` always represents
            the blank/mask index and should not be used for classes.
        y_pred: A tensor of shape `(batch_size, max_length, num_classes)`
            containing logits (the output of your model).
            They should *not* be normalized via softmax.
    
keras/src/losses/losses.py