一键导入
sop-cr-finetuning
Fine-tune Cosmos-Reason2 (CR2) VLM for SOP monitoring. Use when you need to launch and monitor a VLM training run with a given dataset ID.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Fine-tune Cosmos-Reason2 (CR2) VLM for SOP monitoring. Use when you need to launch and monitor a VLM training run with a given dataset ID.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Use this skill when building, deploying, evaluating, debugging, or measuring latency for the DeepStream SOP Inference Microservice — a GPU-accelerated FastAPI service that detects whether operators perform assembly-line steps in order via event boundary detection (GEBD) plus VLM classification. Trigger even if the user does not name it: verify operator step sequence, detect missing or out-of-order SOP steps, score factory/work-cell video for procedure compliance, run VLM-based SOP checking on industrial cameras, or call /v1/chat/completions with a file, RTSP, or Basler camera. Also trigger for its internals: SOPVideoProcessor, DeepStream GEBD model (e.g. DDM) via Triton CAPI, nvds_custom_postprocess, Cosmos Reason 1/2 vLLM, SSE streaming, Kafka NvProto/JSON output, Basler/Pylon camera + emulation, Docker compose, chunk-level latency. Do NOT trigger for generic DeepStream pipelines, object detection/tracking, NIM imports, or video summarization.
Use when the user wants to run data augmentation on an annotated dataset, configure augmentation parameters, check augmentation status, or understand what each QA augmentation type does (BCQ, MCQ, GQA, DMCQ, DSQA, ENQA)
Fine-tune DDM-Net temporal boundary detector for SOP monitoring. Use when you need to launch and monitor a DDM-Net training run with a given dataset ID.
Use when running by-action VLM evaluation (per-action-clip inference + accuracy metrics) against the BP evaluation-ms HTTP API. Invoked as /sop-by-action-eval <inputs.yaml> [natural language parameter overrides]
Use when running the e2e evaluation pipeline (temporal segmentation + action recognition + accuracy) against the BP evaluation-ms HTTP API. Invoked as /sop-e2e-inference <inputs.yaml> [natural language parameter overrides]
Autonomous end-to-end orchestrator for SOP fine-tuning. Runs the full Import → Augment → DDM Train → VLM Train → Evaluate → RCA loop. Interprets RCA findings across DDM, VLM and augment axes, applies config fixes autonomously, and iterates until success criteria are met or max_pipeline_iterations reached. Call with a path to an inputs.yaml or with natural language.
| name | sop-cr-finetuning |
| description | Fine-tune Cosmos-Reason2 (CR2) VLM for SOP monitoring. Use when you need to launch and monitor a VLM training run with a given dataset ID. |
| argument-hint | <qa_augmented_dataset_id> |
| license | CC-BY-4.0 AND Apache-2.0 |
You are performing Cosmos-Reason2 (CR2) VLM fine-tuning for an SOP (Standard Operating Procedure) monitoring system. The training pipeline fine-tunes a Qwen3VL-based vision-language model on augmented SOP video QA data so the model can classify operator actions from video segments.
Your job is to launch training and monitor it to completion. Training logs are persisted by the training service at results/<job_id>/log.txt.
The user provides a qa_augmented_dataset_id as $ARGUMENTS. This is the identifier for the augmented dataset to train on.
If no argument is provided, ask the user for the qa_augmented_dataset_id.
For reference on API endpoints, anomaly detection, and monitoring commands, see ${CLAUDE_SKILL_DIR}/reference.md.
http://localhost:32080/api/v1./assets/resultsBefore starting any training, verify readiness:
Check service health:
curl -s http://localhost:32080/health
If the service is healthy, skip to step 2. If unreachable, start the container:
docker compose up -d cosmos-reason-microservice
Then poll /health with retries until ready. If the service fails to become healthy after retries, report the error and stop.
Check GPU availability:
nvidia-smi --query-gpu=index,name,memory.total,memory.free --format=csv,noheader
Warn if free memory is below 60GB per GPU.
Check for running jobs:
curl -s http://localhost:32080/api/v1/fine-tuning/all_jobs
If a job is already running, warn the user and ask whether to wait or cancel it.
Report all pre-flight results before proceeding.
Start training:
curl -s -X POST "http://localhost:32080/api/v1/fine-tuning/start?dataset_id=<qa_augmented_dataset_id>" -H "Content-Type: application/json"
Use the qa_augmented_dataset_id from $ARGUMENTS. Record the job_id from the response.
Monitor training progress by polling the status endpoint every 60 seconds:
curl -s "http://localhost:32080/api/v1/fine-tuning/status/<job_id>"
On each poll, extract and report:
status — queued / running / completed / failed / cancelledprogress — percentage completecurrent_step / total_stepsloss — current training lossMonitor for anomalies by checking container logs periodically:
# Check for OOM
docker compose logs --since 5m cosmos-reason-microservice 2>&1 | grep -i "out of memory\|OOM\|CUDA error"
# Check for NaN
docker compose logs --since 5m cosmos-reason-microservice 2>&1 | grep -iE "loss.*nan|nan.*loss" | head -5
# Check GPU status
docker compose exec cosmos-reason-microservice nvidia-smi --query-gpu=index,utilization.gpu,memory.used,memory.total,temperature.gpu --format=csv,noheader
Report progress every 10% (10%, 20%, …, 100%). Include:
Wait for completion. When status becomes completed, failed, or cancelled, proceed to Phase 3.
After training completes (regardless of outcome), collect metrics, write a training report to ./assets/results/<job_id>/training_report.md, and report to the user.
Gather metrics from the final status response:
Collect anomaly summary from monitoring:
If the training run used LoRA, the checkpoint is a small adapter (delta weights) that cannot be used for inference on its own and must be merged with the base model. Full fine-tuning runs skip this step — the checkpoint is already a standalone full-weight model.
After this phase, the inference-ready model always lives at the same path: assets/results/<job_id>/<timestamp>/safetensors/step_<N>/. For LoRA runs, the merged full-weight model replaces the adapter at that path; the original adapter is preserved as a sibling step_<N>_lora_adapter/. Downstream evaluation reads step_<N>/ via the standard training_job_id + checkpoint_step resolution and does not need to know whether the run was LoRA or full.
Path layout. Cosmos-RL writes checkpoints to:
assets/results/<job_id>/<timestamp>/safetensors/step_<N>/
<timestamp> is a UTC datetime subdir (one per training run); <N> is the global step. Pick the final step (largest <N>) for inference.
IMPORTANT: Run all merge commands inside the same
cosmos-reason-microservicecontainer that produced the adapter.
/workspace/sop-cr-ftms/assets/weights/<base_model_dir>/./workspace/sop-cr-ftms/assets/results/<job_id>/....Container path prefix mapping (host ↔ container) is a fixed swap:
host: <bp_root>/assets/...
container: /workspace/sop-cr-ftms/assets/...
Detect LoRA vs full fine-tune. Resolve the final-step checkpoint dir, then probe for adapter_config.json:
CR_CONT=$(docker ps --format '{{.Names}}' | grep cosmos-reason-microservice | head -1)
JOB_ID=<job_id>
CKPT_DIR=$(docker exec $CR_CONT bash -c \
"ls -d /workspace/sop-cr-ftms/assets/results/$JOB_ID/*/safetensors/step_* 2>/dev/null | sort -V | tail -1")
echo "checkpoint dir: $CKPT_DIR"
if docker exec $CR_CONT test -f "$CKPT_DIR/adapter_config.json"; then
echo "LoRA adapter detected — run steps 3b.1 → 3b.3."
else
echo "Full fine-tune detected — skip 3b.1 → 3b.3. step_<N>/ is already an inference-ready model."
fi
If full fine-tune: skip the rest of this section.
adapter_config.json for forward-compatCosmos-RL's training stack may serialise LoRA config fields the inference-side peft doesn't accept (e.g. r_pattern), or write null where a dict is expected (e.g. alpha_pattern: null). Normalise defensively before loading:
docker exec $CR_CONT python3 -c "
import json
p='$CKPT_DIR/adapter_config.json'
d=json.load(open(p))
d.pop('r_pattern', None) # drop unknown fields
for k in ('alpha_pattern','rank_pattern'):
if d.get(k) is None: d[k] = {} # null -> {} (peft expects dict)
for k,v in dict(bias='none', task_type='CAUSAL_LM', inference_mode=True,
fan_in_fan_out=False, layers_to_transform=None,
layers_pattern=None, megatron_config=None,
megatron_core='megatron.core', loftq_config={},
use_dora=False, init_lora_weights=True).items():
d.setdefault(k, v) # backfill defaults
json.dump(d, open(p,'w'), indent=2)
print('adapter_config.json normalised')
"
Write to a sibling step_<N>_merged_tmp/ so the final atomic swap (3b.3) is crash-safe:
The base model path and the base model class are both derived from the adapter at run-time:
adapter_config.json["base_model_name_or_path"], which peft writes at training time. It is typically a path relative to the training process's working directory (/workspace/sop-cr-ftms), e.g. ./assets/weights/Cosmos-Reason2-2B. Resolve it against that working dir if it isn't already absolute.AutoModelForImageTextToText, which reads architectures from the base model's config.json and instantiates the right class (e.g. Qwen3VLForConditionalGeneration for Cosmos-Reason2-2B, Qwen2_5_VLForConditionalGeneration for older variants).docker exec -w /workspace/sop-cr-ftms $CR_CONT python3 -c "
import json, os, torch
from transformers import AutoModelForImageTextToText, AutoProcessor
from peft import PeftModel
adapter_path = '$CKPT_DIR'
tmp_path = adapter_path + '_merged_tmp'
# Resolve the base model path from the adapter's own metadata.
with open(os.path.join(adapter_path, 'adapter_config.json')) as f:
base_rel = json.load(f)['base_model_name_or_path']
base_path = (base_rel if os.path.isabs(base_rel)
else os.path.normpath(os.path.join('/workspace/sop-cr-ftms', base_rel)))
print(f'base model: {base_path}', flush=True)
print('loading base...', flush=True)
base = AutoModelForImageTextToText.from_pretrained(
base_path, dtype=torch.bfloat16, device_map='cpu')
print('loading adapter...', flush=True)
model = PeftModel.from_pretrained(base, adapter_path)
print('merging...', flush=True)
merged = model.merge_and_unload()
os.makedirs(tmp_path, exist_ok=True)
merged.save_pretrained(tmp_path, safe_serialization=True)
# Processor/preprocessor configs live with the base model, not the adapter.
# The adapter dir only carries tokenizer files.
AutoProcessor.from_pretrained(base_path).save_pretrained(tmp_path)
print('merged ->', tmp_path)
"
Notes on the kwargs:
device_map='cpu' — merge is memory-bandwidth-bound and uses ~6 GB CPU RAM. Keeps GPUs free for concurrent training/eval.dtype=torch.bfloat16 — matches the precision the LoRA was trained against.AutoProcessor) is loaded from the base model path, not the adapter path. Vision/video preprocessor configs live with the base; the adapter dir only carries tokenizer + adapter files.step_<N>/Evaluation-ms resolves checkpoints by safetensors/step_<N>/ and calls from_pretrained on that exact path; it has no knowledge of merged_model/ or other subdirs. Swap the merged result in and keep the original adapter as a sibling:
docker exec $CR_CONT bash -c "
STEP_DIR='$CKPT_DIR'
PARENT=\$(dirname \$STEP_DIR)
STEP=\$(basename \$STEP_DIR)
mv \$STEP_DIR \${PARENT}/\${STEP}_lora_adapter
mv \${PARENT}/\${STEP}_merged_tmp \$STEP_DIR
"
Listing the new step_<N>/ should show full-model files, not adapter files:
docker exec $CR_CONT ls "$CKPT_DIR"
Expect config.json, model.safetensors (or sharded model-00001-of-NNNNN.safetensors), tokenizer.json, preprocessor_config.json, video_preprocessor_config.json, generation/special-token configs. The presence of adapter_model.safetensors here means the merge did not land — recheck 3b.3.
Save a formatted training report to ./assets/results/<job_id>/training_report.md:
# Training Report
## Overview
| Field | Value |
|-------|-------|
| Dataset | <qa_augmented_dataset_id> |
| Job ID | <job_id> |
| Status | completed / failed / cancelled |
| Duration | Xh Xm |
## Training Metrics
| Metric | Value |
|--------|-------|
| Final Loss | X.XX |
| Best Loss | X.XX (step N) |
| Total Steps | N / N |
| Steps/sec | X.XX |
| GPU Memory Peak | XX% |
## Anomalies
- List any OOM events, loss spikes, NaN occurrences, or GPU warnings detected during training.
- "None" if no anomalies were detected.
## Artifacts
- **Inference-ready checkpoint:** `assets/results/<job_id>/<timestamp>/safetensors/step_<N>/` — always, regardless of training mode (Phase 3b merges LoRA into the base in place; full fine-tune writes here directly).
- **LoRA adapter backup (LoRA runs only):** `assets/results/<job_id>/<timestamp>/safetensors/step_<N>_lora_adapter/` — the unmerged adapter, kept for reproducibility/audit.
- **Training log:** `results/<job_id>/log.txt`
Print the training report content to the user as well. If training failed, include the error details.