Update model card: new architecture, remove diffusion
Browse files
README.md
CHANGED
|
@@ -14,7 +14,18 @@ datasets:
|
|
| 14 |
---
|
| 15 |
|
| 16 |
<div align="center">
|
| 17 |
-
<img
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 18 |
</div>
|
| 19 |
|
| 20 |
<hr>
|
|
@@ -33,17 +44,17 @@ datasets:
|
|
| 33 |
</h2>
|
| 34 |
|
| 35 |
<p align="center">
|
| 36 |
-
<img src="assets/
|
| 37 |
</p>
|
| 38 |
|
| 39 |
<p align="center">
|
| 40 |
-
<a href="">Inference Speed Benchmark on CPU
|
| 41 |
</p>
|
| 42 |
|
| 43 |
## 1. Abstract
|
| 44 |
-
This repository
|
| 45 |
|
| 46 |
-
|
| 47 |
|
| 48 |
## 2. Dataset
|
| 49 |
|
|
@@ -66,45 +77,53 @@ Raw data was cleaned through the following pipeline:
|
|
| 66 |
1. **Deduplication**: exact duplicate pairs removed across all sources.
|
| 67 |
2. **Length filtering**: pairs with extreme source/target length mismatches were discarded.
|
| 68 |
3. **Empty/null removal**: pairs where either side was empty or below a minimum token count were dropped.
|
|
|
|
|
|
|
| 69 |
|
| 70 |
After cleaning, each surviving pair is duplicated in both directions (`ENβKM` and `KMβEN`) with a direction prefix token (`<2km>` / `<2en>`), yielding ~4.2 million training examples.
|
| 71 |
|
| 72 |
## 3. Model Architecture
|
| 73 |
|
| 74 |
<div align="center">
|
| 75 |
-
<img src="assets/model_architecture.png" width="70%" alt="Netra-NMT Architecture" />
|
| 76 |
<p><em>Figure 1: Overview of the Netra-NMT encoder-decoder architecture. The encoder (left) processes the source sentence with bidirectional self-attention; the decoder (right) generates the target sentence autoregressively via causal self-attention and cross-attention over the encoder output. Both sides share a 32K SentencePiece tokenizer.</em></p>
|
| 77 |
</div>
|
| 78 |
|
| 79 |
-
Netra-NMT follows
|
| 80 |
|
| 81 |
-
**Encoder**
|
| 82 |
|
| 83 |
-
**Decoder** takes the (partially generated) target sentence through the same tokenizer
|
| 84 |
|
| 85 |
**Architectural improvements over the vanilla transformer:**
|
| 86 |
|
| 87 |
| Feature | Detail |
|
| 88 |
|---------|--------|
|
| 89 |
-
|
|
| 90 |
-
|
|
| 91 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 92 |
|
| 93 |
**Hyperparameters:**
|
| 94 |
|
| 95 |
| | |
|
| 96 |
|---|---|
|
| 97 |
| d_model | 512 |
|
| 98 |
-
| Encoder / Decoder layers |
|
| 99 |
| Attention heads | 8 |
|
| 100 |
| FFN hidden size | 2048 |
|
| 101 |
-
|
|
| 102 |
-
|
|
|
|
|
|
|
|
| 103 |
|
| 104 |
## 4. Evaluation Results
|
| 105 |
|
| 106 |
<p align="center">
|
| 107 |
-
<img src="assets/metrics_benchmark.png" style="width: 1000px" align=center>
|
| 108 |
</p>
|
| 109 |
|
| 110 |
## Install
|
|
@@ -133,7 +152,7 @@ under `~/.cache/huggingface`.
|
|
| 133 |
from netra_nmt import NetraTranslator
|
| 134 |
|
| 135 |
t = NetraTranslator() # auto-detect GPU/CPU; downloads weights once
|
| 136 |
-
t.translate("Hello, how are you?", direction="en2km") # β "αα½ααααΈ
|
| 137 |
t.translate("αααα»ααααα‘αΆαααααααααααααααα»αα", direction="km2en")
|
| 138 |
|
| 139 |
# Batch + decoding options
|
|
@@ -175,7 +194,7 @@ netra-web --port 8080 --device cpu
|
|
| 175 |
netra-web --local-dir export # load weights from a local export dir
|
| 176 |
```
|
| 177 |
|
| 178 |
-
A two-pane translation site (source left, output right, ENβKM swap button)
|
| 179 |
|
| 180 |
```bash
|
| 181 |
curl -X POST http://127.0.0.1:8000/api/translate \
|
|
|
|
| 14 |
---
|
| 15 |
|
| 16 |
<div align="center">
|
| 17 |
+
<img
|
| 18 |
+
src="https://raw.githubusercontent.com/netra-ai-lab/Netra-NMT/main/assets/logo.png"
|
| 19 |
+
width="20%"
|
| 20 |
+
alt="Netra Lab"
|
| 21 |
+
style="vertical-align: middle; margin-right: 30px;"
|
| 22 |
+
/>
|
| 23 |
+
<img
|
| 24 |
+
src="https://raw.githubusercontent.com/netra-ai-lab/Netra-NMT/main/assets/wordmark.png"
|
| 25 |
+
width="20%"
|
| 26 |
+
alt="Netra Lab"
|
| 27 |
+
style="vertical-align: middle;"
|
| 28 |
+
/>
|
| 29 |
</div>
|
| 30 |
|
| 31 |
<hr>
|
|
|
|
| 44 |
</h2>
|
| 45 |
|
| 46 |
<p align="center">
|
| 47 |
+
<img src="https://raw.githubusercontent.com/netra-ai-lab/Netra-NMT/main/assets/speed_benchmark.png" style="width: 1000px" align=center>
|
| 48 |
</p>
|
| 49 |
|
| 50 |
<p align="center">
|
| 51 |
+
<a href="">Inference Speed Benchmark on CPU (Intel i7-13700KF) and GPU (RTX 3060) using Greedy and Beam-5 decoding</a>
|
| 52 |
</p>
|
| 53 |
|
| 54 |
## 1. Abstract
|
| 55 |
+
This repository presents Netra-NMT, a compact **77M-parameter** encoder-decoder transformer-based model trained from scratch on **220 million tokens** of English-Khmer parallel text (4.2M bidirectional examples). The encoder uses bidirectional self-attention, much like BERT, to capture global contextual representation. The decoder performs autoregressive generation through causal self-attention and encoder-decoder cross-attention.
|
| 56 |
|
| 57 |
+
Netra-NMT adopts a modern transformer recipe: **rotary position embeddings (RoPE)** in self-attention (no learned position table), **RMSNorm** with Pre-Normalization for stable optimization, **SwiGLU** feed-forward networks, and a **single embedding table shared** across the encoder input, decoder input, and tied output projection. It uses a **deep-encoder / shallow-decoder** layout (12 encoder layers, 2 decoder layers) which β combined with a **KV cache** for O(T) incremental decoding β delivers autoregressive quality at a fraction of the decoding latency (Kasai et al., 2021). Khmer text is word-segmented with **khmercut** before tokenization, so the shared 32K SentencePiece vocabulary sees real word boundaries.
|
| 58 |
|
| 59 |
## 2. Dataset
|
| 60 |
|
|
|
|
| 77 |
1. **Deduplication**: exact duplicate pairs removed across all sources.
|
| 78 |
2. **Length filtering**: pairs with extreme source/target length mismatches were discarded.
|
| 79 |
3. **Empty/null removal**: pairs where either side was empty or below a minimum token count were dropped.
|
| 80 |
+
4. **English source case-normalization**: English is NFC-normalized, whitespace-collapsed, and lowercased **only when it is the `en2km` source**, so `"I love Cambodia"` and `"i love cambodia"` map to identical model inputs. English kept as a `km2en` *target* retains its natural casing.
|
| 81 |
+
5. **Khmer word segmentation**: Khmer (which is written without spaces) is segmented with **khmercut** wherever it appears β as the `en2km` target and the `km2en` source β matching the segmented tokenizer. Khmer output is de-segmented back to natural text at inference time.
|
| 82 |
|
| 83 |
After cleaning, each surviving pair is duplicated in both directions (`ENβKM` and `KMβEN`) with a direction prefix token (`<2km>` / `<2en>`), yielding ~4.2 million training examples.
|
| 84 |
|
| 85 |
## 3. Model Architecture
|
| 86 |
|
| 87 |
<div align="center">
|
| 88 |
+
<img src="https://raw.githubusercontent.com/netra-ai-lab/Netra-NMT/main/assets/model_architecture.png" width="70%" alt="Netra-NMT Architecture" />
|
| 89 |
<p><em>Figure 1: Overview of the Netra-NMT encoder-decoder architecture. The encoder (left) processes the source sentence with bidirectional self-attention; the decoder (right) generates the target sentence autoregressively via causal self-attention and cross-attention over the encoder output. Both sides share a 32K SentencePiece tokenizer.</em></p>
|
| 90 |
</div>
|
| 91 |
|
| 92 |
+
Netra-NMT follows an encoder-decoder transformer architecture modernized for training stability, parameter efficiency, and low-latency decoding.
|
| 93 |
|
| 94 |
+
**Encoder** takes the source sentence tokenized by the shared 32K SentencePiece tokenizer (Khmer is word-segmented with khmercut beforehand), and passes the sequence through **12** transformer layers with *bidirectional* self-attention (every token attends to every other token, similar to BERT). Positions are encoded with **rotary embeddings (RoPE)** applied to the queries and keys inside self-attention β there is no learned position table. A final RMSNorm is applied to the encoder output before it is passed to the decoder via cross-attention.
|
| 95 |
|
| 96 |
+
**Decoder** takes the (partially generated) target sentence through the same tokenizer and passes it through only **2** transformer layers. Each decoder layer applies three sub-layers in order: (1) *causal* (masked) self-attention with RoPE over previously generated tokens, backed by a **KV cache** for O(T) incremental decoding, (2) cross-attention over the full encoder output, and (3) a SwiGLU feed-forward block. A final RMSNorm feeds into the tied projection head. The **deep-encoder / shallow-decoder** split (12 vs 2) follows Kasai et al. (2021): most of the modeling capacity lives in the parallelizable encoder, while the thin decoder β the part that runs sequentially at inference β keeps per-step cost low without sacrificing quality.
|
| 97 |
|
| 98 |
**Architectural improvements over the vanilla transformer:**
|
| 99 |
|
| 100 |
| Feature | Detail |
|
| 101 |
|---------|--------|
|
| 102 |
+
| Rotary Position Embeddings (RoPE) | Positions encoded by rotating Q/K inside self-attention β no learned position table, and generalizes past the training length |
|
| 103 |
+
| RMSNorm (Pre-Norm) | Root-mean-square normalization applied *before* each sub-layer; as stable as LayerNorm and cheaper |
|
| 104 |
+
| SwiGLU FFN | Feed-forward blocks use the SwiGLU activation instead of ReLU, providing richer representational capacity |
|
| 105 |
+
| Shared embeddings | One embedding table is shared across the encoder input, decoder input, and the tied output projection head |
|
| 106 |
+
| Deep encoder / shallow decoder | 12-layer encoder + 2-layer decoder (Kasai et al., 2021) β retains quality while sharply cutting sequential decoding cost |
|
| 107 |
+
| KV cache | Incremental decoding caches past keys/values, making generation O(T) instead of O(TΒ²) |
|
| 108 |
+
| Khmer word segmentation | Khmer is segmented with khmercut before SentencePiece so the tokenizer learns real word boundaries |
|
| 109 |
|
| 110 |
**Hyperparameters:**
|
| 111 |
|
| 112 |
| | |
|
| 113 |
|---|---|
|
| 114 |
| d_model | 512 |
|
| 115 |
+
| Encoder / Decoder layers | 12 / 2 |
|
| 116 |
| Attention heads | 8 |
|
| 117 |
| FFN hidden size | 2048 |
|
| 118 |
+
| Position encoding | Rotary (RoPE) |
|
| 119 |
+
| Normalization | RMSNorm (Pre-Norm) |
|
| 120 |
+
| Vocabulary | 32K (SentencePiece unigram, shared, Khmer-segmented) |
|
| 121 |
+
| Total parameters | ~77M |
|
| 122 |
|
| 123 |
## 4. Evaluation Results
|
| 124 |
|
| 125 |
<p align="center">
|
| 126 |
+
<img src="https://raw.githubusercontent.com/netra-ai-lab/Netra-NMT/main/assets/metrics_benchmark.png" style="width: 1000px" align=center>
|
| 127 |
</p>
|
| 128 |
|
| 129 |
## Install
|
|
|
|
| 152 |
from netra_nmt import NetraTranslator
|
| 153 |
|
| 154 |
t = NetraTranslator() # auto-detect GPU/CPU; downloads weights once
|
| 155 |
+
t.translate("Hello, how are you?", direction="en2km") # β "αα½ααααΈαα»ααααααΆαα’αα?"
|
| 156 |
t.translate("αααα»ααααα‘αΆαααααααααααααααα»αα", direction="km2en")
|
| 157 |
|
| 158 |
# Batch + decoding options
|
|
|
|
| 194 |
netra-web --local-dir export # load weights from a local export dir
|
| 195 |
```
|
| 196 |
|
| 197 |
+
A two-pane translation site (source left, output right, ENβKM swap button) and a JSON API:
|
| 198 |
|
| 199 |
```bash
|
| 200 |
curl -X POST http://127.0.0.1:8000/api/translate \
|