TorchEmbed is now integrated into DeepSpeed and ships as a dependency. The fused Triton RoPE kernel replaces the rotary embedding path in DeepSpeed’s transformer engine, delivering 4–7× speedup over pure PyTorch with no code changes required from users.

Why RoPE is a bottleneck

Rotary Position Embedding (RoPE) is now the dominant positional encoding scheme across modern LLMs — Llama, Mistral, Qwen, and most production models use it. At scale, the naive PyTorch implementation becomes a memory-bandwidth bottleneck: it materializes intermediate tensors from chunk and cat operations on every forward pass. For a sequence of length 4096, that means allocating and reading back several hundred MB of intermediate state per layer.

torch.compile helps but doesn’t fully eliminate the problem. Even with fusion, compiled code still allocates intermediate tensors that persist across the operation. The fused Triton kernel in TorchEmbed sidesteps this entirely — it reads and writes each element exactly once.

The integration

DeepSpeed’s transformer engine automatically uses TorchEmbed’s fused kernel when Triton is available. Installing TorchEmbed with the Triton extra is all that’s needed:

pip install torchembed[triton]

DeepSpeed picks up the kernel at import time. No config changes, no monkey-patching. If Triton is unavailable (e.g. CPU-only environments), TorchEmbed falls back to the standard PyTorch path transparently.

Using TorchEmbed directly

If you want to use the fused kernel outside of DeepSpeed, the API is minimal:

from torchembed.positional import RotaryEmbedding

rope = RotaryEmbedding(dim=64, use_fused=True).to("cuda")
q, k = rope(q.cuda(), k.cuda())

Setting use_fused=True routes through the Triton kernel. The interface is otherwise identical to a standard PyTorch module — it drops into any attention implementation without modifications.

Benchmark results

Measured on NVIDIA GB10 hardware at float16 across representative tensor shapes:

Shape (B, H, S, D, dim)PyTorchtorch.compileTorchEmbed (Triton)Speedup
(1, 32, 2048, 128, 128)1.364 ms0.620 ms0.305 ms4.47×
(1, 32, 4096, 128, 128)2.946 ms1.284 ms0.579 ms5.09×
(1, 32, 8192, 128, 128)5.909 ms2.476 ms1.224 ms4.83×
(2, 32, 2048, 128, 128)2.949 ms1.293 ms0.630 ms4.68×
(1, 32, 2048, 256, 128)2.869 ms1.323 ms0.646 ms4.44×

Peak speedup is 5.09× at sequence length 4096 — the sweet spot for most production inference workloads. Speedups hold across batch sizes and head dimensions.

Other embedding types

TorchEmbed is not limited to RoPE. The library also covers patch embeddings for Vision Transformers and cyclic temporal encodings for time-series models:

# Patch embeddings for ViT
from torchembed.patch import PatchEmbedding

patch_emb = PatchEmbedding(image_size=224, patch_size=16, embed_dim=768)
tokens = patch_emb(images)  # (B, 3, 224, 224) → (B, 196, 768)

# Cyclic temporal encoding
from torchembed.temporal import CyclicEmbedding

hour_enc = CyclicEmbedding(period=24)
features = hour_enc(hour_tensor)

Get started

TorchEmbed requires Python ≥ 3.9 and PyTorch ≥ 2.0. No other dependencies beyond PyTorch itself.

pip install torchembed        # CPU / fallback path
pip install torchembed[triton] # with fused Triton kernels

Source and benchmarking scripts are on GitHub.


Leave a Reply

Your email address will not be published. Required fields are marked *