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.

Aadya: an open model for forecasting the next period

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.

InputPast cycle lengths, days since the last period, optional age group, optional ovulation-test day
OutputA probability for each cycle length from 1 to 120 days
Training dataSynthetic users only. Public cycle datasets are used for evaluation, never for training
LicenseApache-2.0 for the code and the weights
PrivacyRuns 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.

Real aadya-m1 output on made-up example histories. The shaded band is the 80% window. In the middle panel, the blue line is the same irregular history with an ovulation test added.

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-m1aadya-m1-mini
Parameters256M0.84M
Weights on diskabout 1 GB3.4 MB
Forecast time on CPU291.9 ms3.4 ms
Built forServers, desktops, research and fine-tuningPhones, 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.

Same accuracy, very different size and speed. Error: lower is better.

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.

Mean error on the three boards. Shorter bars are better.

How much of the usual method's error aadya-m1 removes, track by track:

TrackDataaadya-m1Usual methodError lower byAgainst the strongest comparison
Simulated users, all cases539 users2.923.7021%Slightly ahead of the best competitor (LSTM)
Hard case: life-stage mixsimulated4.786.8330%Better than the Bayes reference
Real data: all public users364 users1.932.3518%Slightly ahead of the Bayes reference
Real data: Creighton251 users2.092.5418%Slightly ahead of the Bayes reference
Real data: Marquette113 users1.571.9519%On par with the Bayes reference
Mid-cycle, no marker (mcPHASES)110 cycles2.433.4930%Poisson-with-skips slightly ahead (2.34 vs 2.43)
With an ovulation-test marker110 cycles1.703.4951%Better than the best competitor
20% of period logs missedsimulated9.5512.4523%On par with the Bayes reference
No history, Marquette113 users2.182.13-2%On par with the 28-day baseline
Error removed compared with the usual tracker method. Blue: also better than the strongest comparison. Grey: not clearly ahead, or not tested.

And against the other methods, on the three main boards (mean CRPS, lower is better):

MethodSimulated (539)Creighton (251)Marquette (113)
aadya-m12.9252.0911.572
Hierarchical Bayes reference3.0262.1191.580
LSTM2.9652.1391.639
Poisson-with-skips3.1092.4911.969
Rolling median3.7022.5361.950
28-day constant3.7122.7172.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.
Forgotten logs hurt every method. aadya-m1 and the Bayes reference stay close together and well below the rolling median.

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.

41 participants, 110 cycles. The optional ovulation-test input narrows the 80% window and lowers the error.

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.

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}
}