Démarrage rapide Docker
Exécute le SDK sans installer Python ni PyTorch sur ton hôte. Pour le démarrage rapide CPU, prévois 8 GB de RAM et 10 GB d’espace disque libre, avec Docker Engine ou Docker Desktop et Compose v2 ou plus récent.
Depuis la racine du dépôt :
docker compose run --build --rm laya
Cela compile le checkout, exécute la requête d’exemple
sur CPU et imprime du JSON couvrant choice, score et noul. La première requête télécharge le
checkpoint public Hugging Face sélectionné ; aucun compte n’est nécessaire. Prévois plusieurs minutes
pour son premier téléchargement.
Les poids restent dans un volume nommé. Les exécutions suivantes utilisent
docker compose run --rm laya.
Les prédictions et la confiance demandent encore une évaluation sur ta charge de travail. Voir les limites de benchmark.
Pour les hôtes ARM64, le DGX Spark et Apple Silicon, voir Conteneurs ARM64 et DGX Spark.
NVIDIA GPU / CUDA
Installe un pilote NVIDIA compatible et configure Docker avec le NVIDIA Container Toolkit. L’image GPU utilise les roues PyTorch CUDA 12.8. Vérifie la capacité de calcul et le pilote de ton GPU par rapport aux builds pris en charge par PyTorch ; les cartes plus anciennes peuvent exiger un build différent. Prévois de l’espace disque supplémentaire pour les couches CUDA. Les besoins en VRAM dépendent du checkpoint, de la taille de lot et de la longueur d’entrée.
docker compose -f compose.yaml -f compose.cuda.yaml run --build --rm laya
L’override sélectionne le GPU 0 et vaut LAYA_DEVICE=cuda par défaut. Définis LAYA_GPU_ID sur un
autre index d’hôte ou UUID. Ce GPU apparaît comme appareil 0 dans le conteneur. Vérifie l’accès sans
télécharger de poids :
docker compose -f compose.yaml -f compose.cuda.yaml run --rm laya python -c \
'import torch; assert torch.cuda.is_available(); print(torch.cuda.get_device_name(0)); print(torch.ones(1, device="cuda").cpu())'
L’exemple rejette un CUDA indisponible avant de charger un checkpoint. Laya peut quand même retomber sur CPU après une erreur de mémoire ou d’inférence, alors inspecte ses avertissements. Recompile en basculant entre les configurations CPU et CUDA.
L’image définit TORCH_DISABLE_NATIVE_JIT=1. Sinon, PyTorch 2.14 remplace certaines opérations CUDA
eager par des kernels Triton qu’il compile à la première inférence, ce qui exige un compilateur C que
l’image slim n’embarque pas : le conteneur se déclare sain puis fait échouer chaque requête (#365). Les
kernels standards donnent les mêmes réponses à la même latence. Définis la même variable sur une
installation native si predict échoue avec Failed to find C compiler.
Cela utilise les réservations GPU de Compose. Windows exige la configuration GPU WSL2 prise en charge par Docker Desktop. Les conteneurs Apple MPS, AMD/ROCm et Intel GPU sont hors de ce démarrage rapide ; utilise le CPU sauf si tu configures et valides un autre backend.
Configuration
Définis les variables Compose dans ton shell, un fichier .env local, ou le bloc environment du
service. Ne commite pas de secrets dans .env. Les variables de runtime fonctionnent aussi avec
docker run -e ; les réglages propres à Compose sont identifiés ci-dessous.
| Variable | Défaut | Rôle |
|---|---|---|
LAYA_DEVICE |
cpu / cuda |
Appareil sélectionné par la configuration de base / GPU |
LAYA_CUDA_AMP |
non défini (amp_dtype du checkpoint) |
fp16/float16 ou bf16/bfloat16 pour la passe avant CUDA ; toute autre valeur est ignorée. Pas cosmétique : la section des seuils du README mesure bf16 inversant 3 des 864 argmax sur le jeu de parité, là où fp16 n’en inverse aucun |
LAYA_CPU_AMP |
non défini | bf16 ou bfloat16 fait passer la passe avant CPU en bf16 ; toute autre valeur la laisse en fp32. Aucune graphie fp16 ne l’active non plus : l’autocast CPU n’a pas de chemin rapide fp16 qui bat fp32, donc bf16 est la seule précision réduite que core offre sur cet appareil |
LAYA_MODEL |
auto |
Alias du Router : auto, english, multilingual, typed-decisions |
LAYA_MODEL_PATH |
non défini | Chemin d’un checkpoint compatible dans le conteneur |
LAYA_REVISION |
non défini | Commit, branche ou tag Hub utilisé pour chaque téléchargement de checkpoint, ou reviewed pour les SHA revus dans laya/revisions.py ; un argument revision= l’emporte quand même |
LAYA_REQUEST_FILE |
requête fournie | Chemin de la requête JSON dans le conteneur |
OMP_NUM_THREADS |
4 |
Threads CPU ; reste dans les cœurs disponibles |
HF_TOKEN / HF_TOKEN_FILE |
non défini | Identifiant Hugging Face optionnel |
LAYA_API_KEY / LAYA_API_KEY_FILE |
non défini | laya-serve uniquement : exige Authorization: Bearer <key> |
LAYA_PORT |
8000 |
laya-serve uniquement : port du conteneur, et port hôte publié pour lui |
HF_HUB_OFFLINE |
0 |
1 n’utilise que les checkpoints en cache |
HF_HOME |
/home/laya/.cache/huggingface |
Chemin du cache ; voir l’exigence de montage ci-dessous |
LAYA_CACHE_VOLUME |
cache de modèle du projet | Compose uniquement : volume de cache nommé |
LAYA_GPU_ID |
0 |
Compose uniquement : index ou UUID d’appareil NVIDIA |
LAYA_TORCH_INDEX |
cpu / cu128 / cu130 |
Build Compose : index des roues PyTorch |
LAYA_TORCH_VERSION |
2.14.0 |
Build Compose : version de PyTorch épinglée |
Compose transmet les variables de runtime sauf HF_HOME, qui reste aligné sur son montage de cache
fixe, et sauf LAYA_MPS_AMP_MIN_ROWS, la porte de lignes MPS, qu’aucune image ici ne peut atteindre
parce qu’aucun conteneur ici ne peut sélectionner MPS.
Si tu surcharges HF_HOME dans docker run ou ton propre fichier Compose, fournis un montage
correspondant inscriptible par l’UID 10001. Les builds Docker directs sélectionnent PyTorch avec
--build-arg TORCH_INDEX=cu128 ; un -e de runtime ne peut pas changer la roue installée.
LAYA_MODEL=english OMP_NUM_THREADS=2 docker compose run --build --rm laya
docker build -t laya:local .
docker run --rm -e LAYA_MODEL=english -e OMP_NUM_THREADS=2 \
-v laya-model-cache:/home/laya/.cache/huggingface laya:local
Pour ta propre requête :
docker compose run --rm --volume "$PWD/request.json:/inputs/request.json:ro" \
--env LAYA_REQUEST_FILE=/inputs/request.json laya
Pour une configuration commentée avec des montages de requête, de checkpoint et de fichier de secret,
voir compose.example.yml :
docker compose -f compose.yaml -f compose.example.yml run --build --rm laya
Ajoute -f compose.cuda.yaml avant run pour les GPU NVIDIA. L’exemple est un override de
compose.yaml, donc les réglages de cache et d’image restent au même endroit.
Fichiers de secrets
HF_TOKEN_FILE lit un fichier UTF-8 monté au démarrage, coupe les espaces autour et prend le pas sur
HF_TOKEN. Les fichiers illisibles, vides ou invalides arrêtent le démarrage sans imprimer leur
contenu. Le fichier doit être lisible par l’UID 10001. _FILE ne s’applique qu’aux secrets pris en
charge, pas à chaque réglage.
Avec HF_TOKEN_PATH pointant vers un fichier hôte existant hors du checkout :
docker compose run --rm --volume "$HF_TOKEN_PATH:/run/secrets/hf_token:ro" \
--env HF_TOKEN_FILE=/run/secrets/hf_token laya
Les secrets Docker ou les volumes Secret Kubernetes peuvent fournir le même fichier. Les valeurs sont chargées dans l’environnement du processus au démarrage ; redémarre après avoir changé un fichier. N’utilise jamais de jetons comme arguments de build et ne les intègre jamais dans des images. Les checkpoints publics n’ont besoin d’aucun jeton.
Checkpoints ajustés
Cette image exécute l’inférence. L’ajustement fin a lieu en dehors — le notebook d’ajustement fin exécute toute la boucle sur les GPU 2xT4 gratuits de Kaggle et exporte un checkpoint que cette image peut servir. Le contexte et les questions ouvertes sur l’interface d’entraînement restent dans #4 et #26.
Pointe LAYA_CHECKPOINT_PATH vers un répertoire hôte absolu contenant
rl_agent_config.json, model.safetensors et les fichiers de tokenizer correspondants :
docker compose run --rm --volume "$LAYA_CHECKPOINT_PATH:/models/custom" \
--env LAYA_MODEL_PATH=/models/custom laya
Utilise une copie de travail inscriptible par l’UID 10001, parce que le chargeur peut mettre à jour la
configuration du tokenizer. Un adaptateur LoRA seul n’est pas un checkpoint complet. Laisse
LAYA_MODEL=auto quand tu définis LAYA_MODEL_PATH ; un alias explicite et un chemin local sont
mutuellement exclusifs. La réponse de chemin local vient de l’Agent et n’a pas de métadonnées routing
du Router. Ces réglages fonctionnent aussi avec l’override CUDA.
Évalue les checkpoints ajustés sur des exemples mis de côté avant de t’y fier.
Modèles depuis ModelScope
Quand un hôte ne peut pas joindre huggingface.co, le checkpoint peut venir de ModelScope et être intégré à l’image au moment du build. Un argument choisit le checkpoint, et il s’agit par défaut du multilingue. L’override Compose ajoute les arguments de prefetch aux deux services et garde le conteneur hors du Hub :
docker compose -f compose.yaml -f compose.http.yaml -f compose.modelscope.yaml up --build laya-serve
Pour NVIDIA, ajoute -f compose.cuda.yaml avant up ; il répète ses propres arguments pour les
deux services, donc l’ordre entre les deux overrides n’importe pas. Docker seul prend les
arguments directement :
docker build --build-arg MODELSCOPE_MODEL=multilingual \
-t laya:local .
docker run --rm -e HF_HUB_OFFLINE=1 -p 127.0.0.1:8000:8000 laya:local laya-serve
Un prérequis sur un hôte qui l’a déjà exécuté. Les poids intégrés atterrissent dans
$HF_HOME/hub à l’intérieur de l’image, sous le répertoire de cache où compose.yaml monte le
volume model-cache (/home/laya/.cache/huggingface), et Docker n’amorce un volume nommé
depuis l’image que tant que ce volume est vide. Un volume laissé par le démarrage rapide basé
sur le Hub contient l’ancien instantané du Hub, il n’est jamais réamorcé, et les poids intégrés
restent invisibles derrière lui : le chargeur résout refs/main vers l’ancien commit du Hub et
le conteneur répond avec les poids qui avaient déjà été téléchargés, comme si la reconstruction
n’avait rien changé. Pointe le déploiement vers un volume de cache vide — docker compose down --volumes avec les
mêmes fichiers Compose et le même LAYA_CACHE_VOLUME, ou LAYA_CACHE_VOLUME=<name> pour un
nouveau. Avec HF_HUB_OFFLINE=1, un ref absent ou divergent
est un échec de chargement sans réseau où se rabattre, mais le prérequis est le même.
docker/prefetch_modelscope.py
liste le dépôt sur modelscope.cn, télécharge les fichiers propres du checkpoint — le même
ensemble que laya/agent.py demande au Hub, donc aucun checkpoint frère n’est tiré — et les
écrit dans le cache hub de l’image comme snapshot_download dispose un instantané. Rien d’autre
ne change : Agent, le Router que construit laya-serve, laya.cli et les intégrations
gardent leurs ids de dépôt et les résolvent vers l’instantané intégré, donc un conteneur
construit ainsi n’a besoin d’aucun réseau. La taille de chaque fichier est vérifiée contre ce
que le dépôt rapporte avant la publication de l’instantané, et son SHA-256 aussi quand le dépôt
en publie un. Une divergence de taille ou de digest fait échouer le build. Un dépôt qui ne
publie aucun digest laisse la vérification sur la taille seule, ce qui ne peut pas détecter une
substitution de même taille.
| Variable | Défaut | Rôle |
|---|---|---|
MODELSCOPE_MODEL |
multilingual (Compose) ; vide dans le Dockerfile |
Checkpoint à intégrer : multilingual, english, typed-decisions ou all. Vide signifie pas de prefetch et l’image inchangée |
MODELSCOPE_REVISION |
master |
Branche, tag ou commit ModelScope à intégrer |
HF_HUB_OFFLINE |
1 dans l’override Compose |
1 ne contacte jamais le Hub, donc la copie intégrée est servie |
Un type s’étend au chemin de ce checkpoint dans le dépôt fourni, que le Router et le démarrage
rapide one-shot chargent par défaut, donc un build qui nomme un type le sert sans autre
changement :
MODELSCOPE_MODEL=english docker compose -f compose.yaml -f compose.http.yaml -f compose.modelscope.yaml up --build laya-serve
MODELSCOPE_MODEL=all docker compose -f compose.yaml -f compose.http.yaml -f compose.modelscope.yaml up --build laya-serve
all est toute la famille, environ 2,4 GB de poids. L’override définit aussi
LAYA_MODELS=multilingual, parce que LAYA_PRELOAD=1 avec la liste par défaut essaierait de
construire chaque checkpoint et échouerait sur le premier qui n’a pas été intégré ; définis
LAYA_MODELS sur la liste que tu as intégrée quand tu en intègres davantage, et
MODELSCOPE_MODEL=all quand un déploiement sert vraiment la famille.
Plusieurs types peuvent être nommés à la fois — MODELSCOPE_MODEL="english multilingual" les
intègre tous les deux, environ 1,5 GB — ce qu’une image de service veut généralement : le
Router choisit lui-même entre le checkpoint anglais et le multilingue, et un qu’il n’a pas
reçu répond 500 inference failed avec does not contain 'rl_agent_config.json' dans le log.
Les checkpoints qui partagent un dépôt sont toujours intégrés en un seul instantané, parce
qu’une révision en cache se résout en un répertoire unique ; le checkpoint racine et chaque
sous-dossier y sont tous les deux.
Au-delà des types, l’argument accepte aussi les spécifications repo[:subfolder], séparées par
des virgules ou des espaces, ce qui est la façon dont les dépôts autonomes du miroir
(laya,
laya-multilingual,
laya-typed-decisions) ou
un checkpoint ajusté sont intégrés. Un dépôt autonome est ce que
Agent("convaiinnovations/laya-multilingual") charge directement ; la valeur par défaut du
Router est le chemin fourni, donc un type est normalement ce qu’une image de service veut.
Deux détails sur les pins et la provenance. Le build imprime le commit auquel l’instantané est
indexé, c’est-à-dire la pointe de la révision intégrée — passe ce SHA comme revision= ou
LAYA_REVISION pour épingler un chargement exactement sur ce qui a été intégré. Un dépôt miroir
peut contenir des fichiers de plusieurs téléversements, donc cette pointe est la seule clé à
l’échelle du dépôt qui existe. Les pins côté Hub ne décrivent pas un instantané miroir :
reviewed nomme des commits Hugging Face, et la table de digests SHA-256 est indexée sur les
hashes d’artefacts du Hub, donc aucune ne s’applique ici, et il n’existe pas non plus de pin de
digest pour un instantané miroir. Le build refuse déjà un téléchargement qui ne correspond pas à
la taille rapportée par le miroir — et à son digest, quand le miroir en publie un — mais cela
vérifie la cohérence avec les métadonnées du miroir, pas un digest épinglé indépendamment. Les
poids viennent du compte miroir que l’argument nomme, ce qui est une décision de chaîne
d’approvisionnement qui revient au déploiement.
Développement et nettoyage
Ouvre une invite Python avec docker compose run --rm laya python. Pour exécuter les vérifications de
routage/critères existantes et les tests de fichier de secret contre ton checkout sans télécharger de
poids :
docker compose run --rm --volume "$PWD:/workspace:ro" --workdir /workspace laya \
sh -ec 'python tests/test_router.py; python tests/test_criteria.py; python tests/test_docker_entrypoint.py'
Recompile avec --build après avoir changé la source ou l’exemple fourni. L’image tourne en UID/GID
10001. Les nouveaux volumes nommés héritent de la propriété du répertoire de cache de l’image ; les
répertoires hôtes doivent être inscriptibles par cet UID. Garde les caches de modèle inscriptibles pour
les mises à jour de compatibilité du tokenizer.
--rm supprime les conteneurs terminés. docker compose down conserve le cache.
Pour supprimer les poids téléchargés, exécute docker compose down --volumes avec les mêmes
fichiers Compose et le même réglage LAYA_CACHE_VOLUME. La prochaine requête les retélécharge ; ne
supprime pas un cache partagé avec un autre projet.
Service HTTP
L’image embarque laya-serve, donc le même build qui exécute le démarrage rapide one-shot peut servir
l’API compatible Jev. compose.http.yaml l’ajoute comme second service et laisse laya tranquille :
docker compose -f compose.yaml -f compose.http.yaml up --build laya-serve
curl -s localhost:8000/health
curl -s localhost:8000/v1/systemone -H 'content-type: application/json' \
--data @examples/docker/request.json
Pour NVIDIA, ajoute l’override CUDA. Il répète les arguments de build et la réservation d’appareil pour
laya-serve, parce que laya-serve est un service séparé et que les overrides de laya ne l’atteignent
jamais :
docker compose -f compose.yaml -f compose.http.yaml -f compose.cuda.yaml up --build laya-serve
up garde le service au premier plan ; -d le détache. Les poids vont dans le même volume nommé
model-cache que le démarrage rapide, donc servir après une exécution du démarrage rapide commence avec
les checkpoints déjà sur disque. Arrête avec docker compose ... down, avec les mêmes fichiers Compose.
Le port n’est publié que sur 127.0.0.1. L’API n’a pas d’authentification tant que LAYA_API_KEY n’est
pas définie, alors définis une clé avant de l’exposer avec LAYA_BIND_ADDRESS=0.0.0.0, et place un
reverse proxy TLS devant pour les clients distants. /health ne demande pas d’authentification dans un
cas comme dans l’autre, donc le healthcheck ci-dessous continue de fonctionner ; avec une clé définie,
il répond à un appelant non authentifié {"status": "ok"} et retient les champs checkpoint, revision
et device, qui ont besoin du bearer.
Le service a un healthcheck sur /health. Le serveur précharge avant de commencer à écouter, donc avec
LAYA_PRELOAD=1 un conteneur sain a ses checkpoints chargés. docker compose ... up -d --wait laya-serve
revient une fois qu’il est sain.
/health rapporte device comme l’appareil sur lequel un checkpoint résident calcule réellement, ce
qui n’est pas toujours ce que LAYA_DEVICE a demandé : un checkpoint qui veut un GPU qu’il ne peut pas
avoir retombe silencieusement sur CPU et répond quand même correctement. checkpoint_devices nomme
chaque checkpoint chargé, et device_is_preference vaut true seulement tant que rien n’est résident,
donc un déploiement qui a discrètement perdu son GPU le dit au lieu de renvoyer sa propre configuration.
Configuration du serveur
Ceux-ci ne s’appliquent qu’au service laya-serve.
| variable | défaut | effet |
|---|---|---|
LAYA_HOST |
0.0.0.0 |
adresse d’écoute dans le conteneur |
LAYA_PORT |
8000 |
port du conteneur, et port hôte publié pour lui |
LAYA_BIND_ADDRESS |
127.0.0.1 |
adresse hôte sur laquelle le port est publié |
LAYA_PRELOAD |
0 |
1 construit chaque checkpoint au démarrage au lieu de le faire à la première requête |
LAYA_MODELS |
(tous) | liste séparée par des virgules à précharger : english,multilingual,typed-decisions |
LAYA_THREADS |
OMP_NUM_THREADS |
plafonne les threads intra-op de torch ; reste au niveau ou en dessous des cœurs physiques |
LAYA_AUTO_TASK |
0 |
1 laisse le routeur atteindre typed-decisions automatiquement |
LAYA_DEFAULT_MODEL |
english |
Checkpoint vers lequel retombe un état sans indice de langue (aucune lettre, ou texte latin trop court pour être identifié). Définis multilingual pour un trafic majoritairement non anglais ; un nom non résolvable arrête le conteneur au démarrage au lieu de servir une configuration que personne n’a demandée |
LAYA_MAX_LOADED |
2 |
Checkpoints gardés résidents ; LAYA_AUTO_TASK en rend un troisième atteignable à la demande, et un plafond en dessous de ce que choisit le routage en reconstruit un par bascule |
LAYA_MAX_CONCURRENT |
16 |
requêtes admises à la fois ; les suivantes reçoivent 503 (une valeur qui ne se parse pas, ou qui n’est pas positive, retombe sur 16) |
LAYA_LOG_LEVEL |
info |
niveau de log uvicorn |
LAYA_API_KEY |
(aucune) | quand elle est définie, exige Authorization: Bearer <key> |
LAYA_ROOT_PATH |
(vide) | préfixe d’URL public pour FastAPI derrière un reverse proxy ; le proxy doit le retirer avant de transmettre |
LAYA_MAX_TOKEN_BUDGET |
8192 |
plafond des surcharges par requête max_len et head_max_len |
LAYA_SHA256_DIGESTS |
(aucun) | digests JSON vérifiés avant qu’un checkpoint ne soit parsé : {artifact: digest} pour chaque checkpoint, ou {model: {artifact: digest}} par checkpoint. Voir Sécurité |
Par exemple, définis LAYA_ROOT_PATH=/laya en publiant l’API sous /laya. Le proxy doit retirer ce
préfixe avant de transmettre au conteneur ; ce réglage met à jour les URL générées par FastAPI et ne
change pas les routes internes /health ou /v1/systemone.
LAYA_PRELOAD vaut 0 ici plutôt que le défaut 1 du paquet, parce que le préchargement fait
télécharger les trois checkpoints au premier démarrage. Définis-le sur 1 pour un déploiement de longue
durée, afin que la première requête ne paie pas la construction.
LAYA_PORT définit à la fois le port hôte publié et le port sur lequel le serveur écoute, donc les deux
ne peuvent pas diverger. Change un seul endroit pour déplacer le service :
LAYA_PORT=9000 docker compose -f compose.yaml -f compose.http.yaml up --build laya-serve
Jeton Bearer depuis un fichier
LAYA_API_KEY_FILE est lu une fois au démarrage, déplacé dans LAYA_API_KEY, et la variable _FILE
est retirée avant que le serveur n’exécute. Préfère ceci à mettre la clé dans l’environnement :
docker compose -f compose.yaml -f compose.http.yaml run --rm \
--volume "$PWD/laya_api_key:/run/secrets/laya_api_key:ro" \
-e LAYA_API_KEY_FILE=/run/secrets/laya_api_key \
--service-ports laya-serve