YAML Runner Settings
This page documents the runner and pipeline keys: data loading, Stage 20
fitting, attached inference data, Stage 70 optimisation and Stage 35 blocked
holdout validation. The
YAML configuration overview lists all root keys,
YAML model specification covers the modelling
blocks, and YAML advanced blocks covers
prior_sensitivity, ai_advisor and diagnostics.
data
The runner loads data before building the model. It supports two CSV layouts.
Combined dataset
data:
dataset_path: "dataset.csv"
The runner reads the CSV, removes the target column from X, and uses that
column as y.
Separate feature and target files
data:
x_path: "X.csv"
y_path: "y.csv"
When loading y_path:
- if the configured target column exists, the runner uses that column
- otherwise, if the file has exactly one column, the runner uses that column and renames it to the target name
Target column resolution
The runner resolves the target column in this order:
PipelineRunConfig.target_columnor CLI--target-columntarget.column"y"
Use the CLI override only when you want to change how the runner reads the CSV.
Keep it consistent with target.column in YAML.
fit
fit controls Stage 20 fitting because the fit stage
calls:
context.model.fit(X=context.X, y=context.y, progressbar=False)
The runner merges these CLI or PipelineRunConfig overrides onto the YAML
fit block when they are provided:
drawstunechainscoresrandom_seed
The public YAML schema currently supports these fit keys:
drawstunechainscoresrandom_seedtarget_acceptprogressbarcompute_convergence_checks
Unknown fit keys are rejected when the YAML is loaded.
inference_data
inference_data.path is passed through to the YAML builder. If the file exists, AMMM3
attaches that InferenceData after graph construction. This occurs in Stage 00
for unlabelled models and Stage 10 for named estimators.
Important: the structured runner still executes Stage 20 and fits the model
again. inference_data.path does not currently skip fitting.
optimization
Add an optimization block when you want Stage 70 to run. If this block is
absent, Stage 70 is marked skipped.
The YAML builder validates this block when the config is loaded. start_date
and end_date are always required, and you must provide exactly one of:
optimization.budgetfor the preferred user-facing budget specoptimization.total_budgetfor the legacy per-period budget input
Unknown top-level optimization keys are rejected.
Preferred example:
optimization:
start_date: "2024-11-11"
end_date: "2025-01-27"
budget:
mode: relative
value: 1.10
basis: reference_window_total
Optional keys read by Stage 70:
| Key | Default | Meaning |
|---|---|---|
budget | None | Preferred user-facing budget spec: absolute or relative |
total_budget | None | Legacy per-period budget input kept for backward compatibility |
response_variable | total_media_contribution_original_scale | Optimisation objective variable |
budget_distribution_over_period | None | Time weights over the optimisation window |
budget_bounds | Derived or default | Explicit spend bounds |
spend_constraint_lower | 0.3 when deriving bounds | Relative lower bound around scaled reference spend |
spend_constraint_upper | 0.3 when deriving bounds | Relative upper bound around scaled reference spend |
default_constraints | true | Whether to add the default equality budget constraint |
noise_level | 0.001 | Noise level for simulated response samples |
include_last_observations | false | Whether posterior predictive sampling includes trailing observed rows |
include_carryover | true | Whether simulated response sampling extends the window for carryover |
Budget spec modes:
budget.mode: absolutebudget.valueis total spend over the full optimisation horizon.budget.mode: relativebudget.valueis a multiplier on the chosen basis.budget.basis: reference_window_totalAMMM3 resolves the budget against the same reference-window total spend it already uses for current-plan comparison and default bound derivation.
Important budget-unit note
The preferred optimization.budget block uses total horizon spend. Stage
70 converts that to the wrapper’s per-period contract internally before calling
PanelBudgetOptimizerWrapper.optimize_budget(...).
The legacy optimization.total_budget field is still supported, but it keeps
the old wrapper-facing per-period spend contract.
See Budget Optimisation.
Xarray-like optimisation values in YAML
For panel bounds or time distributions, use the xarray-like mapping shape that Stage 70 expects:
optimization:
start_date: "2025-02-03"
end_date: "2025-02-24"
budget:
mode: absolute
value: 100000.0
budget_distribution_over_period:
values:
- [[0.25, 0.25], [0.25, 0.25]]
- [[0.25, 0.25], [0.25, 0.25]]
- [[0.25, 0.25], [0.25, 0.25]]
- [[0.25, 0.25], [0.25, 0.25]]
dims: ["date", "geo", "channel"]
coords:
date: [0, 1, 2, 3]
geo: ["UK", "FR"]
channel: ["channel_1", "channel_2"]
The same shape works for budget_bounds, but with an additional "bound"
dimension containing "lower" and "upper".
validation
Use the optional validation block when you want Stage 35 blocked holdout
scoring. This is the runner’s out-of-sample tail check: AMMM3 refits a clean
model on the earlier dates and scores only the final blocked window.
validation:
enabled: true
holdout_observations: 8
include_last_observations: true
coverage_levels: [0.5, 0.8, 0.94]
sampler:
draws: 500
tune: 500
chains: 2
cores: 2
random_seed: 42
Supported keys:
| Key | Meaning |
|---|---|
enabled | Set to false to skip Stage 35 while keeping the stage in the manifest |
holdout_observations | Number of unique dates to reserve for the blocked holdout window |
include_last_observations | Keep lag history for carryover-sensitive holdout scoring |
coverage_levels | Coverage levels reported in Stage 35; use the fixed 50, 80, and 94 percent defaults |
sampler | Optional validation-only sampler overrides for the train-window refit |
Stage 35 reports coverage as coverage_50, coverage_80, and
coverage_94. Keep those defaults unless the implementation and tests are
updated together.
The validation stage builds a clean train-window model for holdout scoring and
ignores inference_data.path so the refit does not inherit attached posterior
state from the full-sample model.
For a full explanation of why the split is blocked, how to read crps and
coverage, and rules of thumb for weekly MMM, see
Blocked Holdout Validation.