AIM Models#
AIMModel and AIMClusterModel are the entry point for getting a model onto the cluster. Each resource describes one model and produces a set of AIMProfile resources that AIMService can deploy.
v1alpha2
This page documents the aim.eai.amd.com/v1alpha2 API. For the v1alpha1 AIMModel shape (with spec.custom, spec.modelSources, spec.discovery, etc.) see Legacy AIMModel.
Four flows#
Every v1alpha2 AIMModel uses one of four flows. The flow is determined by which field you populate on the spec:
Flow |
When to use |
Spec shape |
Source of profiles |
|
|---|---|---|---|---|
Official |
Deploying a published AMD-supported AIM model unmodified |
|
The AIM container image itself (discovery) |
|
Generated |
Deploying model weights with a generic runtime configured for cluster hardware |
|
RuntimeConfig |
|
Fine-tuned |
Deploying a fine-tune of a published architecture |
|
A previously-applied official AIMModel |
|
Custom |
Deploying a model whose architecture isn’t in the catalog |
|
A previously-applied base-image AIMModel |
|
The onboarding contract is enforced by CRD validation: exactly one of spec.image, spec.modelId, or spec.profiles must be set. Mixing them — or setting none — is rejected at admission.
The flow you used is surfaced as status.kind and shown as the KIND column in kubectl get aimmodel. Note that base-image AIMModels classify as Image (they’re a sub-case of the Official flow with a generic image, not a fourth flow). To filter for base-image models specifically, combine status.kind=Image with status.managedProfiles.base > 0 — see Base-image models below.
End-to-end guides for the two derivation flows:
Cluster vs namespace scope#
Resource |
Scope |
Typical owner |
Produces |
|---|---|---|---|
|
Namespace |
Application / ML team |
|
|
Cluster |
Platform team |
|
When an AIMService references a model by name, AIM Engine looks for a namespace-scoped AIMModel first, then falls back to a cluster-scoped AIMClusterModel with the same name. This lets teams override a cluster default without affecting other namespaces.
The two kinds share the same spec and status shape — every spec example below applies to both unless noted.
Flow 1 — Official AIM model#
Use this when AMD publishes an AIM image for the exact model you want to deploy.
apiVersion: aim.eai.amd.com/v1alpha2
kind: AIMModel
metadata:
name: llama-3-8b-official
namespace: ml-team
spec:
image: quay.io/amd/aim-llama-3-8b-instruct:0.9.0
imagePullSecrets:
- name: registry-creds
serviceAccountName: aim-runtime
The controller:
Runs an in-cluster discovery Job that inspects the image’s profile YAMLs (
/workspace/aim-runtime/profiles/<aim_id>/*.yaml) and writes a normalised catalog into aConfigMap(status.discoveryCacheRef).Evaluates each discovered profile against the cluster’s nodes — GPU model, accelerator count, resource capacity.
Materialises one
AIMProfileper supported entry. Unsupported entries (no matching nodes) are counted instatus.discoveredProfiles.unsupportedbut not materialised.Watches node events and re-evaluates the catalog when nodes are added or removed.
The resulting profiles are deployable (carry aimId and modelSources) and labelled aim.eai.amd.com/profile-role=deployable, aim.eai.amd.com/profile-origin=discovered.
Status signal#
kubectl get aimmodel llama-3-8b-official -o jsonpath='{.status}' | jq
{
"status": "Ready",
"aimId": "meta-llama/Llama-3-8B-Instruct",
"baseImage": "ghcr.io/silogen/aim-base:0.11",
"discoveryCacheRef": { "name": "llama-3-8b-official-discovery-5e8ad928" },
"discoveredProfiles": { "total": 7, "supported": 5, "unsupported": 2 },
"managedProfiles": { "total": 5, "ready": 5, "deployable": 5, "base": 0, "notAvailable": 0 }
}
Flow 2 — Generated runtime profile#
Use this when model weights are identified by a model ID and the platform has configured a generic runtime for the available hardware:
apiVersion: aim.eai.amd.com/v1alpha2
kind: AIMModel
metadata:
name: qwen3-5-0-8b
namespace: ml-team
spec:
modelId: Qwen/Qwen3.5-0.8B
The controller defaults aimId to modelId and the source URI to
hf://<modelId>. Both may be overridden for fine-tuned or S3-hosted weights:
spec:
modelId: acme/qwen-finetune
aimId: Qwen/Qwen3.5-0.8B
source:
uri: s3://customer-models/qwen-finetune
The hardware shape is declared per-model. spec.accelerator sets how many
devices the model needs and optionally narrows which fallback serves it:
spec:
modelId: Qwen/Qwen3.5-0.8B
accelerator:
count: 4 # default 1; also becomes the tensor-parallel size
vendor: nvidia # optional
model: H100 # optional
Generated profiles are created only when a matching RuntimeConfig fallback and
hardware are available. They are labelled profile-origin=generated. Existing
profiles are retained and become unavailable if the matching nodes temporarily
disappear.
Generated profile selection is platform policy
Generated profiles default to type: unoptimized — a generic runtime template
is not tuned for any particular model. That is below the AIMService
selection floor. RuntimeConfig fallbacks default to
autoSelectionPolicy: optimized, which keeps that floor in force. A platform
may set autoSelectionPolicy: any to admit the generated profile only when no
optimized profile matches and the service did not explicitly set
minimumType. The chart-provided NVIDIA fallback uses this policy for
out-of-the-box model-ID onboarding. See
Optimization tier and auto-selection policy.
Resolution strategy#
spec.modelId is one flow with room for more than one resolution mechanism.
status.profileGeneration.strategy reports which one ran, and
status.profileGeneration.matchedFallbacks lists the fallbacks that produced a
profile:
status:
kind: Generated
profileGeneration:
strategy: RuntimeFallback
matchedFallbacks: [nvidia-vllm]
RuntimeFallback is the only strategy today: this flow does not yet perform
an AMD catalog lookup, and AMD catalog onboarding remains the image-backed
Official flow. When catalog lookup lands it will be tried first, with
RuntimeConfig fallbacks second, and will report its own strategy value —
status.kind stays Generated either way, so a model’s classification does not
change under it.
Flow 3 — Fine-tuned model#
Use this when you have your own fine-tune of a model whose architecture is in the catalog. The official AIMModel’s profiles already carry the tuned engine arguments and accelerator pairings — you reuse them and override only the model sources.
apiVersion: aim.eai.amd.com/v1alpha2
kind: AIMModel
metadata:
name: llama-3-8b-finetune-acme
namespace: ml-team
spec:
profiles:
derivedFrom:
selector:
aimId: meta-llama/Llama-3-8B-Instruct
acceleratorModel: MI300X
versionPolicy: pinned
version: "0.9.0"
overrides:
modelSources:
- modelId: acme/llama-3-8b-finetune
sourceUri: hf://acme/llama-3-8b-finetune
selector.aimId matches source profiles by their existing spec.aimId. The derived profile inherits aimId from the source and only modelSources and modelId change.
See Fine-Tuned Models for the full walkthrough, version-policy semantics, and override merge rules.
Flow 4 — Custom model#
Use this when your model’s architecture isn’t in the catalog. You apply a base-image AIMModel first to produce base profiles (generic runtime configs with no model identity), then a custom-model AIMModel that overlays your weights and identity on top.
apiVersion: aim.eai.amd.com/v1alpha2
kind: AIMModel
metadata:
name: aim-base-vllm
namespace: ml-team
spec:
image: amdenterpriseai/aim-base:0.11
---
apiVersion: aim.eai.amd.com/v1alpha2
kind: AIMModel
metadata:
name: acme-custom-transformer
namespace: ml-team
spec:
profiles:
derivedFrom:
selector:
role: base
modelRef:
name: aim-base-vllm
scope: Namespace
versionPolicy: all
overrides:
aimId: acme/custom-transformer
modelId: acme/custom-transformer
modelSources:
- modelId: acme/custom-transformer
sourceUri: s3://acme-models/custom-transformer
The shape differs from fine-tunes in two ways:
selector.role: basematches only base profiles;selector.modelRef.namepins to a specific base-image AIMModel.Target identity for the derived profile lives on
overrides.{aimId,modelId}(required by CEL whenrole: base— base profiles ship with no identity to inherit).
See Custom Models for the full walkthrough, the identity-stamping semantics, and base-image requirements.
Base-image models#
A base-image AIMModel is just an official-flow AIMModel whose image happens to be a generic AIM base image — one whose profile YAMLs declare runtime/engine/accelerator settings but leave model_id and model_sources empty. The controller materialises those entries as base AIMProfiles:
status.deployable: falseaim.eai.amd.com/profile-role: baseaim.eai.amd.com/profile-origin: discovered
Base profiles cannot back an AIMService directly. They exist as source material for a custom-model derivation (see Flow 4).
A model is a base-image AIMModel when status.managedProfiles.base > 0 and status.managedProfiles.deployable == 0 (with status.kind: Image). The kind is Image rather than its own value because — mechanically — a base image is just a regular image whose profile YAMLs happen to leave the model identity fields blank; the image-discovery flow is the same. The managedProfiles.base > 0 count is what flags the profiles as base-only.
Discovery cache#
For both official and base-image flows, the discovery Job writes its output into a ConfigMap that the controller treats as the normalised catalog. The cache stores:
Parsed profile YAMLs from the image
Normalised metadata in the same shape that real
AIMProfileresources useThe base image extracted from
AIM_BASE_IMAGE_REFwhen available
status.discoveryCacheRef points at this ConfigMap. status.discovery tracks the job lifecycle:
Field |
Description |
|---|---|
|
Number of discovery Job attempts so far |
|
Timestamp of the most recent attempt |
|
Reason the most recent attempt failed (e.g. |
|
Hash of the inputs that invalidate the cache (image, imagePullSecrets, serviceAccountName, discovery command version) |
When specHash changes — for example, you rotate serviceAccountName or upgrade the image tag — the operator drops the cache and re-runs discovery.
Profile-set delegation#
For derivation flows (fine-tuned and custom), the controller synthesises a child AIMProfileSet (or AIMClusterProfileSet) named <model>-profiles-<hash> and lets it produce the derived profiles. The model summarises the profile-set output back onto its own status; see AIM Profile Sets for the mechanics.
status.profileSetRef points at the child resource:
kubectl get aimmodel acme-custom-transformer \
-o jsonpath='{.status.profileSetRef.name}'
# acme-custom-transformer-profiles-2be25a47
Official-flow models do not create a child profile set — status.profileSetRef is empty.
Spec fields#
The unified spec shape used by all four flows:
Field |
Used by |
Description |
|---|---|---|
|
Official, Base |
Source image to inspect for discovery. Mutually exclusive with |
|
Generated |
Canonical model identity used to generate profiles from RuntimeConfig fallbacks. |
|
Generated |
Optional architecture identity override; defaults to |
|
Generated |
Optional source URI and metadata override; URI defaults to |
|
Generated |
Optional hardware request — |
|
Generated |
Optional RuntimeConfig name; defaults to |
|
Fine-tuned, Custom |
Derivation spec — selector, version policy, overrides. Mutually exclusive with |
|
Official, Fine-tuned, Custom |
Secrets used for image inspection and propagated to derived runtime profiles. |
|
Official, Fine-tuned, Custom |
Service account propagated to managed child resources. Generated-flow service accounts belong on the RuntimeConfig fallback. |
The v1alpha2 CRD explicitly forbids legacy fields such as spec.modelSources,
spec.custom, spec.customTemplates, and spec.profileCopy. spec.aimId,
spec.source, and spec.runtimeConfigName are valid for the generated flow.
Status fields#
Field |
Description |
|---|---|
|
Overall status ( |
|
Detailed reconciliation conditions (see Conditions Reference) |
|
Discriminator for the onboarding flow: |
|
|
|
Resolved architecture identifier — populated by discovery for |
|
Extracted |
|
Reference to the normalised discovery cache |
|
Counts: |
|
Discovery Job state: |
|
Reference to the synthesised child profile set (derivation flows only) |
|
Counts: |
The managedProfiles counts always serialise zero values explicitly (no omitempty), so kubectl printcolumns and assertions on .status.managedProfiles.{total,ready,...} are stable.
Resolution and precedence#
When an AIMService references a model by name, AIM Engine resolves it in this order:
Namespace-scoped
AIMModelwith that name.Cluster-scoped
AIMClusterModelwith that name.
Namespace wins. The resolved scope is recorded in the service’s status.resolvedModel.scope.
Troubleshooting#
Discovery fails#
Check operator logs for image-inspection errors:
kubectl -n aim-system logs -l app.kubernetes.io/name=aim-engine --tail=100 \
| grep -i "<model-name>"
Inspect the discovery Job directly:
kubectl -n <namespace> get jobs -l aim.eai.amd.com/model=<model-name>
kubectl -n <namespace> logs job/<discovery-job>
Common causes:
Missing or invalid
imagePullSecretsImage reference not found at the registry
LogParseFailed— the container is not an AIM-compatible imageRegistry authentication or connectivity failures
status.discovery.lastFailureReason captures the most recent reason, and status.conditions[?(@.type=='DiscoveryReady')] carries the human-readable message including the next retry interval.
Model is Ready but no profiles materialised#
status.managedProfiles.total == 0 and status.discoveredProfiles.unsupported > 0 means discovery succeeded but none of the discovered profiles are compatible with the cluster’s hardware. Compare the cluster’s accelerator labels:
kubectl get nodes -o jsonpath='{.items[*].metadata.labels}' \
| tr ',' '\n' | grep aim-accelerator
against the accelerator requirements in the discovery cache ConfigMap. Add matching nodes or, if the discovered profiles are wrong, fix the source image.
Derivation produces no profiles#
status.profileSetRef points at the child AIMProfileSet. Inspect it:
kubectl get aimprofileset $(kubectl get aimmodel <name> \
-o jsonpath='{.status.profileSetRef.name}') -o yaml
DerivationReady=False / NoMatchingProfiles means the selector matched zero source candidates. See the troubleshooting sections in Fine-Tuned Models and Custom Models.