Kubeflow + Katib
Pull the training loop out of the notebook
Refactor into a deterministic train.py: hyperparameters become CLI flags, and metrics must be emitted where a collector can parse them — printed as accuracy=<value> for the default StdOut collector, or written for the File / TFEvent collectors.
Containerize and publish an image
Write a Dockerfile, build a dependency-locked image, and push it to a registry — plus an imagePullSecret if that registry is private, so the cluster can pull it during trials.
Author the Experiment as Kubernetes YAML
Hand-write the objective, parameter space, algorithm, trial counts, metricsCollectorSpec, trialTemplate, and resource requests as a Katib custom resource.
Apply and operate on the cluster
kubectl apply, then watch Trials, Jobs, and Pods. Debugging means kubectl logs / describe against image pulls, RBAC, quotas, and failed metric collection.
Retrieve the best trial and promote
Read currentOptimalTrial from status, then stand up a KFP pipeline plus CI/CD to retrain on approved data and push the model to a registry.
Package each stage as a KFP component
Declare train / evaluate as a @dsl.component with typed Input/Output artifacts and the metric return contract the selector reads. Light components can lean on packages_to_install, but real training dependencies mean a custom base_image to build and push.
Generate the candidate configs
A component emits the search space as an explicit grid or random sample — workable only for a small, fixed set of trials known up front.
Build the search controller
Removing Katib removes its suggestion service, so you embed Optuna (or Ray Tune) yourself. The catch isn't embedding it — it's that ParallelFor is compiled topology and needs candidates up front, so an adaptive ask → score → tell loop can't live inside the pipeline. You drive rounds from outside, or recompile per round.
Author the sweep as a KFP DSL pipeline
dsl.ParallelFor(parallelism=N) fans out each round of trials; dsl.Collected returns their scores to your controller and selector. The DSL looks like Python but describes topology, not local execution.
Compile and submit to the pipeline runtime
Compile the DSL, submit it to the KFP runtime, and make sure Kubernetes quotas, GPUs, and autoscaling support the concurrency. Retries and cleanup are wired in via exit handlers.
Select, retrain, and register
choose_winner from the collected scores, retrain on approved data, and register the model in downstream steps — while still operating the underlying Kubeflow services throughout.