Live grapheme-to-phoneme tool for isiZulu, isiXhosa & Afrikaans; a from-scratch PyTorch attention seq2seq, served via FastAPI, deployed on AWS.
# PhonemeZA — South African grapheme-to-phoneme
PhonemeZA predicts the pronunciation of isiZulu, isiXhosa, and Afrikaans words
from their spelling, using a sequence-to-sequence model whose LSTM cells and
attention are implemented from scratch in PyTorch (no `nn.LSTM`). Type a word
and it returns the phoneme sequence in X-SAMPA plus a heatmap of which input
letters the decoder attended to at each output step.
**▶ Live demo:
phonemeza.duckdns.org**
## Results
Test-set metrics (held-out 10% split; PER = phone error rate, the mean
edit distance between predicted and reference phoneme sequences normalised by
reference length):
| Language | Context | PER | Word accuracy |
|----------|---------|----:|--------------:|
| isiZulu | attention | 0.0031 | 98.7% |
| isiXhosa | attention | 0.0017 | 99.0% |
| Afrikaans | attention | 0.0284 | 82.4% |
| Afrikaans | bottleneck (no attention) | 0.0894 | 69.6% |
The Nguni languages (isiZulu, isiXhosa) score near-perfect, but that number
deserves caveats. Their orthographies are close to phonemic, the NCHLT
Southern-Bantu dictionaries are largely rule-derived, and the languages are
agglutinative — so stems and affixes recur across the train/test boundary even
though the word lists are disjoint. Afrikaans, whose pronunciations are less
predictable from spelling, is the truer test, and there the attention decoder
cuts PER roughly 3× and raises word accuracy from 69.6% to 82.4% over a
bottleneck decoder that must compress the whole word into one fixed vector.
That replicates the classic attention-vs-bottleneck finding from the original
CMUdict experiments on a new set of languages.
## Architecture
- **From-scratch recurrence.** `LSTMCell` and an attention-augmented
`LSTMCellWithContext` are written out gate-by-gate (`g2p/model.py`); the
encoder and decoder stack these manually rather than calling `nn.LSTM`.
- **Dot-product attention.** At each decoding step the decoder scores its
hidden state against every encoder state, …