Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
82 commits
Select commit Hold shift + click to select a range
fa7d6e0
parakeet tdt intergration
Oct 13, 2025
f2b4938
Add TDT decoder support for Parakeet ASR models
lmaksym Feb 20, 2026
fa36657
Add expected outputs for TDT, small fixes.
ebezzam Feb 25, 2026
05e2e34
Separate CTC and TDT generate outputs.
ebezzam Feb 25, 2026
bb5ff33
Work with auto device, better init,
ebezzam Feb 25, 2026
9ec79b0
Test timestamps and expose token duration.
ebezzam Feb 26, 2026
33f128e
Add reproducer link.
ebezzam Feb 26, 2026
760b4b6
fix: align TDT training and decoding with NeMo implementation
lmaksym Feb 27, 2026
b33002f
revert: restore lasr generated files to original state
lmaksym Feb 27, 2026
48b39dd
warn: torchaudio rnnt_loss does not train duration head
lmaksym Feb 27, 2026
e9f23ab
Relax timestamp test, and test nits.
ebezzam Mar 2, 2026
e2b97aa
feat: TDT training
lmaksym Mar 3, 2026
6b9fc73
chore: for cuda detection and run without patching
lmaksym Mar 3, 2026
6c879bc
Equivalent timestamp processing as Nemo, and various nits/cleanup.
ebezzam Mar 3, 2026
149e17f
Merge branch 'parakeet-tdt' of github.com:lmaksym/transformers into p…
ebezzam Mar 3, 2026
36bfa63
Simplify durations config.
ebezzam Mar 3, 2026
2df0ccc
Update training examples.
ebezzam Mar 3, 2026
388c6d3
chore: enable parralelism
lmaksym Mar 3, 2026
08b2b55
chore: performance optimization
lmaksym Mar 4, 2026
0c4e05a
fix: formatting
lmaksym Mar 4, 2026
1ddd804
Doc and testing nits
ebezzam Mar 5, 2026
f512670
Use active mask from current step, and nits.
ebezzam Mar 6, 2026
07d8e35
Better pre-allocate.
ebezzam Mar 6, 2026
fab050a
TDT has separate pad token and blank token.
ebezzam Mar 6, 2026
c438565
Merge branch 'main' into parakeet-tdt
ebezzam Mar 6, 2026
86d980c
Regenerate lasr.
ebezzam Mar 6, 2026
895c4a0
Merge branch 'parakeet-tdt' of github.com:lmaksym/transformers into p…
ebezzam Mar 6, 2026
ab21380
Style checks and nits
ebezzam Mar 7, 2026
d0141d5
Nits, put back ctc loss test
ebezzam Mar 7, 2026
f7529d4
More standard model output.
ebezzam Mar 10, 2026
77b95d7
Style
ebezzam Mar 10, 2026
94eae66
Remove compute_loss flag and allow monkey patching to tdt loss
ebezzam Mar 23, 2026
f7d4067
Update src/transformers/models/parakeet/modular_parakeet.py
ebezzam Mar 23, 2026
f75c17b
Address various comments.
ebezzam Mar 23, 2026
5a49b65
More compatible with Transformers forward/generate approach
ebezzam Mar 24, 2026
881233f
compile option for generation and decoder cache
ebezzam Mar 24, 2026
b41a8ee
Cleaner, better conventions.
ebezzam Mar 24, 2026
897753a
Merge branch 'main' into parakeet-tdt
ebezzam Mar 24, 2026
6c914db
Update with main.
ebezzam Mar 24, 2026
756cee1
doc nits
ebezzam Mar 26, 2026
f30c536
Imitate whisper for encoder outputs as input
ebezzam Mar 26, 2026
fa95fc8
Address tests and nits.
ebezzam Mar 26, 2026
5df7f28
Inherit from GenerateMixIn for get_compiled_call
ebezzam Mar 26, 2026
cd706d4
Comment nit
ebezzam Mar 26, 2026
a47ed8a
forward cleanup
eustlb Apr 15, 2026
13b68ce
generate cleanup + separate generation file
eustlb Apr 15, 2026
72c1ad0
generate: add _supported_generation_modes
eustlb Apr 15, 2026
8e23b3d
automatic init of the loss
eustlb Apr 15, 2026
1cc39fd
modular cleanups
eustlb Apr 15, 2026
531f297
use is_encoder_decoder
eustlb Apr 15, 2026
2c0f23a
timestamp processing fully from tokens + durations
eustlb Apr 15, 2026
cef6639
convertion script update
eustlb Apr 15, 2026
fd3cf9b
test update
eustlb Apr 15, 2026
e63a5bf
make
eustlb Apr 15, 2026
f9d1a4f
Merge branch 'main' into parakeet-tdt
eustlb Apr 15, 2026
43ee7cd
test update
eustlb Apr 15, 2026
c2a0f78
test update
eustlb Apr 15, 2026
1fd7ed7
ensure correct loss computation
eustlb Apr 16, 2026
7cc9d2e
kernel loss
eustlb Apr 16, 2026
e753eab
test loss integration
eustlb Apr 16, 2026
ed3fa4d
push to hub pr
eustlb Apr 16, 2026
ab66b23
integration tests to rely fully on transcripts
eustlb Apr 16, 2026
a5ba0c6
udpate fixtures
eustlb Apr 16, 2026
48279a6
we don't need to monkey patch with numba anymore!
eustlb Apr 16, 2026
1d7680d
fix pipeline usage
eustlb Apr 16, 2026
59ddced
nit
eustlb Apr 16, 2026
31490d1
fix usage
eustlb Apr 16, 2026
d8eb1b6
Pass through tests and examples: improve kernel fallback, update with…
ebezzam Apr 17, 2026
1f1b912
Update checkpoint
ebezzam Apr 17, 2026
9ab08d1
Merge branch 'main' into parakeet-tdt
ebezzam Apr 17, 2026
fd9f8b1
Add TDT to mapping after merge.
ebezzam Apr 17, 2026
136f676
Fix lasr generate test.
ebezzam Apr 20, 2026
833d289
Output attention mask if labels provided for computing loss.
ebezzam Apr 20, 2026
a1c62a1
Apply suggestion from @ArthurZucker
ebezzam May 13, 2026
8683570
Improve ParakeetTDTDecoderCache definition and usage.
ebezzam May 13, 2026
1d4b0f4
Remove tuple parsing.
ebezzam May 13, 2026
a418eca
processor refactor
ebezzam May 13, 2026
5d0c631
Merge branch 'parakeet-tdt' of github.com:lmaksym/transformers into p…
ebezzam May 13, 2026
5c603c1
Update conversion.
ebezzam May 18, 2026
09ba99c
Merge branch 'main' into tdt_loss_kernel
ebezzam May 19, 2026
e743b2d
Modular after merge.
ebezzam May 19, 2026
8d09cb6
Don't allow all kernels.
ebezzam May 19, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/transformers/integrations/hub_kernels.py
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,7 @@ def register_kernel_mapping_transformers(*args, **kwargs):
"finegrained-fp8": {"repo_id": "kernels-community/finegrained-fp8", "version": 1},
"deep-gemm": {"repo_id": "kernels-community/deep-gemm", "version": 1},
"sonic-moe": {"repo_id": "kernels-community/sonic-moe", "revision": "ep-support"},
"tdt-loss": {"repo_id": "eustlb/tdt-loss", "revision": "v1"},

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

}

_KERNEL_MODULE_MAPPING: dict[str, ModuleType | None] = {}
Expand Down
28 changes: 28 additions & 0 deletions src/transformers/loss/loss_tdt.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,17 @@
logger = logging.get_logger(__name__)


def _load_tdt_kernel():
"""Try to load the TDT loss CUDA kernel from the Hub. Returns None on failure."""
from ..integrations.hub_kernels import lazy_load_kernel

kernel = lazy_load_kernel("tdt-loss")
if kernel is None or not hasattr(kernel, "tdt_loss"):
logger.warning_once("Falling back to pure PyTorch implementation.")
return None
return kernel


def tdt_loss(
token_logits: torch.Tensor,
duration_logits: torch.Tensor,
Expand All @@ -38,6 +49,9 @@ def tdt_loss(
the token prediction head and the duration prediction head. It uses vectorized anti-diagonal processing for
efficiency: all (t, u) pairs on each anti-diagonal t+u=n are computed in parallel as batched tensor operations.

When the ``kernels-community/tdt-loss`` CUDA kernel is installed, it is used automatically for GPU tensors,
Falls back to the pure PyTorch implementation otherwise.

Args:
token_logits: Token logits of shape `(batch, T, U+1, vocab_size+1)`.
duration_logits: Duration logits of shape `(batch, T, U+1, num_durations)`.
Expand All @@ -53,6 +67,20 @@ def tdt_loss(
Scalar loss tensor (or per-example losses if `reduction="none"`).

"""
kernel = _load_tdt_kernel() if token_logits.is_cuda else None
if kernel is not None and hasattr(kernel, "tdt_loss"):
durations_t = torch.tensor(durations, dtype=torch.int32, device=token_logits.device)
return kernel.tdt_loss(
token_logits,
duration_logits,
targets,
logit_lengths,
target_lengths,
durations_t,
blank_token_id,
sigma,
reduction,
)

if reduction not in ("mean", "sum", "none"):
raise ValueError(f'Invalid reduction mode "{reduction}". Expected one of "mean", "sum", or "none".')
Expand Down
54 changes: 36 additions & 18 deletions tests/models/parakeet/test_modeling_parakeet.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@
import json
import tempfile
import unittest
from contextlib import nullcontext
from pathlib import Path
from unittest.mock import patch

from transformers import is_datasets_available, is_torch_available
from transformers.testing_utils import cleanup, require_torch, slow, torch_device
Expand Down Expand Up @@ -731,9 +733,12 @@ def test_tdt_model_integration_timestamps(self):
@slow
def test_tdt_model_integration_loss(self):
"""
Verify that ParakeetForTDT loss matches NeMo's TDT loss (sigma=0).
Verify that ParakeetForTDT loss matches NeMo's TDT loss (sigma=0) for both
the CUDA kernel and the pure PyTorch implementation.
reproducer: https://gist.github.com/883ea42bf7d8ce2af42f3055627476a7
Comment on lines +736 to 738

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we also test for sigma != 0?

"""
from transformers.loss.loss_tdt import _load_tdt_kernel

RESULTS_PATH = Path(__file__).parent.parent.parent / "fixtures/parakeet/expected_loss_tdt.json"
with open(RESULTS_PATH, "r") as f:
raw_data = json.load(f)
Expand All @@ -754,20 +759,33 @@ def test_tdt_model_integration_loss(self):
)
inputs.to(model.device)

# Forward in eval mode — check loss matches NeMo
model.eval()
with torch.no_grad():
outputs = model(**inputs)
self.assertIsNotNone(outputs.loss, "Loss must be computed when labels are provided")
self.assertEqual(outputs.logits.dim(), 4, "Training logits must be 4D (B, T, U+1, V+D)")
torch.testing.assert_close(outputs.loss.cpu(), EXPECTED_MEAN_LOSS, rtol=1e-3, atol=1e-3)

# Backward — verify gradients flow
del outputs
torch.cuda.empty_cache()
model.train()
model.zero_grad()
outputs = model(**inputs)
outputs.loss.backward()
n_with_grad = sum(1 for p in model.parameters() if p.grad is not None)
self.assertGreater(n_with_grad, 0, "No gradients after backward")
# Test both backends: kernel (if available) and pure PyTorch
has_kernel = _load_tdt_kernel() is not None
backends = [
("kernel", None),
("torch", patch("transformers.loss.loss_tdt._load_tdt_kernel", return_value=None)),
]
if not has_kernel:
backends = backends[1:] # skip kernel test when not installed

for backend_name, ctx in backends:
with self.subTest(backend=backend_name):
ctx_manager = ctx if ctx is not None else nullcontext()
with ctx_manager:
# Forward in eval mode — check loss matches NeMo
model.eval()
with torch.no_grad():
outputs = model(**inputs)
self.assertIsNotNone(outputs.loss, "Loss must be computed when labels are provided")
self.assertEqual(outputs.logits.dim(), 4, "Training logits must be 4D (B, T, U+1, V+D)")
torch.testing.assert_close(outputs.loss.cpu(), EXPECTED_MEAN_LOSS, rtol=1e-3, atol=1e-3)

# Backward — verify gradients flow
del outputs
torch.cuda.empty_cache()
model.train()
model.zero_grad()
outputs = model(**inputs)
outputs.loss.backward()
n_with_grad = sum(1 for p in model.parameters() if p.grad is not None)
self.assertGreater(n_with_grad, 0, "No gradients after backward")
Loading