Documentation

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