duplex-simmt-en-de: Full-Duplex (Clocked) Streaming English-to-German Translation LM
A 111.9M-parameter decoder-only transformer that translates English to German in real time on a shared 10 Hz clock (100 ms ticks) — the way you drive rather than the way you play chess.
Instead of waiting for sentence or turn boundaries, at every 100 ms tick the model receives:
s_t: 0 toK=4source subword pieces that arrived during that tick (NOP-padded),y_{t-1}: its own previous output token (closed-loop feedback),
and emits y_t: either one German subword piece or NOP (wait / silence). There is no separate READ action, no EOS token, and no external turn detector.
- GitHub Repository: sumit-1/duplex-simmt-en-de
tick in: s_t (0..K tokens) in: y_t-1 out: y_t
0 The NOP NOP
1 NOP NOP NOP
2 house NOP NOP
3 is NOP Das
4 NOP Das Haus
5 big Haus ist
6 NOP ist NOP
7 NOP NOP groß
Quick Start
Install the package from the GitHub repository and run live translation directly from your keyboard (automatically downloads best.pt and the SentencePiece tokenizer from this Hugging Face repo):
git clone https://github.com/sumit-1/duplex-simmt-en-de.git
cd duplex-simmt-en-de
pip install -e .
# Interactive split-screen terminal demo (type English in top pane, German streams in bottom pane)
python -m duplex.live --ckpt sumitk/duplex-simmt-en-de --nop-bias 0.0
# Non-interactive simulated typing trace
python -m duplex.live --ckpt sumitk/duplex-simmt-en-de --nop-bias 0.0 --demo "Hello, how are you doing today? I paid 1234 euros." --wpm 120
Model Details
- Architecture: Decoder-only Transformer (
d_model=768,n_layers=12,n_heads=12,d_ff=2048, SwiGLU, RMSNorm, RoPE over absolute tick indices, causal sliding-window attention ofwindow=300ticks = 30 seconds). - Parameters: 111.9M (~448 MB checkpoint / ~225 MB in fp16/bf16).
- Vocabulary: 16,000 joint En/De SentencePiece BPE pieces (
split_digits=True) + 1 sharedNOPtoken (id=16000). - Training Data:
1.29M OpenSubtitles v2018 En-De pairs (2,500 movies with real subtitle timestamps) mixed with MuST-C En-De (223k TED talk segments), aligned via GPU IBM Model 1 with diagonal prior and scheduled withpolicy=align, lag=3. - Training Budget: 20,000 steps at batch size 16 x 600 ticks in bf16.
Evaluation Results
Streaming evaluation over whole talks/movies using the ring-buffer KV cache (duplex.eval):
| Benchmark | nop_bias |
sacreBLEU | chrF | AL (words) | LAAL (words) | Length ratio |
|---|---|---|---|---|---|---|
| OpenSubtitles test (24 unseen movies) | -0.75 |
25.15 | 59.93 | 1.55 | 2.47 | 1.085 |
| OpenSubtitles test (24 unseen movies) | 0.00 |
26.69 | 59.92 | 2.11 | 2.85 | 1.034 |
| MuST-C (TED) test | -0.75 |
24.57 | 67.59 | 2.16 | 3.38 | 1.075 |
| MuST-C (TED) test | 0.00 |
25.63 | 66.00 | 4.65 | 5.45 | 1.007 |
--nop-bias shifts the NOP logit at inference time to trade latency against quality without retraining (negative speaks sooner, positive waits longer).
Files in this Repo
best.pt: Trained PyTorch checkpoint (model weights + embedded config, step 20,000).tok/spm16000.model&tok/spm16000.vocab: Joint En-De SentencePiece BPE tokenizer (split_digits=True).opensubs.yaml: Training configuration.eval_test.json&eval_test_mustc.json: Full evaluation outputs on OpenSubtitles and MuST-C test sets.