Gender classifier for first names
A small fully connected neural network written from scratch in Rust, without external ML libraries.
name-gender-nn-rs — Rust port of name-gender-nn-py. Same algorithm, same datasets, ~40× faster training.
Determines whether a first name is male or female. Ships with two datasets:
data/names_ru.json) — Cyrillic alphabet, 108 namesdata/names_en.json) — Latin alphabet, 100 namesEach dataset defines its own alphabet. You train a separate model per dataset, and each model works only with names from its own alphabet.
⚠️ Educational project
Not production-ready. Shows how a small neural network works from scratch, without external ML libraries.
Scope: models are trained on full name forms (александр, екатерина, alexander, elizabeth). Diminutive and hypocoristic forms (коля, соня, катя in Russian; kate, bob, liz in English) are not in the datasets and are outside the intended use case.
Determines whether a first name is male or female. Ships with two datasets:
data/names_ru.json) — Cyrillic alphabet, 108 namesdata/names_en.json) — Latin alphabet, 100 namesEach dataset defines its own alphabet. You train a separate model per dataset, and each model works only with names from its own alphabet.
Same as the Python reference:
_ pad character. The Russian dataset uses the 33-letter Cyrillic alphabet; the English dataset uses the 26-letter Latin alphabet.lr = 0.1, 8000 epochs.git clone https://github.com/smartlegionlab/name-gender-nn-rs.git cd name-gender-nn-rs cargo build --release
Binary: target/release/name-gender-nn-rs.
Requirements: Rust 1.85+ (2024 edition), Cargo.
All commands are subcommands of a single binary.
Validate a dataset
cargo run --release -- check --data data/names_ru.json cargo run --release -- check --data data/names_en.json
Output for the Russian dataset:
File: data/names_ru.json Alphabet size: 34 Loaded 49 female and 59 male names Alphabet check: OK Duplicate check: OK Cross-gender check: OK All checks passed.
Checks: all names use only characters from the dataset alphabet; no duplicates inside each list; no name appears in both female and male.
Train
cargo run --release -- train --data data/names_ru.json --out weights_ru.json cargo run --release -- train --data data/names_en.json --out weights_en.json
Output for the Russian dataset:
Loaded 108 names from data/names_ru.json Alphabet size: 34 epoch 0 error=13.671195 t=0.0s epoch 500 error=0.019290 t=0.1s ... epoch 7500 error=0.000797 t=0.9s Train accuracy: 108/108 = 100.0% Weights saved to weights_ru.json Total time: 1.0s
Predict
cargo run --release -- predict --weights weights_ru.json александр cargo run --release -- predict --weights weights_en.json alexander
One-liner output:
александр -> male (confidence 99.7%) alexander -> male (confidence 99.8%)
Interactive mode (no name argument):
cargo run --release -- predict --weights weights_ru.json Enter a name (or 'exit' to quit): > анна анна -> female (confidence 99.8%) > exit
Measured on the same machine as the Python reference implementation.
| Task | Python | Rust (release) |
|---|---|---|
| Train Russian model | ~41 s | ~1.0 s |
| Train English model | ~38 s | ~0.9 s |
| Single prediction | ~0.2 s | ~0.01 s |
Same algorithm, same accuracy. The speedup comes from the release build profile (opt-level = 3, lto = true, codegen-units = 1).
Inputs from the datasets
анна -> female (confidence 99.8%) дмитрий -> male (confidence 100.0%) ольга -> female (confidence 99.5%) александр -> male (confidence 99.7%) екатерина -> female (confidence 100.0%) mary -> female (confidence 99.0%) john -> male (confidence 100.0%) elizabeth -> female (confidence 99.7%) alexander -> male (confidence 99.8%) catherine -> female (confidence 99.9%)
Full forms not in the datasets
сара -> female (confidence 85.5%) мара -> female (confidence 93.9%) федот -> male (confidence 96.1%) жанна -> female (confidence 99.9%) ева -> female (confidence 62.1%) karl -> male (confidence 95.0%) victoria -> female (confidence 94.9%) diana -> female (confidence 99.7%) george -> male (confidence 100.0%) peter -> female (confidence 99.7%) wrong
19 out of 20 correct. The single failure (peter) is a known limitation of the small training set: the model has never seen a short male name ending in -er, and the closest patterns in the training data are female (elizabeth, catherine, mary).
name-gender-nn-rs/ ├── Cargo.toml ├── Cargo.lock ├── data/ │ ├── names_ru.json # Russian dataset (Cyrillic) │ └── names_en.json # English dataset (Latin) ├── src/ │ ├── main.rs # CLI entry point (clap) │ ├── model.rs # NameNet: forward, train_step, save, load │ ├── train.rs # training │ ├── predict.rs # inference │ └── check_data.rs # dataset validation ├── LICENSE # BSD 3-Clause License ├── DISCLAIMER.md # full legal disclaimer └── README.md
weights_*.json files are generated by train and are not tracked by git.
Open the dataset file and add a name to either female or male:
{
"alphabet": "абвгдеёжзийклмнопрстуфхцчшщъыьэюя_",
"female": ["анна", "...", "александра"],
"male": ["иван", "...", "александр"]
}
Then retrain:
cargo run --release -- train --data data/names_ru.json --out weights_ru.json
Create data/names_XX.json with the correct alphabet and name lists, then train:
cargo run --release -- train --data data/names_XX.json --out weights_XX.json cargo run --release -- predict --weights weights_XX.json
The model reads the alphabet from the dataset, so any language with a single-alphabet script works out of the box.
By using this software, you agree to the full disclaimer terms.
Software provided "AS IS" without warranty. You assume all risks.
Full legal disclaimer: See DISCLAIMER.md
License: BSD 3-Clause License