textpie/genderize
genderize — cora / ultra
Two models that take a personal name and return a gender (M/F) and a country (226 ISO-3166 alpha-2 codes), with probabilities. Byte-level, CPU-only, no tokenizer and no vocabulary file: you feed them a string.
Package contents
What the models do
ultra is the larger, more accurate variant; cora is the lighter one. Both run on CPU: on an Intel i3-6100T (2 cores, 2 threads used) the network alone processes about 850 names/s (cora) and 160 names/s (ultra) in batches of 100.
How it works
1. Normalisation. The input name is normalised before anything else: Unicode NFC, lowercase, whitespace collapsed (internal runs and leading/trailing spaces become a single space). The normalised form is what the weights saw, so this step must not be changed or skipped:
" MARÍA GARCÍA " -> "maría garcía"
2. Encoding. The normalised text is encoded as UTF-8 and truncated to 48 bytes (not 48 characters: an accented or non-Latin character takes more than one byte, so the effective character budget is smaller). Each byte becomes an integer in 0–255; byte value 0 is the padding value. A name shorter than 48 bytes is padded with zeros.
3. Network. Byte-level, dual-head 1-D convolutional classifier:
- one embedding table, 256 entries (one per byte value) of width 64, padding index 0;
- a 1×1 convolution projecting 64 →
chchannels; - four residual 1-D convolution blocks, kernel sizes 3, 5, 7, 3, each with convolution + BatchNorm + GELU around a residual connection, padding to keep the length;
- the masked positions are pooled twice — mean-pooling and max-pooling — and the two vectors are concatenated;
- a shared layer of 512 units (GELU, plus a dropout layer that is inactive at inference);
- two linear heads read out from it: gender, 2 classes, and country, 226 classes.
cora uses ch = 160, ultra ch = 384; those are the only differences between the two configs.
4. Probabilities. Because it is a convolutional stack, the model sees all byte positions at once: character order matters through the convolution kernels, not through a recurrent state. Logits are divided by a per-head temperature before softmax — temp_gender and temp_country from the calibration file:
5. Decision rule. Gender is reported as male when P(M) ≥ 0.5, otherwise female; the reported probability is the probability of the reported class. Countries are returned as the top-k codes (default 5, --top) sorted by probability.
6. Output. One record per input name:
{"name": "...", "gender": "male|female", "probability": 0.0-1.0, "countries": [{"code": "IT", "probability": 0.0-1.0}, ...], "model": "cora|ultra"}
Loading and using the weights
All files sit flat in this repository. Download them (for example with huggingface_hub.snapshot_download("textpie/genderize")) and run the reference driver from that directory:
pip install torch numpy python genderize_infer.py --variant ultra --top 3 "Andrea Rossi"
In Python:
from genderize_infer import Genderize
model = Genderize("ultra") # or Genderize("cora"); pass models_dir=... if the files live elsewhere
model.predict(["Andrea Rossi"], top=3)Output for the five names published with the examples (--variant ultra), reproduced locally against these exact weight files:
Benchmarks
Source: dbtool.it/benchmark. These are not new measurements taken for this card and no re-measurement was performed here.
- Bench: 25,000 names never seen in training, scored on the network alone.
- The dictionary layer used by the hosted API does not contribute on unseen names, so these figures describe the released weights.
Per-country figures for the full hosted system are on https://dbtool.it/academic; an independent open bench on public WGND 2.0 names (network alone, losses included) is on https://dbtool.it/benchmark.
What this release does NOT include
- The dictionary layer of the API. The hosted API combines the network with a proprietary frequency layer (exact-name and per-country M/F frequencies) derived from production data. That layer is not part of this release: you get the network alone. Consequence: the public API can answer differently from the weights you download, especially on very frequent names. Documented example:
Yuki Tanakascores female 0.59 with the network alone (the value reproduced above), while the API with its dictionary layer answers male 0.58. - Everything about how the models were trained: no recipe, no epochs, no optimiser, no data split, no training hyperparameters, no data sources and no per-country counts. This release ships a usable model, not the process behind it, and no training example.
Training data — nature only
The models were trained on name–gender–country pairs covering 226 countries, tens of millions of examples. That is the whole description this release provides: the corpus is not redistributed, and its sources, composition and per-country sizes are not part of the package.
Limitations
- East Asian names: accuracy drops to roughly 82–88 %; Chinese, Korean and Japanese names are frequently confused with one another.
- Names ambiguous across countries: many names are plausible in several countries, so a top-1 of ~83 % means roughly one name in six gets the wrong country.
Andreais the classic case: male in Italy, female elsewhere. Treat the country score as a prior, and never as a single-country verdict. - 48-byte truncation: only the first 48 UTF-8 bytes reach the model. Long names and long compounds are silently cut, and multi-byte characters consume more of the budget than plain ASCII.
- Empty or near-empty input: an empty or fully-trimmed name is encoded as 48 padding bytes and still returns a prediction. Validate your input.
- Binary gender: the gender head has two classes; names that do not fit them are forced into the closer one.
- Transliteration: results depend on how the name was romanised upstream; different romanisations of the same name can disagree.
- Dictionary gap: the released weights are the network alone, so for very frequent names they can differ from the hosted API (see above).
Licence
Two licences, one per artefact:
- Weights —
genderize_cora.pt,genderize_ultra.pt, their.config.jsonand.calibration.json, andmaps.json— are released under Creative Commons Attribution-NonCommercial 4.0 International (CC BY-NC 4.0), full text inLICENSE. You may download, run, study, modify and redistribute them and their derivatives for non-commercial purposes, with attribution (dbtool.it, genderize cora/ultra, 2026) and an indication of changes. - Inference code —
genderize_infer.py— is released under the MIT License, full text inLICENSE-CODE. It can be reused freely; it carries no model knowledge.
Commercial use of the weights is not granted by this licence. The commercial channel is dbtool.it (the hosted API and the on-premise licence), or a separate written licence from the rights holder. What counts as commercial use, and how to request a licence, is set out in `COMMERCIAL_USE.md`.
The training data is not part of this release, and neither is the dictionary layer of the hosted API (see above).
Contact
dbtool — https://dbtool.it — open-weights page: https://dbtool.it/open-models.html Domenico Gigante, d.gigante@tech-time.it
