textpie/genderize
0
1---2language:3- multilingual4license: cc-by-nc-4.05library_name: pytorch6tags:7- text-classification8- gender-detection9- nationality10- name-analysis11- byte-level12- cpu13pipeline_tag: text-classification14---15 16# genderize — cora / ultra17 18Two models that take a personal name and return a **gender** (M/F) and a19**country** (226 ISO-3166 alpha-2 codes), with probabilities. Byte-level,20CPU-only, no tokenizer and no vocabulary file: you feed them a string.21 22## Package contents23 24| File | What it is |25|---|---|26| `genderize_cora.pt` | weights, cora (3.1 MB) — **CC BY-NC 4.0** |27| `genderize_ultra.pt` | weights, ultra (12.9 MB) — **CC BY-NC 4.0** |28| `genderize_cora.config.json` | `{"ch": 160}` — CC BY-NC 4.0 |29| `genderize_ultra.config.json` | `{"ch": 384}` — CC BY-NC 4.0 |30| `genderize_cora.calibration.json` | per-head temperature — CC BY-NC 4.0 |31| `genderize_ultra.calibration.json` | per-head temperature (the file additionally records a calibration-error metric) — CC BY-NC 4.0 |32| `maps.json` | class ids: gender `M/F`, 226 countries — CC BY-NC 4.0 |33| `genderize_infer.py` | standalone inference code (needs `torch` and `numpy`) — **MIT** |34| `LICENSE` | full text of CC BY-NC 4.0 (weights) |35| `LICENSE-CODE` | full text of the MIT License (inference code) |36| `COMMERCIAL_USE.md` | what counts as non-commercial use, and how to obtain a commercial licence |37 38## What the models do39 40| Variant | Gender | Country | Size |41|---|---|---|---|42| `genderize-cora` | 2 classes (M/F) | 226 classes | ~0.77M parameters, ch=160 |43| `genderize-ultra` | 2 classes (M/F) | 226 classes | ~3.21M parameters, ch=384 |44 45`ultra` is the larger, more accurate variant; `cora` is the lighter one. Both run46on CPU: on an Intel i3-6100T (2 cores, 2 threads used) the network alone processes47about **850 names/s** (`cora`) and **160 names/s** (`ultra`) in batches of 100.48 49## How it works50 51**1. Normalisation.** The input name is normalised before anything else:52Unicode **NFC**, **lowercase**, **whitespace collapsed** (internal runs and53leading/trailing spaces become a single space). The normalised form is what the54weights saw, so this step must not be changed or skipped:55 56 " MARÍA GARCÍA " -> "maría garcía"57 58**2. Encoding.** The normalised text is encoded as **UTF-8 and truncated to 4859bytes** (not 48 characters: an accented or non-Latin character takes more than60one byte, so the effective character budget is smaller). Each byte becomes an61integer in 0–255; byte value 0 is the padding value. A name shorter than 48 bytes62is padded with zeros.63 64**3. Network.** Byte-level, dual-head 1-D convolutional classifier:65 66- one embedding table, 256 entries (one per byte value) of width 64, padding67 index 0;68- a 1×1 convolution projecting 64 → `ch` channels;69- four residual 1-D convolution blocks, kernel sizes **3, 5, 7, 3**, each with70 convolution + BatchNorm + GELU around a residual connection, padding to keep71 the length;72- the masked positions are pooled twice — mean-pooling and max-pooling — and the73 two vectors are concatenated;74- a shared layer of 512 units (GELU, plus a dropout layer that is inactive at75 inference);76- two linear heads read out from it: **gender**, 2 classes, and **country**,77 226 classes.78 79`cora` uses `ch = 160`, `ultra` `ch = 384`; those are the only differences80between the two configs.81 82**4. Probabilities.** Because it is a *convolutional* stack, the model sees all83byte positions at once: character order matters through the convolution kernels,84not through a recurrent state. Logits are divided by a **per-head temperature**85before softmax — `temp_gender` and `temp_country` from the calibration file:86 87| Variant | temp_gender | temp_country |88|---|---|---|89| cora | 1.0096479654312134 | 1.0 |90| ultra | 1.0460342168807983 | 0.939997673034668 |91 92**5. Decision rule.** Gender is reported as `male` when P(M) ≥ 0.5, otherwise93`female`; the reported probability is the probability of the reported class.94Countries are returned as the **top-k** codes (default 5, `--top`) sorted by95probability.96 97**6. Output.** One record per input name:98 99 {"name": "...", "gender": "male|female", "probability": 0.0-1.0,100 "countries": [{"code": "IT", "probability": 0.0-1.0}, ...], "model": "cora|ultra"}101 102## Loading and using the weights103 104All files sit flat in this repository. Download them (for example with105`huggingface_hub.snapshot_download("textpie/genderize")`) and run the reference106driver from that directory:107 108 pip install torch numpy109 python genderize_infer.py --variant ultra --top 3 "Andrea Rossi"110 111In Python:112 113```python114from genderize_infer import Genderize115 116model = Genderize("ultra") # or Genderize("cora"); pass models_dir=... if the files live elsewhere117model.predict(["Andrea Rossi"], top=3)118```119 120Output for the five names published with the examples (`--variant ultra`),121reproduced locally against these exact weight files:122 123| Input | Gender | P | Country top-3 |124|---|---|---|---|125| Andrea Rossi | male | 0.849 | IT 0.84, FR 0.05, US 0.02 |126| Yuki Tanaka | female | 0.589 | JP 0.98, US 0.01, ID 0.00 |127| María García | female | 0.995 | ES 0.42, MX 0.13, AR 0.09 |128| Chen Wei | male | 0.692 | CN 0.56, TW 0.13, SG 0.09 |129| Fatima Al Sayed | female | 0.996 | AE 0.35, OM 0.19, SA 0.14 |130 131## Benchmarks132 133Source: **dbtool.it/benchmark**. These are **not** new measurements taken for134this card and no re-measurement was performed here.135 136- **Bench**: 25,000 names never seen in training, scored on the **network alone**.137- The dictionary layer used by the hosted API does not contribute on unseen138 names, so these figures describe the released weights.139 140| Metric | cora | ultra |141|---|---|---|142| Gender accuracy | 97.9 % | 98.2 % |143| Country top-1 accuracy | 82.6 % | 83.7 % |144 145Per-country figures for the full hosted system are on https://dbtool.it/academic; an146independent open bench on public WGND 2.0 names (network alone, losses included) is147on https://dbtool.it/benchmark.148 149## What this release does NOT include150 151- **The dictionary layer of the API.** The hosted API combines the network with152 a proprietary frequency layer (exact-name and per-country M/F frequencies)153 derived from production data. That layer is **not part of this release**:154 you get the network alone. Consequence: **the public API can answer155 differently from the weights you download**, especially on very frequent156 names. Documented example: `Yuki Tanaka` scores *female 0.59* with the network157 alone (the value reproduced above), while the API with its dictionary layer158 answers *male 0.58*.159- **Everything about how the models were trained**: no recipe, no epochs, no160 optimiser, no data split, no training hyperparameters, no data sources and no161 per-country counts. This release ships a usable model, not the process behind162 it, and no training example.163 164## Training data — nature only165 166The models were trained on **name–gender–country pairs covering 226 countries,167tens of millions of examples**. That is the whole description this release168provides: the corpus is **not redistributed**, and its sources, composition and169per-country sizes are not part of the package.170 171## Limitations172 173- **East Asian names**: accuracy drops to roughly **82–88 %**; Chinese, Korean174 and Japanese names are frequently confused with one another.175- **Names ambiguous across countries**: many names are plausible in several176 countries, so a top-1 of ~83 % means roughly one name in six gets the wrong177 country. `Andrea` is the classic case: male in Italy, female elsewhere. Treat178 the country score as a prior, and never as a single-country verdict.179- **48-byte truncation**: only the first 48 UTF-8 bytes reach the model. Long180 names and long compounds are silently cut, and multi-byte characters consume181 more of the budget than plain ASCII.182- **Empty or near-empty input**: an empty or fully-trimmed name is encoded as 48183 padding bytes and still returns a prediction. Validate your input.184- **Binary gender**: the gender head has two classes; names that do not fit them185 are forced into the closer one.186- **Transliteration**: results depend on how the name was romanised upstream;187 different romanisations of the same name can disagree.188- **Dictionary gap**: the released weights are the network alone, so for very189 frequent names they can differ from the hosted API (see above).190 191## Licence192 193Two licences, one per artefact:194 195- **Weights** — `genderize_cora.pt`, `genderize_ultra.pt`, their `.config.json`196 and `.calibration.json`, and `maps.json` — are released under **Creative197 Commons Attribution-NonCommercial 4.0 International (CC BY-NC 4.0)**, full198 text in `LICENSE`. You may download, run, study, modify and redistribute them199 and their derivatives **for non-commercial purposes**, with attribution200 (*dbtool.it, genderize cora/ultra, 2026*) and an indication of changes.201- **Inference code** — `genderize_infer.py` — is released under the **MIT License**,202 full text in `LICENSE-CODE`. It can be reused freely; it carries no model203 knowledge.204 205**Commercial use of the weights is not granted by this licence.** The commercial206channel is **dbtool.it** (the hosted API and the on-premise licence), or a207separate written licence from the rights holder. What counts as commercial use,208and how to request a licence, is set out in **`COMMERCIAL_USE.md`**.209 210The training data is **not** part of this release, and neither is the dictionary211layer of the hosted API (see above).212 213## Contact214 215dbtool — https://dbtool.it — open-weights page: https://dbtool.it/open-models.html216Domenico Gigante, d.gigante@tech-time.it217 