Aadya: an open model for forecasting the next period
An open model that forecasts the next period start as a probability for every cycle length, with a version small enough for a phone and a public benchmark to hold it to account.
Overview
Most period trackers give you one predicted date. Aadya gives a probability for every possible cycle length instead, so an app can say "most likely these days, about 8 in 10 chance" and never promise one brittle date. It runs on your own device, so your cycle data never has to leave it.
The name comes from Sanskrit: Aadya (आद्या) means "the first" or "the beginning", which fits a model that forecasts the start of a cycle, whose day one is the first day of bleeding.
There are two models behind one API, an open benchmark to test them (and everyone else's) against, a synthetic-user generator, and a small reference engine for places a large model does not fit.
| Input | Past cycle lengths, days since the last period, optional age group, optional ovulation-test day |
| Output | A probability for each cycle length from 1 to 120 days |
| Training data | Synthetic users only. Public cycle datasets are used for evaluation, never for training |
| License | Apache-2.0 for the code and the weights |
| Privacy | Runs on the device, learns from confirmed periods locally, makes no network calls |
How it works
You give it the lengths of your past cycles and how many days have passed since the last period started. It returns a probability for each possible length of the cycle you are in. From that distribution an app can show the most likely day and an 80% window.
A few things follow from that design:
- Every day gets a probability. The model never collapses the answer to a single date.
- It widens when it is unsure. With thin or messy history, the window gets wider instead of faking precision. An 80% window should hold the real day about 8 times in 10, and that is checked.
- It learns, locally. After each confirmed period, the model can update a small state on the device. That state is never uploaded, and nothing needs an account.
Two sizes, one API
| aadya-m1 | aadya-m1-mini | |
|---|---|---|
| Parameters | 256M | 0.84M |
| Weights on disk | about 1 GB | 3.4 MB |
| Forecast time on CPU | 291.9 ms | 3.4 ms |
| Built for | Servers, desktops, research and fine-tuning | Phones, browsers and low-power devices |
The mini is about 300 times smaller and about 85 times faster on a CPU, and on the public real data it is level with the large model: mean error 1.933 against 1.930 on 364 real users, and 2.876 against 2.889 on 5,400 simulated users.
Benchmarks
Error is measured with CRPS, a proper scoring rule for probability forecasts. Lower is better. The "usual method" below is what many trackers do: the rolling median of the last 3 cycles.
How much of the usual method's error aadya-m1 removes, track by track:
| Track | Data | aadya-m1 | Usual method | Error lower by | Against the strongest comparison |
|---|---|---|---|---|---|
| Simulated users, all cases | 539 users | 2.92 | 3.70 | 21% | Slightly ahead of the best competitor (LSTM) |
| Hard case: life-stage mix | simulated | 4.78 | 6.83 | 30% | Better than the Bayes reference |
| Real data: all public users | 364 users | 1.93 | 2.35 | 18% | Slightly ahead of the Bayes reference |
| Real data: Creighton | 251 users | 2.09 | 2.54 | 18% | Slightly ahead of the Bayes reference |
| Real data: Marquette | 113 users | 1.57 | 1.95 | 19% | On par with the Bayes reference |
| Mid-cycle, no marker (mcPHASES) | 110 cycles | 2.43 | 3.49 | 30% | Poisson-with-skips slightly ahead (2.34 vs 2.43) |
| With an ovulation-test marker | 110 cycles | 1.70 | 3.49 | 51% | Better than the best competitor |
| 20% of period logs missed | simulated | 9.55 | 12.45 | 23% | On par with the Bayes reference |
| No history, Marquette | 113 users | 2.18 | 2.13 | -2% | On par with the 28-day baseline |
And against the other methods, on the three main boards (mean CRPS, lower is better):
| Method | Simulated (539) | Creighton (251) | Marquette (113) |
|---|---|---|---|
| aadya-m1 | 2.925 | 2.091 | 1.572 |
| Hierarchical Bayes reference | 3.026 | 2.119 | 1.580 |
| LSTM | 2.965 | 2.139 | 1.639 |
| Poisson-with-skips | 3.109 | 2.491 | 1.969 |
| Rolling median | 3.702 | 2.536 | 1.950 |
| 28-day constant | 3.712 | 2.717 | 2.145 |
To read these plainly: on simulated users it is the best open method I could run. On the 364 public real users it is first on mean error, slightly but clearly ahead of the Bayes reference (about 1% lower error) and clearly ahead of every other method. The big gaps are against what trackers do today. With cycle dates alone, clean real data leaves little room above the Bayes reference.
How it was tested: seeds and folds were fixed in advance, and every number comes from a committed report. The 251 Creighton users were scored in 5 cross-fitted folds, so no user is both fitted and scored. The 113 Marquette users were scored out of distribution, and the network is never trained on real data. I make no comparison to closed apps, because there is no shared data to compare on.
Where it wins, ties and falls short
- Wins on irregular and changing cycles. 30% less error than the usual method on the hardest simulated group.
- Hard for everyone when people forget to log. Error rises for every method as logs go missing. For aadya-m1 it goes from 3.0 to 9.5 when 20% of periods are unlogged.
- A tie on real users. 18% less error than the usual method on 364 real users, and a close race with the Bayes reference.
- A win, with a caveat, from an ovulation test. The 80% window narrows from about 12 days to about 7, in a study of 41 people.
- On par for a brand-new user. With no history it matches a plain 28-day baseline.
- Falls short on a generator it never saw. On an unseen simulated generator the lead over the strongest methods disappears, though it stays clearly ahead of simple heuristics.
Optional ovulation-test input
This input is experimental. On 41 mcPHASES participants it narrowed the 80% window from about 12 to about 7 days (CRPS difference -0.73, 95% interval -1.25 to -0.24). Mean error across 110 cycles was 1.70 with the marker, 2.43 without it, and 3.49 for the rolling median.
It only tightens the window for the next period. It never produces an ovulation date or a fertile window. It has been tested in one small study, so treat it as a promising result and not a settled one.
Intended use
Apps that show period timing with honest uncertainty, and research and education.
Out of scope: diagnosis, contraception or conception planning, "safe days", treatment decisions, and any server-side handling of personal data. Aadya is not a medical device.
Limitations
- On real data the lead over the classical reference is small, and the evidence is simulated users plus two public cohorts.
- It is less accurate for very irregular cycles, postpartum and perimenopause phases, hormonal contraception, and very short histories.
- Forgotten period logs raise the error sharply.
- The ovulation-test input has been tested in only one small study.
- The weights are trained on synthetic data only, so real adherence and life-stage effects may be missed.
Use it
pip install "aadya[torch] @ git+https://github.com/manasdutta04/aadya#subdirectory=packaging"
from huggingface_hub import snapshot_download
from aadya_neural.torch_forecaster import AadyaM1Forecaster
from aadya_sim.types import Cohort
model = AadyaM1Forecaster(snapshot_download("manasdutta04/aadya-m1"))
pmf = model.forecast([28, 30, 27, 29], elapsed=0, cohort=Cohort())
# pmf[k - 1] is the probability that the cycle is k days long
The same call works with aadya-m1-mini, which is the one to use on a phone or in a browser. Rules for apps that integrate it (a privacy contract, always showing uncertainty, no fertility claims) are in the repository's integration guide.
Beat it
AadyaBench is an open benchmark with proper scoring (CRPS), fixed seeds, paired confidence intervals and a public leaderboard. To compete, write a forecaster, run the submit command and open a pull request. Aadya also ships a synthetic-user generator with oracle predictors, and a small Bayesian reference engine in Python and TypeScript for places where a 1 GB model does not fit.
Links
Cite
@misc{dutta2026aadyam1,
title = {aadya-m1: An Open, On-Device Probabilistic Model for Calibrated Next-Period Forecasting},
author = {Dutta, Manas},
year = {2026},
doi = {10.5281/zenodo.23236800},
url = {https://doi.org/10.5281/zenodo.23236800},
note = {Preprint}
}