# GPU Resource Optimization Design **Goal:** Route RL training jobs (DQN, PPO) to cheaper L4 GPUs and supervised jobs to L40S, maximizing throughput and minimizing cost. **Architecture:** Two-tier GPU routing with separate CI templates per model family, tuned CPU/memory requests per workload profile. **Tech Stack:** GitLab CI, Kubernetes node selectors, Scaleway Kapsule node pools --- ## Current State - **L40S node** (ci-training pool): Running one job at a time, GPU at 34% utilization, 617MiB/46GB VRAM - **L4 node** (ci-compile pool): Idle after compile, scaled to zero - **DQN/PPO**: CPU-bound (environment simulation), use <1GB VRAM, small checkpoints (~233KB) - **Supervised models** (TFT, Mamba2, TGGN, TLOB, Liquid, KAN, xLSTM, Diffusion): GPU-bound (attention, SSM, denoising), need larger VRAM ## Design ### Routing Rules | Model Family | GPU Pool | Node | Why | |---|---|---|---| | DQN, PPO (+ hyperopt) | ci-compile | L4-1-24G | CPU-bound, <1GB VRAM, L4 has idle CPU after compile | | TFT, Mamba2, TGGN, TLOB, Liquid, KAN, xLSTM, Diffusion (+ hyperopt) | ci-training | L40S-1-48G | GPU-bound, benefit from 48GB VRAM and FP8 | ### Resource Requests **RL jobs (L4):** - CPU: 3000m request / 3800m limit (high — RL is CPU-bound from env simulation) - Memory: 8Gi request / 16Gi limit - Concurrency: 2 jobs max on L4 (7800m total CPU) **Supervised jobs (L40S):** - CPU: 1000m request / 2000m limit (low — GPU-bound) - Memory: 16Gi request / 40Gi limit - Concurrency: 3-4 jobs via CUDA MPS / time-slicing (46GB VRAM shared) ### CI Template Changes **New `.train-rl-base` template** (no `KUBERNETES_NODE_SELECTOR_POOL` override → uses runner default `ci-compile`): ```yaml .train-rl-base: stage: train image: ${REGISTRY}/training:${CI_COMMIT_SHA} tags: [kapsule, gpu] variables: KUBERNETES_CPU_REQUEST: "3000m" KUBERNETES_CPU_LIMIT: "3800m" KUBERNETES_MEMORY_REQUEST: "8Gi" KUBERNETES_MEMORY_LIMIT: "16Gi" # No KUBERNETES_NODE_SELECTOR_POOL → defaults to ci-compile (L4) ``` **Updated `.train-validate-base`** (supervised, explicit L40S): ```yaml .train-validate-base: stage: train image: ${REGISTRY}/training:${CI_COMMIT_SHA} tags: [kapsule, gpu] variables: KUBERNETES_NODE_SELECTOR_POOL: "k8s.scaleway.com/pool-name=ci-training" KUBERNETES_CPU_REQUEST: "1000m" KUBERNETES_CPU_LIMIT: "2000m" KUBERNETES_MEMORY_REQUEST: "16Gi" KUBERNETES_MEMORY_LIMIT: "40Gi" ``` ### Job Routing Jobs extending `.train-rl-base`: `train-validate-dqn`, `train-validate-ppo`, `hyperopt-dqn`, `hyperopt-ppo` Jobs extending `.train-validate-base`: all 8 supervised train + 8 supervised hyperopt jobs ### Hyperopt Epoch Reduction Reduce default hyperopt epochs from 15 → 8 for RL models (faster iteration, DQN currently ~1100s/epoch × 15 = 4.5h per trial). ### Cost Impact - L4 is ~60% cheaper than L40S per hour - RL jobs move to L4 → immediate cost reduction - Supervised jobs can run concurrently on L40S → higher throughput - Both pools autoscale 0→1 → no idle cost when unused