workload__inference
@vivekkhandelwal1 is already working on this.
Since Jun 17, 2026.
- Dominant language
- Python
- Stars
- 11
- Forks
- 7
- Avg merge
- 1d 17h
- Merged PRs (30d)
- 31
Description
Task — In-tree inference Workload
Goal
Add one public, in-tree workload named inference that runs eval-only model execution. The recipe chooses the inference mode:
workload: inference
workload_config:
mode: offline_batch # offline_batch|continuous_batch
This workload should exercise inference behavior without backward or optimizer steps. It measures latency/throughput, checks outputs for NaN/inf, and returns a normal WorkloadResult.
After this task:
aorta run --workload inference --steps Nruns a public synthetic inference loop.- Recipes can choose model topology and serving mode.
- One-node smoke works on CPU or GPU.
- Optional single-node multi-rank smoke can run if
distributed: trueis set in the recipe.
Why Separate From training
Inference has a different failure and performance surface:
- no backward pass
- no optimizer
- eval mode
- prefill/decode latency
- KV cache behavior
- batching behavior
- output/logit stability
Keep training and inference separate workloads so recipes, metrics, and acceptance criteria stay clear.
Recipe vs Sidecar Decision
Use recipes for inference shape:
- inference mode
- model topology
- batch size
- prompt length
- generated token count
- dtype
- KV cache on/off
- deterministic/checksum settings
Use sidecars only for ad-hoc registries: extra mitigations, environments, or temporary local definitions. Do not use sidecars to choose inference mode or model topology.
Files to create / modify
Follow the existing flat-module convention: every in-tree public workload
(workloads/race.py, workloads/llm_determinism.py, workloads/_subprocess.py)
is a single module, not a subpackage. llm_determinism.py already bundles
its config dataclass, helper classes, and the workload in one file — mirror that.
Do not introduce a workloads/inference/ subpackage.
src/aorta/workloads/inference.py # NEW — InferenceWorkload(Workload)
# + typed config dataclass(es)
# + prefill/decode/batching helpers
recipes/example-inference-smoke.yaml # NEW — offline batch smoke recipe
recipes/example-inference-continuous-smoke.yaml # NEW — continuous batching smoke recipe
tests/workloads/test_inference.py # NEW — config, lifecycle, result schema
Reuse existing infra — do not write new model builders:
aorta.models.repeated_block(RepeatedBlockModel+BlockConfig) already
provides the dense-transformer and MoE (num_experts > 1→ top-1 router)
topologies. Use it fordecoder_transformer/encoder_transformer.aorta.data.synthetic_dataset(SyntheticDatasetConfig,create_dataloader)
provides public synthetic inputs.- The
mlpsmoke topology is the only thing that may need a small local builder
ifrepeated_blockis too heavy for the smallest lifecycle smoke.
Modify pyproject.toml:
[project.entry-points."aorta.workloads"]
inference = "aorta.workloads.inference:InferenceWorkload"
Contract details
- Base contract: import
WorkloadandWorkloadResultfromaorta.workloads. - Name declaration: set
name: ClassVar[str] = "inference"to match the existing convention (RaceWorkload.name,LlmDeterminismWorkload.name). - Launch declaration: default to
launch_mode = "single_process"andmin_world_size = 1. - Optional distributed smoke: support a recipe flag like
distributed: truelater if multi-rank inference is needed. Do not make distributed launch mandatory for the first public inference workload. - Device behavior: use CUDA/ROCm when available. CPU is acceptable for lifecycle/unit smoke, but result metrics must report the actual device.
--stepsflow:--steps Sfromaorta runarrives asself.config["steps"]and overrides recipe/default request batches or decode iterations.- Rank/output behavior: single-process writes through dispatcher as usual. If distributed inference is added later, rank-0-only JSON remains the dispatcher contract.
Recipe shape
schema_version: 1
ticket: EXAMPLE-INFERENCE-SMOKE
workload: inference
trials: 1
steps: 4
workload_config:
mode: offline_batch # offline_batch|continuous_batch
seed: 1234
device: auto # auto|cuda|cpu
dtype: bfloat16 # bfloat16|float16|float32
request:
batch_size: 4
prompt_len: 128
generate_tokens: 32
model:
kind: decoder_transformer # mlp|encoder_transformer|decoder_transformer
hidden_size: 512
num_layers: 4
num_heads: 8
ffn_size: 2048
vocab_size: 32000
serving:
kv_cache: true # simulated only — RepeatedBlockModel has no real paged KV cache;
# the workload re-uses past hidden states via tensor slicing to
# exercise the prefill/decode timing split, not paged attention.
continuous_batch:
enabled: false
max_active_requests: 8
arrival_pattern: fixed
checks:
fail_on_nan_logits: true
fail_on_nonfinite_output: true
compare_logits_checksum: true
cells:
- name: baseline-local
mitigations: [none]
environment: local
Implementation guidance
Use typed config dataclasses for structured config. Avoid loose dict plumbing beyond the Workload(config) boundary.
Build topologies from existing in-tree models (aorta.models.repeated_block) and synthetic inputs (aorta.data.synthetic_dataset) — do not author fresh model code:
mlp: smallest lifecycle smoke (small local builder acceptable ifrepeated_blockis too heavy).encoder_transformer: fixed tensor input, useful for embedding/classification-style inference. Map ontoRepeatedBlockModel.decoder_transformer: synthetic token prompts, prefill + decode loop, optional KV cache. Map ontoRepeatedBlockModel.
Note: repeated_block's MoE path is top-1 only (num_experts > 1 selects a top-1 router; there is no top_k knob). If a recipe needs MoE inference, drive it via num_experts and do not expose top_k.
Inference loop should:
- set deterministic seed
- build synthetic token or tensor inputs
- put model in
eval()mode - run with
torch.no_grad()ortorch.inference_mode() - run warmup iterations outside measured timings
- measure prefill latency where applicable
- measure decode latency where applicable
- compute throughput metrics
- check logits/outputs for NaN/inf
- optionally compute stable checksums for drift detection
- return
WorkloadResult
KV cache note: RepeatedBlockModel has no real paged attention or KV cache. When kv_cache: true, the workload simulates the prefill/decode split by running a full forward pass for prefill then re-running with a shorter input for decode (tensor slicing). This is enough to produce separate prefill and decode latency measurements without implementing real KV caching.
Keep serving modes small:
offline_batch: fixed batch and fixed token count. This is the required MVP.continuous_batch: simple simulated arrivals and active-request scheduling. Keep it deterministic and public-safe.
Do not pull real customer prompts, tokenizers, or model weights into public AORTA.
Acceptance criteria
-
inferenceentry point exists inpyproject.toml. -
InferenceWorkload(Workload)implementssetup(),run(), andcleanup(). -
InferenceWorkloaddeclaresname = "inference",launch_mode = "single_process", andmin_world_size = 1. - Workload lives in a single flat module
src/aorta/workloads/inference.py(no subpackage). - Model topologies reuse
aorta.models.repeated_block/aorta.data.synthetic_datasetrather than new model code. - Recipe config supports
mode: offline_batch;continuous_batchcan be included if scoped small. - Recipe config supports at least
model.kind: mlp|decoder_transformer. - Bare smoke works:
aorta run --workload inference --trials 1 --steps 2. - Recipe smoke works:
aorta triage run --recipe recipes/example-inference-smoke.yaml --dry-run. -
run()returnsWorkloadResultwithpassed,failure_count,failure_details,step_times_ms,total_iterations,elapsed_sec,main_work_started,executed_iterations, andconfigured_iterations. - Metrics include
mode,device,dtype,model_kind,parameter_count,batch_size,prompt_len,generate_tokens,prefill_latency_ms,decode_latency_ms,tokens_per_sec,step_time_p50, andstep_time_p99where applicable. - Numeric checks fail on NaN/inf logits or non-finite outputs.
- Tests cover config parsing, model construction, offline batch run, optional continuous batch scheduling, and WorkloadResult schema.
Out of scope
- Customer/NDA prompts, model weights, traces, or tokenizers.
- Real production serving stack integration.
- Tensor parallelism, pipeline parallelism, or distributed inference.
- RAG with real indexes or private corpora.
- Speculative decoding with real draft/verifier model pairs.
- Throughput tuning.
search_space()/objective()methods.
How to test
# Unit tests:
python -m pytest tests/workloads/test_inference.py -v
# One-process smoke:
aorta run --workload inference --trials 1 --steps 2
# Recipe dry run:
aorta triage run --recipe recipes/example-inference-smoke.yaml --dry-run
# Recipe smoke:
aorta triage run --recipe recipes/example-inference-smoke.yaml
# Result shape:
python -m json.tool results/inference/trial_d0_m0_t0.json
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.