Getting started
Install
pip install cloudposteriorThis pulls in PyMC, ArviZ, and the Modal client. For cloud execution you also need a (free) Modal account — authenticate once:
modal setupYour first cloud sample
The only change to your normal PyMC workflow is the with cp.cloud(...) line — pm.sample() stays exactly the same.
import pymc as pm
import cloudposterior as cp
with pm.Model() as model:
mu = pm.Normal("mu", 0, 5)
sigma = pm.HalfNormal("sigma", 5)
pm.Normal("obs", mu, sigma, observed=data)
with cp.cloud(model, remote=True, cache="disk"):
idata = pm.sample(draws=2000, chains=4)Run that cell again and the cached result returns instantly — no re-sampling.
What you can toggle
cp.cloud(model, ...) accepts independent switches:
remote=True— sample on an auto-sized cloud VM. Omit it to run locally with just caching/notifications.cache="disk"— persist results to./.cloudposterior(survives restarts). The defaultcache=Truekeeps results for the current session;cache=Falsedisables it.dashboard=True— a live web dashboard (convergence, traces, a Stop button). On by default forremote=True; passdashboard=Falseto skip it. The URL it prints carries an access token, so treat it as a secret.notify=True— push notifications to your phone via ntfy on sampling start, completion, and errors. Pass a string to choose the topic, or a dict for{"topic", "server"}. Auto- generated topics are random, but ntfy topics are public to anyone who knows them — use your own server for anything sensitive.instance="large"— override the auto-sized VM with a preset (small,medium,large,xlarge,gpu).until=True— stop early once every scalar parameter converges (R-hat <= 1.01, ESS >= 400). Pass a dict to set your own thresholds. Remote runs with the nutpie or pymc sampler only.overwrite=True— re-run and replace the cached entry instead of reading it.project="name"— namespace the remote volume and dashboard; defaults to the working directory name.progress=False— silence the live progress display.
See the examples for each feature in depth.
Fitting many models at once
cp.map fans a list of models out to one container each, sharing a dashboard:
idatas = cp.map([pooled, hierarchical, county], {"draws": 2000}, until=True)Cleanup
Remote runs keep a small project-scoped volume warm, and disk caching accumulates traces locally. Tear both down when you’re done:
import cloudposterior as cp
cp.cleanup_volumes(project="my-project")
cp.cleanup_cache()