X_train and keeps a per-layer key/value cache over those rows. That cache —
not the model itself — is what fills a GPU on a big table. Nori handles it by
walking a ladder of fallbacks, keeping the cache at full precision while it fits
and stepping down only when it must. memory_policy lets you decide which steps
it may take, and tells you afterwards which one it used.
memory_policy governs how the cache holds your context. Above a row-count
threshold, large_context_policy governs which context rows a call actually
uses — routing across one or more Nori calls instead of
trimming randomly or paying the VRAM cost of the whole table. See
context routing below.
The same fields work locally and over the hosted API.
synthefy-nori 0.13.0 or newer; see
Installation.
Quickstart
Omitmemory_policy entirely and nothing changes — the defaults are what
almost every call should use. They are: cache at full precision (bf16), let it
drop to int8 only if that is what keeps it on the GPU, spend at most 40% of
VRAM on it, offload to host RAM rather than give up, and shrink the context only
as a last resort. In our tests, changing chunking or batching introduced only
small rounding differences, though predictions were not always bit-for-bit
identical.
Reach for a policy when you want a different trade. A preset covers the common
three:
Which lever saves the most memory
Ranked by how much GPU memory each one frees, most first. Figures are from a 400-row × 8-feature context, whose full-precision cache is 0.0122 GiB — yours scales with rows and features, but the ratios hold.
Note that int8 is ~1.9× and not 4×: the saving is against
bf16, not fp32,
and the per-row scales cost a little back.
Row chunking
Usecontext_row_chunk when a call dies building the cache rather than holding
it — the projection over all N rows at once is the spike, and this processes N a
slice at a time. It is the lever for “it OOMs on fit”, where a smaller budget
would not help.
Capping the budget on a shared GPU
Budgets are fractions of your hardware by default, so one setting travels between cards. Use the absolute form when a hard ceiling is the actual requirement, such as a GPU you share with another process:Refusing a shortened context
Shrinking the context is the last resort on the ladder: Nori reaches for it only when every other fallback still leaves the request too large, and it never fails outright if there is any way to serve it — see Quickstart. Make that an error instead when a silently shortened context would invalidate your results:allow_subsample=False raises before any prediction runs, rather than
returning one computed on fewer rows than you asked for. Either way, check
memory_report_["dropped_context_rows"].
How it works
Onepredict reads the context once and saves a key/value vector per layer, per
feature group, per context row. Query rows then attend to that cache instead of
re-reading the table. The cache is what grows with your data:
no_cache. That is normal, not a degradation.
When the cache does not fit, Nori takes the cheapest step that works:
Only the int8 rungs quantize the cache. Ordinary BF16 offloading moves bytes
unchanged: its reference is the same resident cached computation with the same
context, query chunks, projection chunks, ensemble batching, model, and
numerical backend. The policy can change batching eligibility, so selecting
offload_bf16 alone does not guarantee identical end-to-end predictions.
Changing chunk sizes, using streaming, or switching between cached and uncached
execution can change floating-point rounding even without quantization.
Subsampling changes the context itself.
The exact preset disables cache quantization. It does not guarantee identical
predictions across execution paths or prevent subsampling. Use
allow_subsample=False separately when every context row must be retained.
Reading the report
memory_report_ locally, last_memory_report on the client, memory_report in
the raw response. It carries the resolved policy plus what was decided:
The last two are added by the server when it echoes the report, so they are
present over the API and absent from
memory_report_ locally.
dropped_context_rows is the one number worth watching: it is the only accuracy
loss here that is not a rounding-level effect. Set allow_subsample=False to
make that case an error instead.
Reaching the cached path over the API
Coming soon. The cache is built only when your query set spans more than
one batch, and today that threshold is more query rows than a single hosted
request can carry — so a hosted call reports
no_cache however much data you
send. We are raising the hosted request limit; once it lifts, a normal-sized
request reaches the cached path on its own, with nothing extra to set.Choosing context rows above a threshold
memory_policy decides how the cache holds your context; large_context_policy
decides which rows go into it once X_train exceeds
large_context_threshold (50,000 rows by default). Above that threshold, a
policy routes the request across one or more Nori calls instead
of the cache silently trimming a random subset to fit.
Off by default — large_context_policy=None keeps behavior byte-for-byte
identical to today. The same built-in policy specs work in local, hosted, and
SageMaker modes:
cluster_route — recommended
Clusters the query rows into groups (8 by default) and gives each group its own
local context pool, one Nori call per group. It is the only policy with full
coverage across a broad benchmark sweep — best on nearly half the tables
tested, and it never regressed below a single shared window.
Choosing between them
Here are some commonly used built-in policies:
Hosted and SageMaker support built-ins from the installed Nori version. The
complete current list and configuration options live in
src/synthefy_nori/inference/policies.py in the
Synthefy Nori repository. Custom
Python policies are local-only.
Reading the report
large_context_report_ locally, last_large_context_report on the client,
large_context_report in the raw response — present whenever a policy was
requested, even below the threshold, so a deployment silently ignoring the
field is distinguishable from an ordinary small-table request.
Configuration
Presets
Presets
Precision
Precision
Budgets
Budgets
Budgets are fractions of your hardware, so one setting travels from a laptop GPU
to an H200. The
*_absolute_gb overrides exist for a shared GPU, where a hard
ceiling is the requirement rather than a share.Over the hosted API the host-RAM budgets are capped to what the container
survives, and a cap is reported in
clamped rather than applied silently.Chunking and context
Chunking and context
large_context_policy
large_context_policy
large_context_cache_entries (NoriRegressor only, default 1) keeps more
than one policy’s context cache resident between calls on the same estimator.
It is not part of the shared client/hosted contract: hosted requests are
one-shot, so there is nothing to retain between them.Good to know
Incoherent settings fail loudly. Asking for a cache-only field alongside
cache=False is rejected rather than ignored, because a policy spelled
correctly that silently does nothing is worse than an error. Settings that work
but probably are not what you meant are honoured and explained in notes.The report is not a policy. Feeding a
memory_report back in as
memory_policy is rejected: those are decided outputs, and reusing them as
configuration would skip the coherence checks.Not on Thinking models. A Nori Thinking deployment
rejects both
memory_policy and large_context_policy with a 400. It
predicts through a test-time-compute wrapper with no separate fit/predict
step for a policy to attach to, and manages its own inference memory — so a
policy passed in from outside would not reach the run that produces the
answer, and accepting it silently would be worse than refusing it.Where a cache cannot help. Preprocessing (polynomial features and the
adaptive SVD) runs before any of this and has its own memory cost, which
memory_policy does not govern. A table that fails there fails regardless of
the policy.large_context_policy is point-output only. output_type="mean" and
"median" are supported; "quantiles" and "full" fail before inference,
because a routed policy combines point predictions from several Nori calls and
has no single combined predictive distribution.Hosted requests fail closed on a stale deployment. The response always
carries
large_context_report when a policy was requested, even below the
threshold. If a deployment omits it or reports a different policy, threshold,
or seed, the client raises rather than silently returning an ordinary,
unrouted prediction that looks valid.One-shot everywhere. Every call — local, hosted, or SageMaker — supplies
and fits
X_train again; there is no hidden upload-once/query-many cache
across requests. reused_train_state in the report reflects reuse within
one client-owned NoriRegressor instance in local mode only, and is always
false over the hosted API.Next steps
Hosted client
Auth, modes, and the request contract for calling Nori over the API.
Missing values
Pass NaNs straight through — what the model does with them.