Open-source project
WildChlamydia/MiVOLO avatar
WildChlamydia/MiVOLO

MiVOLO: estimating age and gender from a face, a body, or both

MiVOLO age & gender transformer neural network

542 stars99 forksPythonApache-2.0

At a glance

What is it?
MiVOLO is a multi-input transformer that takes a face crop, a person crop, or both, and predicts age and gender from them, and its published benchmarks show why the second input matters: the same checkpoint scores 3.99 years of mean absolute age error using face and body together and 6.87 using the body alone. The code, the weights and a face detector are all published, alongside a Lagenda dataset the authors built for the task.
Who is it for?
Adopt MiVOLO if you are doing research on age or gender estimation from images, or building content-moderation filtering where a rough age gate is needed, and you are comfortable with a model whose gender output is a binary label.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 141 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What the model does, and the two papers behind it

MiVOLO stands for Multi-input Transformer for Age and Gender Estimation, and the repository is described as an age and gender transformer neural network.

Two papers sit behind the code. The first is MiVOLO: Multi-input Transformer for Age and Gender Estimation, by Maksim Kuprashevich and Irina Tolstykh, from 2023, arXiv 2307.04616. The second is Beyond Specialization: Assessing the Capabilities of MLLMs in Age and Gender Estimation, by Kuprashevich, Grigorii Alekseenko and Tolstykh, from 2024, arXiv 2403.02302.

The second paper's title is the more interesting one, because it says the first model was specialised and the second asks what general-purpose multimodal language models can do at the same task. The repository carries the code and checkpoints for both lines of work, so the two are connected rather than separate.

The links at the top of the README give the full set of entry points. There is a demo on Hugging Face Spaces, the model weights on Hugging Face as mivolo_v2, a separate YOLO-Face-Person-Detector, a Telegram bot called AnyAgeBot, a link to the Lagenda dataset, and a BibTeX citation section.

The most recent addition is MiVOLO-Next, described as the successor of MiVOLO v2, with live demos on Spaces for age and gender and for adult versus minor. The line under it gives the headline figures: a dual-stream face plus person backbone, APPA-Real MAE of 4.07, and 28,722 FPS on an A100.

The primary language is Python, the licence listed on the repository is Apache-2.0, the default branch is main, and the last push was on 2026-06-04 with the project not archived. The repository publishes no GitHub releases, so the model weights on Hugging Face are the distribution channel rather than the source repository.

There is a licence wrinkle worth flagging early, because it is easy to miss. The repository metadata says Apache-2.0, but the setup.py header comment says MiVOLO, Attribution-ShareAlike 4.0, and the package classifiers list License :: Attribution-ShareAlike 4.0. The packaging metadata is the more specific statement, and the two disagree.

Why a multi-input model, and what the body crop adds

The architectural idea is in the name and the benchmark tables make its value concrete.

Most age and gender models take a face crop. MiVOLO takes a face and a person crop, and the two are fed through a dual-stream backbone so the model can use whichever evidence is available and combine them. Where the model is trained on both, the tables report a bracketed face plus body figure and a body-only figure for comparison, and the gap is where the argument lives.

Take the mivolo_d1 checkpoint trained and tested on Lagenda. The age mean absolute error is 3.99 using face and body together, and 6.87 using the body alone. The Age CS at 5 metric, which is the share of predictions within five years, is 71.27 for face and body and 46.32 for body only. Gender accuracy is 97.36 against 96.48.

So the body crop alone gets you most of the way on gender, and roughly half the way on age, and combining the two gives a clear improvement on the harder of the two tasks.

The reason is not hard to guess from the results. Gender is mostly a face attribute and the face is the higher-resolution crop of the same person, so adding the body adds little. Age is a different matter: a face gives you some information, but the body carries a substantial amount of it independently, and the two are not perfectly redundant. That is why the body-only number is so much worse on age, and why combining beats either.

The body-only figure is also the interesting failure case to look at, because it is where the model has to reason about proportions and posture rather than appearance, and where a training set with limited clothing variation would show up.

This is why the second paper is about assessing general MLLMs. If a multimodal language model is given a whole image rather than a cropped face, it has the body crop for free, and the question becomes whether that extra evidence is used well.

The benchmark tables, and what the train and test columns are telling you

The README carries three tables, and the one detail that matters most in all of them is that the dataset column is explicit about what was used for training and what was used for testing.

In the pretrained models table, the models are volo_d1, mivolo_d1 and mivolov2_d1_384x384, and the dataset column is a single train and test set: IMDB-cleaned, UTKFace or Lagenda. The IMDB-cleaned rows are the face-only volo_d1 variants, and the best of them reach 4.22 age MAE with 68.68 CS at 5 and 99.38 gender accuracy.

The mivolov2_d1_384x384 checkpoint trained on Lagenda is the best in that table, at 3.65 age MAE, 74.48 CS at 5 and 97.99 gender accuracy. The resolution in the name is 384 by 384, and it is the only model in the table with a resolution in its name, which tells you the input size was part of the design rather than a constant.

Then the regression benchmarks, where the train and test datasets are different. A mivolo_d1 trained on Lagenda and tested on AgeDB gets 5.55 age MAE, 55.08 CS at 5 and 98.3 gender accuracy, and one trained on IMDB-cleaned and tested on AgeDB gets 5.58, 55.54 and 97.93.

That jump from about 4 on the matched set to about 5.5 on AgeDB is the cross-dataset gap, and it is the number to read if you are deploying this on data that is not Lagenda. Gender barely moves, from 99.46 down to 98.3. Age loses about 1.3 years of accuracy.

Then the classification benchmarks, where the metric is age accuracy within a bucket rather than MAE. A model trained on Lagenda and tested on FairFace gets 61.07 age accuracy and 95.73 gender accuracy, both with face and body. A model trained on Lagenda and tested on Adience gets 68.69 age accuracy and 96.51 gender accuracy with face only.

The FairFace number is the one to notice. FairFace is a dataset built with an emphasis on balanced representation across demographic groups, and 61 percent age accuracy there against 68.69 on Adience is a substantial drop for a bucket-based metric. Since the same checkpoint does markedly better on its own training distribution, the gap points at demographic generalisation rather than at a broken metric, and it is exactly the thing a cross-dataset evaluation is there to surface.

The README also gives the way to reproduce all of it. There is a script, scripts/valid_age_gender.sh, described as the way to reproduce results with the checkpoints, so the numbers are checkable rather than asserted.

The package, its dependencies and the tooling around it

The repository layout shows a research code release rather than a polished library, and that is the right shape for it.

There is a mivolo/ directory holding the package itself, with the setup.py packages list naming mivolo, mivolo.model, mivolo.data and mivolo.data.dataset explicitly, so the model, the data loaders and the dataset definitions are separate subpackages. The top level also has demo.py, eval_pretrained.py, eval_tools.py and measure_time.py, which between them cover running the model, evaluating the published checkpoints and timing the model, which is consistent with a paper that reports both accuracy and frames per second.

There are tools/ and scripts/ directories for the training and evaluation tooling, images/ for the assets the README uses, and mypy.ini, setup.cfg, .flake8, .isort.cfg and a .pre-commit-config.yaml, so the project runs type checking, several linters and import sorting.

The setup.py is a little unusual and worth reading. It reads the requirements from requirements.txt at build time with pkg.parse_requirements and passes them through as install_requires, and it executes the file mivolo/version.py to obtain the version number, which is the pattern that keeps a single source of truth for the version.

The metadata is research-shaped. The description is Layer MiVOLO for SOTA age and gender recognition, the author is Layer Team, SberDevices, and the classifiers list Development Status 4 Beta, Intended Audience for Developers, Education and Science/Research, and the topics are Software Development plus Scientific/Engineering and Artificial Intelligence. The project URLs include a Datasets entry pointing at the Lagenda dataset page.

The requirements list is short and tells you the stack. huggingface_hub is for the model weights, ultralytics at 8.1.0 is the detection and training toolkit behind the face and person detector, timm at 0.8.13.dev0 is the model zoo that supplies the backbones, yt_dlp is there for pulling video, and lapx at 0.5.2 or newer is a linear assignment library, which is the kind of dependency that appears in face pipelines that match detections to crops.

The Python floor is 3.8, and the classifiers list support through 3.11.

How to evaluate it, and what to check first

There are five things to consider, and the first two are about whether you should be running this at all.

First, what you are trying to detect. The model estimates age and gender from a face, a person, or both, and the published artefacts include a detector, weights and a demo that separates adults from minors. Age estimation from images is a sensitive thing to deploy, and the questions it raises, about which faces a model was trained on and whether it works on the faces in your population, are not answered by a benchmark table on three datasets.

Second, the gender axis. The models output a binary gender classification, and the accuracy figures in the tables are near 98 to 99 percent on the matched datasets. A binary label is a design decision baked into the training data, and it is worth being explicit that a high accuracy figure here is a statement about the benchmark's labelling convention and not about a rich attribute. The 2024 paper's title, assessing what multimodal language models can do at this task, is a reasonable place to look for a fuller discussion of what the labels mean.

Third, the cross-dataset gap, and this is the practical number. On its own training distribution the best checkpoint reaches 3.65 years of age MAE, and on AgeDB the same family of model gets 5.55. The gender accuracy barely moves. So if your data is not Lagenda, expect the age figure to be worse than the headline, and benchmark on your own data before trusting it.

Fourth, the FairFace result, which is the one to interrogate rather than quote. 61.07 age accuracy on FairFace against 68.69 on Adience for a comparable model, with gender accuracy of 95.73 against 96.51, suggests the age head is where the imbalance shows. A dataset built to be balanced is the right instrument for finding that out, and the fact that it is in the table is a point in the authors' favour.

Fifth, the practical shape of the deployment. There is a detector as a separate artefact, so the pipeline is detect, crop face, crop person, run the model, and both crops have to line up with the same detection. The 28,722 FPS figure on an A100 is a throughput number for the model on batches, and whether your pipeline reaches it depends on the detector and the image handling around it. The measure_time.py script in the repository is there because that question needed answering.

What you get is a well-documented research release with published weights, a dataset, a detector and reproducible evaluation scripts, and a lineage of two papers. The honest caveats are the ones above: a binary gender label, a measurable cross-dataset and cross-demographic gap on age, and a licence that needs reading because the repository listing and the package metadata disagree on it.

Editorial conclusion

Adopt MiVOLO if you are doing research on age or gender estimation from images, or building content-moderation filtering where a rough age gate is needed, and you are comfortable with a model whose gender output is a binary label. Do not adopt it as a general-purpose demographic classifier on the strength of a near 99 percent accuracy figure, because that number describes a labelled benchmark rather than the attribute, and check the FairFace and AgeDB numbers rather than the matched-distribution ones, since the age head loses about 1.3 years of mean absolute error and roughly seven points of bucket accuracy on a balanced dataset. Before you commit, read the licence carefully, because the licence listed on the repository says Apache-2.0 while the package metadata and the setup.py header say Attribution-ShareAlike 4.0, and run the valid_age_gender.sh script on your own data to get numbers that describe your population rather than Lagenda.

Frequently asked questions

What is MiVOLO?

It is a multi-input transformer neural network for age and gender estimation, described as Layer MiVOLO for SOTA age and gender recognition. It takes a face crop, a person crop, or both, through a dual-stream backbone, and the code and weights are published alongside a face and person detector and a purpose-built dataset called Lagenda.

Which papers does the MiVOLO repository correspond to?

Two. MiVOLO: Multi-input Transformer for Age and Gender Estimation by Maksim Kuprashevich and Irina Tolstykh from 2023, arXiv 2307.04616, and Beyond Specialization: Assessing the Capabilities of MLLMs in Age and Gender Estimation by Kuprashevich, Grigorii Alekseenko and Tolstykh from 2024, arXiv 2403.02302.

How much does using the person crop as well as the face help?

On the mivolo_d1 checkpoint trained and tested on Lagenda, the age mean absolute error is 3.99 with face and body together and 6.87 with body alone, and Age CS at 5 is 71.27 against 46.32. Gender accuracy moves much less, from 97.36 to 96.48, since gender is largely a face attribute.

Which MiVOLO checkpoint performs best?

The mivolov2_d1_384x384 model trained and tested on Lagenda, with an age MAE of 3.65, an Age CS at 5 of 74.48 and a gender accuracy of 97.99. The older volo_d1 face-only models on IMDB-cleaned and UTKFace reach around 4.2 to 4.3 age MAE with gender accuracy near 97.7 to 99.4.

How do the cross-dataset results compare with the matched results?

A mivolo_d1 trained on Lagenda and tested on AgeDB gets an age MAE of 5.55 against about 4 on its own distribution, with gender accuracy at 98.3. In the classification benchmarks, a Lagenda-trained model tested on FairFace gets 61.07 age accuracy and 95.73 gender accuracy, while the same family tested on Adience gets 68.69 age accuracy, so the age head is where the cross-dataset gap shows.

What are the MiVOLO package requirements and tooling?

The requirements are huggingface_hub, ultralytics 8.1.0, timm 0.8.13.dev0, yt_dlp and lapx 0.5.2 or newer, with Python 3.8 as the floor. The repository includes mypy.ini, setup.cfg, .flake8, .isort.cfg and a pre-commit configuration, and the setup.py reads its dependencies from requirements.txt at build time and takes the version from mivolo/version.py.

Official sources

  1. Issues
  2. License: Apache-2.0
  3. README
  4. WildChlamydia/MiVOLO on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/wildchlamydia-mivolo.svg)](https://hysenlabs.com/projects/wildchlamydia-mivolo)

Was this useful?