Configuration Alternatives at Runtime#
This section describes how to run the RFD4-Proteina NIM with different settings for
serving your own model checkpoints
deployment limits (request size, token count, step count, search cost)
execution backend and compile tuning
TMol metrics (refer to Oracles for the separate, mount-based refolding oracle)
general service settings and admission control
These instructions assume you have installed and set up Prerequisite Software and pulled the container as described in Getting Started.
Start the NIM#
export NGC_API_KEY=<Your NGC API Key>
export LOCAL_NIM_CACHE=~/.cache/nim
docker run --rm --name rfd4-proteina \
--runtime=nvidia \
--gpus 'device=0' \
-e NGC_API_KEY \
-v $LOCAL_NIM_CACHE:/opt/nim/.cache \
-p 8000:8000 \
--shm-size=16g \
nvcr.io/nim/ipd/rfd4-proteina:1.0.0
Every environment variable that follows is passed the same way, with an
additional -e VARIABLE=value on the docker run command.
Using Your Own Model Checkpoints#
RFD4-Proteina serves from two checkpoints: the latent-diffusion trunk (the
velocity model, sometimes called the “denoiser”) and a partial autoencoder
(encoder and decoder). Both are resolved from the manifest workspace at
NIM_WORKSPACE_PATH (default /opt/nim/workspace) unless named explicitly.
Serve your own weights (typically a fine-tune of the shipped architecture)
by mounting them into the container and naming them with two environment
variables:
Variable |
Default |
Purpose |
|---|---|---|
|
unset, resolved from the workspace |
Full path to the latent-diffusion checkpoint (the velocity trunk). |
|
unset, resolved from the workspace |
Full path to the partial-autoencoder checkpoint (encoder and decoder). |
Left unset, each is resolved by looking in NIM_WORKSPACE_PATH for the one
*.ckpt file that matches: autoencoder checkpoints are the ones whose name
contains _ae_, and the denoiser is whichever workspace checkpoint is not. That
only works when the workspace holds exactly one candidate of each kind, which
is true for the shipped image; set the variable explicitly whenever you mount
a different checkpoint, whether alongside the shipped one or in its place.
export NGC_API_KEY=<Your NGC API Key>
export LOCAL_NIM_CACHE=~/.cache/nim
export MY_CHECKPOINT_DIR=/data/rfd4-proteina-finetuned
docker run --rm --name rfd4-proteina \
--runtime=nvidia \
--gpus 'device=0' \
-e NGC_API_KEY \
-e NIM_DENOISER_CKPT=/checkpoints/my-finetuned-denoiser.ckpt \
-e NIM_AUTOENCODER_CKPT=/checkpoints/my-finetuned_ae_.ckpt \
-v $MY_CHECKPOINT_DIR:/checkpoints:ro \
-v $LOCAL_NIM_CACHE:/opt/nim/.cache \
-p 8000:8000 \
--shm-size=16g \
nvcr.io/nim/ipd/rfd4-proteina:1.0.0
Confirm which checkpoints were loaded from the startup log:
loaded RFProteina in 42.1s (denoiser=my-finetuned-denoiser.ckpt, autoencoder=my-finetuned_ae_.ckpt, device=cuda:0, execution=..., buckets=...)
What Is and Is Not Checked#
A checkpoint you name must exist. Setting NIM_DENOISER_CKPT or
NIM_AUTOENCODER_CKPT to a path that is not a file fails the NIM at startup
rather than falling back to whatever the workspace would have resolved on its
own:
FileNotFoundError: NIM_DENOISER_CKPT='/checkpoints/my-finetuned-denoiser.ckpt' names a
denoiser checkpoint that is not a file. The NIM will not fall back to the one
in /opt/nim/workspace: that would serve different weights than you asked for.
Check the path and that the volume is mounted, or unset NIM_DENOISER_CKPT to
use the shipped checkpoint.
This is deliberate. Quietly serving the shipped checkpoint instead would look identical from the outside: the server starts, designs come back, metrics look ordinary. A fine-tune-and-re-serve workflow would then measure the model it was trying to replace. Leave both variables unset to use the shipped checkpoints.
The architecture is not checked up front. Each checkpoint is loaded with
strict=True, so the model is rebuilt from that checkpoint’s own saved
hyperparameters: any missing or unexpected weight key means the code has
drifted from whatever produced the checkpoint, and it is reported as a
PyTorch state-dict error at startup rather than a message from the NIM. This
also means a checkpoint trained with a materially different architecture (for
example, with the MSA module enabled, or a differently sized autoencoder)
fails loudly rather than loading partially initialized.
The Baker Laboratory’s public 2026_10_15_* checkpoints are one such case.
They widen the autoencoder’s residue vocabulary from 33 to 147 classes and
its latent from 16 to 32 dimensions. As a result, they cannot be served
through NIM_DENOISER_CKPT and NIM_AUTOENCODER_CKPT on this release.
No conversion is performed. Supply PyTorch .ckpt files in the same
format the NIM ships: either a raw training checkpoint (the EMA weights are
picked up automatically from the paired SimpleEMA state) or one already
named *-ema.ckpt. The NIM does not train or fine-tune; produce the weights
with your own training code and serve them here.
Note
Accuracy and performance figures published for the RFD4-Proteina NIM describe the shipped checkpoints. Designs from your own weights are yours to validate.
Deployment Limits#
These bound what a request can ask for, independent of the wide, static bounds enforced by the request schema itself: the schema stays wide so one client can talk to deployments of different capacity, and what a particular deployment accepts is a property of its GPU and its SLA.
Variable |
Default |
Purpose |
|---|---|---|
|
|
Ceiling on |
|
|
Ceiling on trunk evaluations across one trajectory. Runtime scales with trunk passes rather than steps, and a custom |
|
|
Ceiling on tokens in one design. Enforced after the input is parsed, since token count depends on the parsed structure. |
|
|
Ceiling on the whole request body, enforced before the body is read. |
|
|
Ceiling on trajectories a search can roll out for scoring across one request ( |
Every response reports the limits actually in force for that deployment in
runtime.limits, so a client does not need to know these variable names to
discover them.
Note
There is deliberately no ceiling on sampling.num_replicates. Replicates are
batched into one forward pass by default, so what a request can ask for is a
property of the GPU and the token count rather than a fixed number: a cap of
16 would refuse at 128 tokens a request the card would have served, and admit
at 1024 tokens one it cannot. The real detection is the out_of_memory (HTTP
413) answer, which names sampling.batch_size and sampling.num_replicates
as what the caller can change. Refer to Replicates and
Batching.
A request that exceeds one of these limits, or whose input turns out to
require more GPU memory than is available, is answered with the appropriate
error code (request_too_large or out_of_memory); refer to the
API Reference for the full error-code table.
Execution Backend and Compile Tuning#
Variable |
Default |
Purpose |
|---|---|---|
|
|
Selects the execution backend: |
|
unset |
Token-length buckets to reserve |
Important
When switching a deployment from oss_torch_compile to bioir, make sure
NIM_COMPILE_LENGTHS is fully unset rather than set to an empty value: an
empty-but-set value is treated as an explicit (invalid) configuration rather
than “not configured.”
Oracle and TMol Metrics#
The refolding oracle folds each design with an independent structure
predictor and scores it against eleven in-silico pass criteria
({criterion}.pass rows in the response’s aggregated_metrics). This NIM
ships with no refolding oracle built in: every image carries an inert
reward.py that declares none, and enabling one is a matter of mounting a
replacement. Refer to Oracles for the full
mount contract, the NIM_ORACLE_PLUGIN/NIM_ALLOW_ORACLE_PLUGIN variables,
and working reference implementations against hosted structure-prediction
NIMs.
Variable |
Default |
Purpose |
|---|---|---|
|
|
Enables TMol-based interface-energy metrics and reward keys. Independent of the refolding oracle; set |
A request tagging metrics or pass criteria that the mounted oracle does not
publish is rejected at request time with a clear error, rather than allowed
to run and silently score -inf mid-search. Refer to /v1/tasks and the
API Reference for which metric tags a running
deployment currently supports.
General Service Settings#
Variable |
Default |
Purpose |
|---|---|---|
|
the image’s |
Overrides the version string reported in |
|
|
Service log level. |
|
all visible |
Comma-separated GPU indices for the service’s worker pool to use. |
|
|
Set to |
|
|
Working directory the pipeline uses for scratch files. |
|
|
Seconds to wait for each GPU worker process to load the model before startup fails. |
|
|
Requests allowed to wait beyond the ones already running, before this NIM’s own gate answers |
NIM Telemetry#
NIM Telemetry collects minimal host and NIM information to help improve performance, reliability, and compatibility across deployments. It is disabled by default and, when enabled, stays disabled on RTX GPUs unless explicitly opted in.
Variable |
Default |
Purpose |
|---|---|---|
|
|
|
|
|
Set to |
|
|
Enables logging for telemetry operations. Only relevant when |
On an RTX GPU with telemetry requested but not opted in, the startup log reports it explicitly:
RTX GPU detected: NVIDIA RTX PRO 6000 Blackwell Workstation Edition
Telemetry collection disabled
Refer to NIM Telemetry Settings for what is collected, retention, and advanced options, and to NVIDIA’s Privacy Policy.
Admission Control#
By default, every request waits its turn for a free GPU, bounded only by
NIM_MAX_QUEUED_REQUESTS (10): beyond that, a request is rejected on
arrival with 503 rather than joining a queue it is unlikely to clear. In a
saturated deployment, nothing outside the process can see how deep that queue
is, so a client cannot distinguish a slow design from one that has not
started.
Setting NIM_ENABLE_QUEUE_METRICS to true hands queueing to nimlib’s own
admission-control middleware (nimlib >= 0.22.0) instead. It bounds
concurrency at NIM_MAX_CONCURRENT_REQUESTS, sheds requests with 503 and a
Retry-After header after NIM_QUEUE_TIMEOUT_SECONDS elapses or
NIM_MAX_QUEUE_DEPTH is exceeded, and publishes queue-depth metrics on
/v1/metrics. This NIM’s own queue gate (NIM_MAX_QUEUED_REQUESTS,
described earlier) stands down the moment admission control is enabled, so a
request is never waiting in two places that disagree about how many are
ahead of it.
Variable |
Default |
Purpose |
|---|---|---|
|
|
Set to |
|
unset |
Number of requests served at the same time. This NIM runs one request per GPU, so set it to the number of GPUs the container can use (the size of |
|
unbounded |
Number of requests allowed to wait for a free GPU under admission control. Beyond this number, a request is rejected on arrival with |
|
|
How long a request waits for a free GPU before it is rejected with |
|
|
Value sent in the |
Important
Unlike some other bioNeMo NIMs, RFD4-Proteina does not accept
NIM_GPU_ACQUIRE_TIMEOUT_SECONDS. This NIM’s GPU worker pool waits
indefinitely for a free GPU after a request holds an admission-control permit,
rather than enforcing a second, shorter timeout of its own: a timed-out wait
would not stop the design in progress, since the worker keeps the GPU and
finishes anyway while the caller has already been told it failed.
export NGC_API_KEY=<Your NGC API Key>
export LOCAL_NIM_CACHE=~/.cache/nim
docker run --rm --name rfd4-proteina \
--runtime=nvidia \
--gpus '"device=0,1"' \
-e NGC_API_KEY \
-e NIM_ENABLE_QUEUE_METRICS=true \
-e NIM_MAX_CONCURRENT_REQUESTS=2 \
-e NIM_MAX_QUEUE_DEPTH=8 \
-e NIM_QUEUE_TIMEOUT_SECONDS=600 \
-e NIM_QUEUE_RETRY_AFTER_SECONDS=60 \
-v $LOCAL_NIM_CACHE:/opt/nim/.cache \
-p 8000:8000 \
--shm-size=16g \
nvcr.io/nim/ipd/rfd4-proteina:1.0.0
The following table describes requirements admission control cannot infer for you.
Requirement |
Reason |
|---|---|
|
Concurrency is enforced by the worker pool, one request per GPU, regardless of this setting. A larger value only moves the surplus queue to where nimlib’s metrics cannot see it ( |
Health and documentation endpoints bypass admission control. |
A saturated NIM continues to answer |
While admission control is enabled, the following Prometheus series are
published on /v1/metrics:
Metric |
Description |
|---|---|
|
Number of requests waiting for a GPU. |
|
Number of requests running on a GPU. |
|
Histogram of time spent waiting for a GPU. |
|
Requests rejected with |
Note
Admission control is disabled unless NIM_ENABLE_QUEUE_METRICS is set. When
it is unset, this NIM’s own queue gate (NIM_MAX_QUEUED_REQUESTS) governs
request handling exactly as described in
Behavior Under Load, and none of the preceding queue
metric series are registered.
Behavior Under Load#
A request arriving with every GPU worker busy and the queue full is answered
with HTTP 503 (service_busy), not 429: the NIM is not rate-limiting a
particular caller, it has no free capacity, so the caller should retry
elsewhere. Which queue governs this, this NIM’s own
(NIM_MAX_QUEUED_REQUESTS) or nimlib’s admission control
(NIM_MAX_QUEUE_DEPTH), depends on whether NIM_ENABLE_QUEUE_METRICS is set;
refer to Admission Control.
A request whose GPU memory is exhausted is answered with HTTP 413
(out_of_memory), a 4xx status: the same job on the same GPU will exhaust it
again, so retrying unchanged will not help. Memory grows with the batch size,
with the square of the token count, and with search width, so what can change
is sampling.batch_size (1 serves the replicates one at a time), the input
size, or the search width. The error names the batch size and token count it
failed at. Because batch_size defaults to num_replicates, a request that
raised its replicate count without setting a batch size raised its peak
memory with it; refer to Replicates and
Batching.
A client that disconnects before its response is ready is recorded as
HTTP 499 (client_gone) rather than a server error: since nobody
receives that status by definition, it exists only so the drop is not
counted against the NIM’s error rate. This matters more for RFD4-Proteina
than for a single forward pass: an abandoned beam search can hold a GPU for
minutes producing a response that nothing will read.