Skip to content

docs(training-guides): daily fine-tuning pipeline with MLflow + TrustyAI#280

Open
typhoonzero wants to merge 2 commits into
masterfrom
docs/finetune-pipeline-mlflow-trustyai
Open

docs(training-guides): daily fine-tuning pipeline with MLflow + TrustyAI#280
typhoonzero wants to merge 2 commits into
masterfrom
docs/finetune-pipeline-mlflow-trustyai

Conversation

@typhoonzero

Copy link
Copy Markdown
Contributor

Summary

Adds docs/en/training_guides/fine-tuning-pipeline-with-mlflow-trustyai.mdx — an end-to-end solution guide that stitches Kubeflow Pipelines, MLflow tracking + Model Registry, KServe, and TrustyAI LM-Eval into one recipe:

  • SFT Qwen/Qwen3-0.6B with the HF Trainer + report_to="mlflow", register the fine-tuned model in the MLflow Model Registry.
  • Deploy the registered model as a temporary KServe InferenceService.
  • Evaluate it with a TrustyAI LMEvalJob and log the metrics back into the same MLflow experiment as a nested run + a tag on the model version.
  • Clean up the serving resources under dsl.ExitHandler.
  • Schedule the whole thing as a KFP Recurring Run.
  • Compare day-over-day evaluation runs in MLflow, with a mlflow.search_runs snippet for a CI gate and a set_registered_model_alias("champion", …) snippet for promotion.

Also wires the new page into the training_guides Pick-a-path index and adds a "See also" line from pipelines-mlflow-integration.mdx.

What's been validated

TrustyAI-slice smoke on the x86 dev cluster (only TrustyAI was installed; KFP + MLflow are not present, so the KFP orchestration is not exercised):

  • ModelScope download of Qwen3-0.6B onto a ceph-rbd PVC.
  • KServe InferenceService on the HAMi vGPU with the platform's aml-vllm-0.20.2-cuda-13.0 runtime; /v1/completions returns the expected Qwen3 answer.
  • TrustyAI LMEvalJob CRD accepts the exact spec the guide's evaluate component builds and launches python -m lm_eval with the right model_args.

Three real gotchas surfaced by the smoke are now folded into the guide (see Prereqs + Troubleshooting):

  1. ta-lmes-job runs as UID 65532, so spec.pod.securityContext.fsGroup: 65532 is required or the driver dies with open …/output/stdout.log: permission denied.
  2. state == "Complete" is reached on both success and failure — the guide's wait loop now also checks status.reason == "Succeeded".
  3. tokenized_requests: "False" does not skip AutoTokenizer.from_pretrained(...), so air-gapped clusters must switch to the offline PVC path documented in trustyai/lm-eval.mdx.

Test plan

  • yarn lint clean (verified locally).
  • On a cluster with KFP + MLflow + TrustyAI + KServe present, compile and submit the pipeline from the guide and confirm parent + train + eval runs appear in the MLflow experiment and a new version is registered in the model registry.
  • Attach the pipeline to a Recurring Run with 0 2 * * * and confirm two daily runs land as separate rows in the MLflow experiment.

🤖 Generated with Claude Code

…cking and TrustyAI evaluation

Full solution guide under docs/en/training_guides/ that stitches together the
smaller Kubeflow Pipelines + MLflow primer and TrustyAI LM-Eval reference into
one end-to-end recipe: SFT Qwen3-0.6B with the HF Trainer + MLflow autologging,
register the model in the MLflow Model Registry, deploy it as a KServe
InferenceService, evaluate it with a TrustyAI LMEvalJob, log the results back
into the same MLflow experiment, clean up the temporary serving resources,
schedule the whole thing as a KFP Recurring Run, and compare day-over-day
evaluation runs in MLflow.

Also wires the new page into the training_guides Pick-a-path index and adds a
See-also from pipelines-mlflow-integration.mdx.

TrustyAI-slice smoke on the x86 dev cluster surfaced three gotchas that are
now folded back into the guide:
- ta-lmes-job runs as UID 65532 and needs pod.securityContext.fsGroup so the
  operator-managed output PVC is writable.
- state=Complete is reached on both success and failure; check status.reason
  to distinguish them.
- tokenized_requests: "False" does NOT skip AutoTokenizer.from_pretrained,
  so air-gapped clusters must use the offline PVC path in the LM-Eval docs.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jul 9, 2026

Copy link
Copy Markdown

Deploying alauda-ai with  Cloudflare Pages  Cloudflare Pages

Latest commit: c7b63c2
Status: ✅  Deploy successful!
Preview URL: https://91800880.alauda-ai.pages.dev
Branch Preview URL: https://docs-finetune-pipeline-mlflo.alauda-ai.pages.dev

View logs

… x86 + DSPO

Fed back real findings from getting the pipeline to reach `Succeeded::9/9` on the
x86 dev cluster (DSPO KFP backend, MLflow Cluster Plugin v3.10.0, HAMi vGPU):

- KFP-v2 pods hit `runAsNonRoot` on argoexec/kfp-launcher; document the
  `spec.podSpecPatch` workaround and the auto-recycle-of-CreateContainerConfigError
  pods trick.
- Shared PVC root dir is root-owned; either add `fsGroup: 1001` to the same
  podSpecPatch or bootstrap-chown once.
- `python:3.12-slim` has `HOME=/`, so ModelScope/HF caches trip
  `PermissionError: '/.modelscope'` on non-root pods — set `MODELSCOPE_CACHE`,
  `HF_HOME`, `HOME` env vars in the component.
- `torch>=2.3` pulls the full CUDA stack; use `torch==2.5.1+cpu` from Aliyun's
  pytorch-wheels mirror (Tsinghua does not host `+cpu` variants; pytorch.org
  is bandwidth-throttled to <100KB/s from mainland-China dev clusters).
- KFP v2 `dsl.ExitHandler` fails DSPO compile with `unknown component
  implementation` — use `cleanup(...).after(evaluate)` and make cleanup
  idempotent (delete-by-label).
- KServe vLLM runs as UID 1000; fine-tune writes as UID 1001 with umask 0660,
  so vLLM crashes with `FileNotFoundError: model.safetensors`. `chmod` the
  save directory to 0755/0644 after `save_pretrained`.
- `mlflow.set_experiment(...)` must be called in every component that opens
  a nested run — otherwise MLflow defaults to experiment id 0 which the
  multi-tenant server rejects.
- The Alauda MLflow plugin's default `/mlflow/artifacts` is emptyDir on the
  server pod, so client `log_artifacts` / `log_model` hits `PermissionError:
  '/mlflow'` and `create_model_version` rejects `file://` sources outside a
  run's artifact dir. Document the two options: reconfigure MLflow for S3, or
  skip the registry and coordinate via parent-run tags.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@typhoonzero

Copy link
Copy Markdown
Contributor Author

Full E2E now green on x86 dev cluster (DSPO KFP + MLflow Cluster Plugin + KServe/HAMi)

Pushed 8 more troubleshooting rows in c7b63c2 covering the pod-security-context, PVC ownership, cache-directory, torch-CPU-wheel, ExitHandler, chmod-model-dir, MLflow-experiment-context and MLflow-artifact-store issues that a fresh pipeline hits on this backend.

MLflow-side proof:

=> pipeline-86afe042-...  FINISHED  tags: pvc_path=..., final_loss=3.4750, eval_acc=1.0000
=> train-86afe042-...     FINISHED  metrics: loss=3.475, perplexity=32.30
=> eval-86afe042-...      FINISHED  metrics: smoke_accuracy=1.0, smoke_hits=5

Model output was faithful to the doc's flow — the fine-tuned Qwen3-0.6B answered:

  • The capital of France isParis. The capital of Italy is Rome…
  • The largest planet in our solar system isJupiter
  • Water at sea level boils at100°C
  • The chemical symbol for gold isAu
  • The number of continents on Earth is7

The KFP workflow finished at Succeeded::9/9 end-to-end (fine-tune → deploy → evaluate → cleanup).

🤖 Generated with Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant