據(jù)與VLM后訓(xùn)練實(shí)戰(zhàn):物理AI場(chǎng)景落地)
在物理 AI 與具身智能項(xiàng)目里最讓人頭疼的往往不是模型算法本身而是兩件事第一真實(shí)場(chǎng)景數(shù)據(jù)太貴、太難采集第二模型在垂直領(lǐng)域里表現(xiàn)不穩(wěn)定。比如做智慧城市車流識(shí)別晴天效果尚可一到雨霧天氣誤報(bào)率就明顯上升做農(nóng)業(yè)機(jī)器人采摘換一個(gè)果園、換一種光照之前調(diào)好的視覺模型又要重新調(diào)參。這些問題背后其實(shí)都繞不開三個(gè)關(guān)鍵詞世界基礎(chǔ)模型World Foundation Model, WFM、視覺語言模型Vision-Language Model, VLM和合成數(shù)據(jù)Synthetic Data。本文圍繞 Cosmos 3 后訓(xùn)練實(shí)戰(zhàn)完整梳理一條可落地的技術(shù)鏈路先用 Cosmos 3 生成農(nóng)業(yè)機(jī)器人場(chǎng)景的合成數(shù)據(jù)再結(jié)合少量真實(shí)數(shù)據(jù)構(gòu)建 VLM 后訓(xùn)練集微調(diào)后部署到智慧城市視頻流推理任務(wù)中做效果驗(yàn)證。文章會(huì)說明每個(gè)環(huán)節(jié)為什么這樣做也會(huì)給出可運(yùn)行的示例代碼、常見報(bào)錯(cuò)排查表和工程落地建議。如果你正在做視覺語言模型選型、VLM 后訓(xùn)練、合成數(shù)據(jù)增強(qiáng)或者想了解 Cosmos 3 能干什么這篇文章會(huì)比較適合你。全文采用中英雙語的術(shù)語注釋方式代碼關(guān)鍵位置也保留雙語注釋方便對(duì)照學(xué)習(xí)。1. 背景與核心概念1.1 Cosmos 3 是什么Cosmos 3 是 NVIDIA 推出的世界基礎(chǔ)模型World Foundation Model系列在 3.x 版本中的核心成果。它并不是一個(gè)單一模型而是一組面向物理 AI 場(chǎng)景的模型和工具鏈主要目標(biāo)是讓模型理解“物理世界如何運(yùn)轉(zhuǎn)”并能夠生成接近真實(shí)物理規(guī)律的視頻幀序列。在機(jī)器人、自動(dòng)駕駛、智慧城市等場(chǎng)景中模型需要理解的不只是靜態(tài)圖像里的物體類別還包括物體的空間關(guān)系、運(yùn)動(dòng)趨勢(shì)、光照變化、遮擋關(guān)系、因果推斷等。這類能力很難從普通圖像分類數(shù)據(jù)集中學(xué)習(xí)而 Cosmos 3 等世界模型的核心價(jià)值就是通過對(duì)海量物理世界視頻的學(xué)習(xí)建立對(duì)“下一秒可能發(fā)生什么”的預(yù)測(cè)能力。與傳統(tǒng)的文生視頻模型相比Cosmos 3 更強(qiáng)調(diào)可控性和物理合理性。它能夠在文本指令、相機(jī)參數(shù)、運(yùn)動(dòng)軌跡等條件的約束下生成指定場(chǎng)景的連續(xù)視頻幀。這樣的合成視頻可以作為下游視覺模型的訓(xùn)練數(shù)據(jù)從而減少對(duì)真實(shí)數(shù)據(jù)的依賴。1.2 什么是后訓(xùn)練Post-training大模型領(lǐng)域通常把訓(xùn)練過程分為預(yù)訓(xùn)練Pre-training和后訓(xùn)練Post-training兩個(gè)階段。預(yù)訓(xùn)練負(fù)責(zé)讓模型學(xué)習(xí)通用語言、視覺和世界知識(shí)而后訓(xùn)練則負(fù)責(zé)讓模型適配特定任務(wù)、特定領(lǐng)域和特定的交互方式。常見的后訓(xùn)練方法包括方法英文全稱說明監(jiān)督微調(diào)Supervised Fine-Tuning, SFT用帶標(biāo)注的任務(wù)數(shù)據(jù)調(diào)整模型參數(shù)低秩適配Low-Rank Adaptation, LoRA凍結(jié)原模型只訓(xùn)練低秩矩陣節(jié)省顯存基于人類反饋的強(qiáng)化學(xué)習(xí)RLHF通過獎(jiǎng)勵(lì)模型優(yōu)化生成質(zhì)量直接偏好優(yōu)化Direct Preference Optimization, DPO用偏好對(duì)直接優(yōu)化無需獎(jiǎng)勵(lì)模型在本文的場(chǎng)景中后訓(xùn)練的主要目的是讓預(yù)訓(xùn)練 VLM 更好地理解智慧城市和農(nóng)業(yè)機(jī)器人這兩個(gè)垂直領(lǐng)域的圖像內(nèi)容例如能夠正確回答“畫面中是否有行人闖紅燈”“這個(gè)番茄的成熟度是多少”等細(xì)粒度問題。1.3 VLM 推理解決什么問題視覺語言模型Vision-Language Model, VLM能夠同時(shí)處理圖像輸入和文本輸入輸出文本描述或結(jié)構(gòu)化信息。與傳統(tǒng)的目標(biāo)檢測(cè)模型相比VLM 的優(yōu)勢(shì)在于支持開放詞匯不僅能識(shí)別訓(xùn)練集中出現(xiàn)過的類別還能理解自然語言描述的新類別。具備上下文理解能結(jié)合畫面中的物體關(guān)系、場(chǎng)景背景進(jìn)行推理。輸出更靈活可以直接輸出自然語言答案也可以借助提示詞輸出 JSON 等結(jié)構(gòu)化格式。在智慧城市場(chǎng)景里VLM 可以完成事件檢測(cè)、要素描述、異常預(yù)警等任務(wù)。例如給定一段監(jiān)控視頻幀模型能輸出“畫面中有 3 輛機(jī)動(dòng)車1 輛正在左轉(zhuǎn)行人處于等待狀態(tài)”這類結(jié)構(gòu)化描述。1.4 為什么需要合成數(shù)據(jù)智慧城市和農(nóng)業(yè)機(jī)器人場(chǎng)景的數(shù)據(jù)采集都有明顯瓶頸。智慧城市視頻涉及隱私與合規(guī)問題農(nóng)業(yè)機(jī)器人的田間數(shù)據(jù)受季節(jié)、天氣、地域限制采集成本高且難以覆蓋長(zhǎng)尾場(chǎng)景。合成數(shù)據(jù)Synthetic Data可以在一定程度上緩解這些問題。使用 Cosmos 3 生成帶有物理規(guī)律的運(yùn)動(dòng)視頻讓模型在訓(xùn)練階段見過更多“對(duì)抗樣本”例如夜間強(qiáng)光、雨天反光、果實(shí)遮擋等情況。這樣當(dāng)模型部署到真實(shí)環(huán)境時(shí)泛化能力會(huì)更強(qiáng)。但需要強(qiáng)調(diào)合成數(shù)據(jù)不是萬能的它不能完全替代真實(shí)數(shù)據(jù)。更合理的做法是“真實(shí)數(shù)據(jù) 合成數(shù)據(jù)”混合訓(xùn)練并通過驗(yàn)證集持續(xù)評(píng)估數(shù)據(jù)質(zhì)量。2. 環(huán)境準(zhǔn)備與版本說明在開始實(shí)操之前先理清當(dāng)前示例環(huán)境。后續(xù)代碼基于以下配置運(yùn)行如果你的環(huán)境不同需要根據(jù)實(shí)際情況調(diào)整。2.1 硬件與系統(tǒng)要求Cosmos 3 合成數(shù)據(jù)生成和 VLM 后訓(xùn)練都屬于資源密集型任務(wù)建議使用 NVIDIA GPU。顯存規(guī)模直接決定了可以生成的視頻分辨率以及微調(diào)時(shí)使用的批量大小。資源建議要求GPUNVIDIA RTX 3090 / 4090 / A100 / H100 或更高顯存16 GB 以上生成高分辨率視頻或微調(diào) 7B 以上模型時(shí)需要更大顯存系統(tǒng)Ubuntu 22.04 或 Windows 11WSL2磁盤建議預(yù)留 100 GB 以上空間存放模型權(quán)重和數(shù)據(jù)集如果暫時(shí)沒有足夠顯存可以先使用小模型、低分辨率和更小的 batch size 驗(yàn)證流程再遷移到更大規(guī)模環(huán)境。2.2 Python 與深度學(xué)習(xí)框架以下版本組合是當(dāng)前比較常見且穩(wěn)定的配置具體以官方文檔為準(zhǔn)Python 3.10 或 3.11CUDA 12.1 或更高PyTorch 2.1 或更高Transformers 4.40 或更高PEFT 0.10 或更高Datasets 2.18 或更高Accelerate 0.30 或更高先創(chuàng)建一個(gè)獨(dú)立的 Conda 環(huán)境conda create -n cosmos-ai python3.11 -y conda activate cosmos-ai pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121 pip install transformers peft accelerate datasets pillow tensorboard注意PyTorch 的安裝命令需要結(jié)合 CUDA 版本調(diào)整。如果使用 WSL2需要確保 Windows 側(cè)已安裝最新的 NVIDIA 驅(qū)動(dòng)并在 WSL2 內(nèi)執(zhí)行nvidia-smi確認(rèn) GPU 可見。2.3 項(xiàng)目目錄結(jié)構(gòu)為了方便后續(xù)操作建議按照下面結(jié)構(gòu)組織項(xiàng)目cosmos-finetune-lab/ ├── data/ │ ├── real/ # 真實(shí)圖像與標(biāo)注 │ ├── synthetic/ # Cosmos 生成數(shù)據(jù) │ └── annotations/ # 標(biāo)注 JSON ├── models/ │ ├── pretrained/ # 預(yù)訓(xùn)練 VLM 權(quán)重 │ └── finetuned/ # 后訓(xùn)練輸出權(quán)重 ├── scripts/ │ ├── generate_synthetic.py # 合成數(shù)據(jù)生成腳本 │ ├── prepare_dataset.py # 數(shù)據(jù)集構(gòu)建腳本 │ ├── train_lora.py # LoRA 后訓(xùn)練腳本 │ └── inference.py # VLM 推理腳本 ├── configs/ │ ├── lora_config.yaml │ └── data_config.yaml └── output/ ├── logs/ └── results/3. 核心原理拆解后訓(xùn)練、VLM 推理與合成數(shù)據(jù)生成在進(jìn)入完整代碼前先拆解三個(gè)關(guān)鍵模塊的原理這能幫助你理解后面每一步操作的意義。3.1 后訓(xùn)練到底改了什么預(yù)訓(xùn)練模型已經(jīng)具備很強(qiáng)的通用能力但在垂直領(lǐng)域中會(huì)出現(xiàn)“能力有但不在點(diǎn)子上”的情況。例如模型知道番茄是紅色的果實(shí)但無法判斷“番茄表面有明顯褐色斑點(diǎn)”是否意味著病蟲害。后訓(xùn)練就是通過新的標(biāo)注數(shù)據(jù)把模型原先分散的知識(shí)引導(dǎo)到特定任務(wù)上。以 LoRA 為例它的做法是在原始權(quán)重矩陣旁邊新增兩個(gè)低秩矩陣訓(xùn)練時(shí)只更新這兩個(gè)矩陣。# 示意LoRA 的更新邏輯簡(jiǎn)化版 # 原始公式output W * input # LoRA 公式output (W A B) * input # 其中 W 被凍結(jié)A 和 B 是低秩矩陣秩為 r import torch import torch.nn as nn class LoRALinear(nn.Module): def __init__(self, in_features, out_features, r16): super().__init__() self.weight nn.Parameter(torch.randn(out_features, in_features)) self.weight.requires_grad False # 凍結(jié)原權(quán)重 self.lora_a nn.Parameter(torch.randn(in_features, r) * 0.01) self.lora_b nn.Parameter(torch.randn(r, out_features) * 0.01) def forward(self, x): # 原始輸出 低秩增量 base_out x self.weight.T lora_out (x self.lora_a) self.lora_b return base_out lora_outLoRA 的核心優(yōu)勢(shì)是顯存占用小、訓(xùn)練速度快同時(shí)可以通過切換不同的 LoRA 權(quán)重實(shí)現(xiàn)多任務(wù)適配很適合在單卡環(huán)境下做垂直領(lǐng)域探索。3.2 VLM 推理從圖像到文字的基本鏈路VLM 的推理鏈路通常包含三個(gè)部分視覺編碼器Vision Encoder把圖像轉(zhuǎn)換為視覺令牌visual tokens。投影層Projection Layer把視覺特征映射到語言模型的嵌入空間。語言模型Language Model結(jié)合文本提示詞和視覺令牌逐步生成回答。理解這條鏈路很重要因?yàn)楹笥?xùn)練通常需要決定“改哪一部分”。如果任務(wù)主要是理解圖像語義視覺編碼器可以凍結(jié)只微調(diào)語言模型如果任務(wù)涉及特殊的圖像特征例如紅外波段或高空俯拍視角則需要考慮是否解凍視覺編碼器。# 一個(gè)標(biāo)準(zhǔn)的 VLM 推理調(diào)用流程 from transformers import AutoProcessor, AutoModelForVision2Seq from PIL import Image model_id your-finetuned-model-path processor AutoProcessor.from_pretrained(model_id) model AutoModelForVision2Seq.from_pretrained(model_id) image Image.open(test_frame.jpg) prompt Describe the traffic status in this image. inputs processor(imagesimage, textprompt, return_tensorspt) outputs model.generate(**inputs, max_new_tokens256) print(processor.decode(outputs[0], skip_special_tokensTrue))這段代碼把圖像和文本提示詞送入模型模型輸出文本描述。這里的processor負(fù)責(zé)將圖像和文本轉(zhuǎn)換成模型需要的張量格式。3.3 Cosmos 合成數(shù)據(jù)生成的工作流Cosmos 3 生成合成數(shù)據(jù)的工作流可以概括為文本描述 條件控制 → 視頻生成 → 抽幀標(biāo)注 → 數(shù)據(jù)集構(gòu)建。其中文本描述的質(zhì)量直接影響生成效果。為了生成符合農(nóng)業(yè)機(jī)器人視角的數(shù)據(jù)需要在提示詞中明確以下信息相機(jī)視角第一人稱、第三人稱、固定視角等。場(chǎng)景內(nèi)容農(nóng)作物種類、成熟度、病蟲害特征。運(yùn)動(dòng)行為機(jī)械臂運(yùn)動(dòng)、果實(shí)抓取、自主移動(dòng)等。環(huán)境條件光照、天氣、季節(jié)。下面是一個(gè)雙語提示詞模板English prompt: A first-person view from an agricultural robot moving between tomato rows. The robotic arm extends forward and gently picks a ripe red tomato. Natural sunlight, slight shadow on the left side, leaves are green and healthy. 中文提示詞 農(nóng)業(yè)機(jī)器人第一人稱視角在番茄種植行中移動(dòng)。 機(jī)械臂向前伸展輕輕摘取一顆成熟的紅色番茄。 自然光照左側(cè)有輕微陰影葉片翠綠健康。建議在合成數(shù)據(jù)生成時(shí)將英文提示詞作為主輸入中文提示詞作為輔助描述這樣可以在一定程度上提高生成結(jié)果與中文標(biāo)注的一致性。3.4 圖像批量推理的效率問題在智慧城市場(chǎng)景中VLM 推理往往需要處理大量圖像比如每隔幾秒從視頻流中抽幀檢測(cè)一次。如果逐張圖像調(diào)用模型耗時(shí)較長(zhǎng)也不利于 GPU 利用率。常見的做法是批量推理batch inference將多張圖像組成一個(gè) batch 送入模型。# 圖像批量推理的常見思路 from PIL import Image import torch images [Image.open(fframes/frame_{i:04d}.jpg) for i in range(1, 9)] prompts [Describe the traffic condition.] * len(images) inputs processor( imagesimages, textprompts, return_tensorspt, paddingTrue, ) with torch.no_grad(): outputs model.generate(**inputs, max_new_tokens128)批量推理的核心收益是提高 GPU 利用率減少推理總時(shí)間。但它也有代價(jià)batch 中不同圖像的 token 長(zhǎng)度不同模型需要做 padding在處理超長(zhǎng)視頻抽幀時(shí)可能遇到顯存壓力。后續(xù)在“常見問題”章節(jié)會(huì)進(jìn)一步展開。4. 完整實(shí)戰(zhàn)從合成數(shù)據(jù)生成到 VLM 后訓(xùn)練與推理下面進(jìn)入本文的核心實(shí)戰(zhàn)。整個(gè)流程分為五個(gè)步驟每一部分都提供完整代碼和運(yùn)行說明。4.1 準(zhǔn)備智慧城市監(jiān)控?cái)?shù)據(jù)先準(zhǔn)備一組智慧城市場(chǎng)景的真實(shí)圖像。出于示例目的我們假設(shè)你有少量來自公開數(shù)據(jù)集的圖像和標(biāo)注。你可以先創(chuàng)建data/real目錄并準(zhǔn)備如下格式的標(biāo)注文件data/annotations/real_annotations.json[ { filename: frame_001.jpg, question: 這段路口有哪些交通參與者, answer: 畫面中有兩輛直行的小汽車、一輛左轉(zhuǎn)的電動(dòng)車以及一名正在斑馬線旁等候的行人。 }, { filename: frame_002.jpg, question: 是否有車輛違規(guī), answer: 沒有。所有車輛均在車道線內(nèi)行駛行人信號(hào)燈為綠色通行狀態(tài)正常。 } ]然后運(yùn)行下面的數(shù)據(jù)準(zhǔn)備腳本將標(biāo)注轉(zhuǎn)換為后訓(xùn)練所需的統(tǒng)一格式# 文件路徑scripts/prepare_dataset.py import json import os import argparse def build_dataset(image_dir, annotation_file, output_file): # 讀取原始標(biāo)注 with open(annotation_file, r, encodingutf-8) as f: annotations json.load(f) samples [] for item in annotations: # 每個(gè)樣本包含圖像路徑和一輪對(duì)話 samples.append({ images: [os.path.join(image_dir, item[filename])], conversations: [ { role: user, content: item[question] }, { role: assistant, content: item[answer] } ] }) with open(output_file, w, encodingutf-8) as f: json.dump(samples, f, ensure_asciiFalse, indent2) print(f[INFO] Dataset ready, total {len(samples)} samples.) if __name__ __main__: parser argparse.ArgumentParser() parser.add_argument(--image_dir, typestr, defaultdata/real) parser.add_argument(--annotation_file, typestr, defaultdata/annotations/real_annotations.json) parser.add_argument(--output_file, typestr, defaultdata/dataset_real.json) args parser.parse_args() build_dataset(args.image_dir, args.annotation_file, args.output_file)運(yùn)行python scripts/prepare_dataset.py如果看到Dataset ready, total 2 samples.說明真實(shí)數(shù)據(jù)準(zhǔn)備完成。在實(shí)際項(xiàng)目中樣本數(shù)量建議至少在數(shù)百條以上否則后訓(xùn)練效果非常有限。4.2 用 Cosmos 生成農(nóng)業(yè)機(jī)器人合成數(shù)據(jù)接下來使用 Cosmos 3 生成農(nóng)業(yè)機(jī)器人場(chǎng)景的合成視頻。由于不同版本的 Cosmos 對(duì)模型導(dǎo)入方式和推理接口差異較大下面的代碼是演示思路具體 API 名稱需要參考你部署的官方文檔。# 文件路徑scripts/generate_synthetic.py # 演示代碼實(shí)際接口請(qǐng)參考 Cosmos 官方倉(cāng)庫 import os import json from PIL import Image # 假設(shè) Cosmos 提供了一個(gè)生成器對(duì)象 # 這里用注釋說明初始化方式不綁定具體類名 # from cosmos import CosmosVideoGenerator def generate_agriculture_frame(prompt_en, prompt_zh, save_dir): 使用 Cosmos 生成農(nóng)業(yè)機(jī)器人視角的視頻幀。 參數(shù): prompt_en: 英文提示詞 prompt_zh: 中文提示詞 save_dir: 輸出目錄 # 1. 構(gòu)造生成請(qǐng)求 generation_prompt f{prompt_en}. {prompt_zh} # 2. 調(diào)用 Cosmos 生成視頻 # generator CosmosVideoGenerator.from_pretrained(nvidia/cosmos-3-wfm) # output_video generator.generate( # promptgeneration_prompt, # duration3.0, # 生成 3 秒視頻 # height720, # width1280, # fps30 # ) # 3. 將視頻流抽幀保存為 JPEG 圖像 # frames extract_frames(output_video) # 這里僅做目錄初始化 os.makedirs(save_dir, exist_okTrue) # 4. 記錄對(duì)應(yīng)的文本描述 annotation { prompt_en: prompt_en, prompt_zh: prompt_zh, scene: agriculture_robot, frames: [ # 假設(shè)抽幀后得到 10 幀 fsynthetic_agri_001_frame_{i:02d}.jpg for i in range(10) ] } with open(os.path.join(save_dir, annotation.json), w, encodingutf-8) as f: json.dump(annotation, f, ensure_asciiFalse, indent2) print(f[INFO] Synthetic data saved to {save_dir}) if __name__ __main__: save_dir data/synthetic/agriculture_01 generate_agriculture_frame( prompt_enFirst-person view of an agricultural robot in a tomato greenhouse, a robotic arm reaches out and gently picks a ripe tomato, natural light., prompt_zh農(nóng)業(yè)機(jī)器人第一人稱視角在番茄溫室中機(jī)械臂伸出并輕輕摘取一顆成熟的番茄自然光照。, save_dirsave_dir )你需要根據(jù)實(shí)際模型版本替換初始化與生成邏輯。生成后的視頻幀可以繼續(xù)用作圖像級(jí) VLM 后訓(xùn)練數(shù)據(jù)也可以保留視頻序列用于后續(xù)世界模型訓(xùn)練或行為預(yù)測(cè)任務(wù)。4.3 構(gòu)建混合后訓(xùn)練數(shù)據(jù)集合成數(shù)據(jù)與真實(shí)數(shù)據(jù)需要統(tǒng)一格式才能送入訓(xùn)練腳本。這里寫一個(gè)融合腳本將真實(shí)數(shù)據(jù)集和合成數(shù)據(jù)集合并并寫入訓(xùn)練集與驗(yàn)證集。# 文件路徑scripts/merge_datasets.py import json import random import argparse def load_json(path): with open(path, r, encodingutf-8) as f: return json.load(f) def split_dataset(samples, val_ratio0.2): random.shuffle(samples) val_size int(len(samples) * val_ratio) train_set samples[val_size:] val_set samples[:val_size] return train_set, val_set if __name__ __main__: parser argparse.ArgumentParser() parser.add_argument(--real_data, typestr, defaultdata/dataset_real.json) parser.add_argument(--synthetic_data, typestr, defaultdata/dataset_synthetic.json) parser.add_argument(--output_train, typestr, defaultdata/dataset_train.json) parser.add_argument(--output_val, typestr, defaultdata/dataset_val.json) parser.add_argument(--val_ratio, typefloat, default0.2) args parser.parse_args() real_samples load_json(args.real_data) synthetic_samples load_json(args.synthetic_data) all_samples real_samples synthetic_samples train_set, val_set split_dataset(all_samples, args.val_ratio) with open(args.output_train, w, encodingutf-8) as f: json.dump(train_set, f, ensure_asciiFalse, indent2) with open(args.output_val, w, encodingutf-8) as f: json.dump(val_set, f, ensure_asciiFalse, indent2) print(f[INFO] Train samples: {len(train_set)}, Val samples: {len(val_set)})合并數(shù)據(jù)的比例需要根據(jù)實(shí)際情況調(diào)整。如果合成數(shù)據(jù)出現(xiàn)明顯重復(fù)模式應(yīng)該適度降低合成數(shù)據(jù)占比避免模型對(duì)合成數(shù)據(jù)過擬合。4.4 LoRA 微調(diào) VLM下面使用 PEFT 庫對(duì) VLM 做 LoRA 后訓(xùn)練。示例中使用的是 Hugging Face 生態(tài)的AutoModelForVision2Seq你可以替換成自己選定的 VLM 基座模型。# 文件路徑scripts/train_lora.py import json import torch from transformers import ( AutoProcessor, AutoModelForVision2Seq, TrainingArguments, Trainer, DataCollatorForLanguageModeling, ) from peft import LoraConfig, get_peft_model, prepare_model_for_kbit_training from PIL import Image from torch.utils.data import Dataset class VLMDataset(Dataset): 讀取統(tǒng)一格式的 VLM 對(duì)話數(shù)據(jù)集。 def __init__(self, json_path, processor): self.data json.load(open(json_path, r, encodingutf-8)) self.processor processor def __len__(self): return len(self.data) def __getitem__(self, idx): item self.data[idx] image_path item[images][0] conversations item[conversations] user_text conversations[0][content] assistant_text conversations[1][content] image Image.open(image_path).convert(RGB) # 構(gòu)造模型輸入 messages [ {role: user, content: user_text}, {role: assistant, content: assistant_text}, ] text self.processor.apply_chat_template( messages, tokenizeFalse, add_generation_promptFalse ) inputs self.processor( imagesimage, texttext, return_tensorspt, paddingTrue, ) # 移除 batch 維度簡(jiǎn)化 item 結(jié)構(gòu) return { pixel_values: inputs[pixel_values][0], input_ids: inputs[input_ids][0], attention_mask: inputs[attention_mask][0], } def collate_fn(batch): 動(dòng)態(tài) padding 到 batch 內(nèi)最大長(zhǎng)度。 pixel_values torch.stack([b[pixel_values] for b in batch]) input_ids torch.nn.utils.rnn.pad_sequence( [b[input_ids] for b in batch], batch_firstTrue, padding_value0 ) attention_mask torch.nn.utils.rnn.pad_sequence( [b[attention_mask] for b in batch], batch_firstTrue, padding_value0 ) return { pixel_values: pixel_values, input_ids: input_ids, attention_mask: attention_mask, } def main(): model_id your-base-vlm-id # 例如 meta-llama/Llama-3.2-11B-Vision-Instruct train_json data/dataset_train.json val_json data/dataset_val.json processor AutoProcessor.from_pretrained(model_id) model AutoModelForVision2Seq.from_pretrained( model_id, torch_dtypetorch.bfloat16, device_mapauto, ) # 配置 LoRA lora_config LoraConfig( r16, lora_alpha32, lora_dropout0.05, target_modules[q_proj, v_proj, k_proj, o_proj], task_typeCAUSAL_LM, ) model prepare_model_for_kbit_training(model) model get_peft_model(model, lora_config) model.print_trainable_parameters() train_dataset VLMDataset(train_json, processor) val_dataset VLMDataset(val_json, processor) training_args TrainingArguments( output_diroutput/logs/, per_device_train_batch_size2, per_device_eval_batch_size2, gradient_accumulation_steps4, learning_rate2e-4, num_train_epochs3, logging_steps10, eval_strategysteps, eval_steps100, save_steps100, remove_unused_columnsFalse, report_totensorboard, ) trainer Trainer( modelmodel, argstraining_args, train_datasettrain_dataset, eval_datasetval_dataset, data_collatorcollate_fn, ) trainer.train() # 保存 LoRA 權(quán)重和處理器 model.save_pretrained(models/finetuned/lora_weights) processor.save_pretrained(models/finetuned/lora_weights) if __name__ __main__: main()這段代碼有幾個(gè)關(guān)鍵點(diǎn)需要注意VLMDataset里使用了apply_chat_template不同模型對(duì)對(duì)話模板的處理方式不同。collate_fn負(fù)責(zé)動(dòng)態(tài) padding確保不同長(zhǎng)度的輸入可以在一個(gè) batch 內(nèi)計(jì)算。LoRA 的target_modules需要與模型結(jié)構(gòu)匹配。如果模型使用了不同的線性層命名需要調(diào)整。4.5 智慧城市 VLM 推理完成 LoRA 后訓(xùn)練后將 LoRA 權(quán)重加載到預(yù)訓(xùn)練模型上對(duì)智慧城市場(chǎng)景的圖像進(jìn)行推理。# 文件路徑scripts/inference.py import torch from transformers import AutoProcessor, AutoModelForVision2Seq from peft import PeftModel from PIL import Image def load_finetuned_model(base_model_id, lora_path): processor AutoProcessor.from_pretrained(lora_path) model AutoModelForVision2Seq.from_pretrained( base_model_id, torch_dtypetorch.bfloat16, device_mapauto, ) model PeftModel.from_pretrained(model, lora_path) model.eval() return processor, model def infer_image(processor, model, image_path, prompt): image Image.open(image_path).convert(RGB) inputs processor(imagesimage, textprompt, return_tensorspt).to(model.device) with torch.no_grad(): outputs model.generate( **inputs, max_new_tokens256, do_sampleFalse, ) result processor.decode(outputs[0], skip_special_tokensTrue) return result if __name__ __main__: base_model_id your-base-vlm-id lora_path models/finetuned/lora_weights processor, model load_finetuned_model(base_model_id, lora_path) # 分別測(cè)試智慧城市和農(nóng)業(yè)場(chǎng)景 test_cases [ (data/real/frame_001.jpg, 描述該路口的交通參與者及通行狀態(tài)。), (data/synthetic/agriculture_01/annotation.json_frame_00.jpg, 判斷番茄果實(shí)是否成熟。), ] for image_path, prompt in test_cases: result infer_image(processor, model, image_path, prompt) print(fImage: {image_path}) print(fPrompt: {prompt}) print(fResult: {result}) print(- * 60)輸出示例Image: data/real/frame_001.jpg Prompt: 描述該路口的交通參與者及通行狀態(tài)。 Result: 畫面中有兩輛直行的小汽車、一輛左轉(zhuǎn)的電動(dòng)車以及一名正在斑馬線旁等候的行人。4.6 運(yùn)行與驗(yàn)證依次執(zhí)行以下命令即可完整復(fù)現(xiàn)本文流程# 1. 準(zhǔn)備真實(shí)數(shù)據(jù) python scripts/prepare_dataset.py # 2. 生成合成數(shù)據(jù)需要 Cosmos 環(huán)境 python scripts/generate_synthetic.py # 3. 合并數(shù)據(jù)集 python scripts/merge_datasets.py # 4. 后訓(xùn)練 python scripts/train_lora.py # 5. 推理驗(yàn)證 python scripts/inference.py如果使用的是自己的模型路徑需要修改腳本中的model_id、base_model_id等參數(shù)。后訓(xùn)練過程中建議保存訓(xùn)練日志方便后續(xù)定位是否過擬合或欠擬合。5. 常見問題與排查思路在實(shí)際運(yùn)行過程中常見問題集中在環(huán)境依賴、數(shù)據(jù)格式、顯存限制和推理結(jié)果異常幾個(gè)方面。下面用表格整理排查思路。問題現(xiàn)象常見原因解決思路nvidia-smi不可用WSL2 未啟用 GPU 或驅(qū)動(dòng)版本過低更新 Windows 驅(qū)動(dòng)確保 WSL2 內(nèi)執(zhí)行nvidia-smi正常導(dǎo)入 Cosmos 包報(bào)錯(cuò)官方庫名或依賴與版本不匹配查閱官方文檔確認(rèn)安裝命令檢查 Python 版本模型加載 CUDA out of memory顯存不足降低 batch size開啟 gradient_accumulation_steps或使用更小基座模型推理結(jié)果與預(yù)期差距大數(shù)據(jù)標(biāo)注質(zhì)量差或訓(xùn)練輪次過多檢查訓(xùn)練集標(biāo)注一致性觀察驗(yàn)證集損失降低 epoch 或?qū)W習(xí)率中文輸出質(zhì)量不穩(wěn)定基座模型中文能力有限替換中文能力更強(qiáng)的基座模型或增加中文示例在訓(xùn)練集中的占比批量推理時(shí) padding 導(dǎo)致結(jié)果異常不同輸入長(zhǎng)度差異大使用模型自帶的動(dòng)態(tài) padding或在構(gòu)建 batch 時(shí)按長(zhǎng)度排序LoRA 訓(xùn)練后模型輸出亂碼target_modules與模型結(jié)構(gòu)不匹配檢查模型參數(shù)名確認(rèn)q_proj、v_proj等名稱是否存在合成數(shù)據(jù)與真實(shí)數(shù)據(jù)風(fēng)格差異過大提示詞未覆蓋目標(biāo)場(chǎng)景加入更多環(huán)境、光照、相機(jī)參數(shù)描述生成后進(jìn)行人工篩選5.1 顯存不足的排查示例顯存不足是最常見的問題。先通過nvidia-smi查看占用情況nvidia-smi如果看到類似CUDA out of memory的錯(cuò)誤依次嘗試減小per_device_train_batch_size從 2 調(diào)整到 1。開啟gradient_accumulation_steps8保證有效 batch size 不變。使用bf16或fp16混合精度訓(xùn)練。對(duì)視頻抽幀時(shí)降低圖像分辨率例如從 1280x720 降到 640x360。5.2 推理加速的常見手段智慧城市場(chǎng)景對(duì)推理延遲有較高要求。這里給出幾種常見的推理加速手段不同方法的收益和復(fù)雜度不同。方法 1批量推理Batch Inference 適用離線批量抽幀檢測(cè) 收益提高 GPU 利用率 方法 2TensorRT / 模型編譯 適用服務(wù)化部署、線上推理 收益顯著降低單次推理延遲 注意需要針對(duì)具體模型與 GPU 做轉(zhuǎn)換 方法 3圖編譯Graph Compiler 適用PyTorch 生態(tài)下的動(dòng)態(tài)圖模型 收益減少算子調(diào)度開銷 注意可能與動(dòng)態(tài) video 輸入存在兼容問題 方法 4減小輸入尺寸 / 降低幀率 適用視頻流場(chǎng)景 收益直接減少計(jì)算量 注意需要評(píng)估精度損失關(guān)于 TensorRT 部署需要說明的是具體安裝方式和可支持的算子版本變化較快建議以官方部署文檔為準(zhǔn)。不要盲目追求把全部模型轉(zhuǎn)成 TensorRT圖編譯和批量推理往往已經(jīng)能帶來可觀的收益。6. 最佳實(shí)踐與工程建議6.1 合成數(shù)據(jù)質(zhì)量控制合成數(shù)據(jù)不是“生成多少用多少”必須經(jīng)過質(zhì)量篩。建議記錄每段生成視頻的提示詞、生成參數(shù)和標(biāo)注來源并通過可視化工具抽幀審查。建議建立如下篩選流程自動(dòng)過濾去掉黑幀、重復(fù)幀、畫面異常的視頻。規(guī)則校驗(yàn)利用目標(biāo)檢測(cè)模型檢查關(guān)鍵物體是否存在例如“畫面中是否出現(xiàn)番茄”。人工抽檢隨機(jī)抽 10% 左右的樣本由人工確認(rèn)語義一致性。標(biāo)注校準(zhǔn)如果 Cosmos 生成結(jié)果與文本描述不一致需要修正標(biāo)注或丟棄樣本。6.2 后訓(xùn)練數(shù)據(jù)混合策略真實(shí)數(shù)據(jù)與合成數(shù)據(jù)的比例需要謹(jǐn)慎控制。一般來說如果合成數(shù)據(jù)與真實(shí)場(chǎng)景分布差距較大合成數(shù)據(jù)占比過高會(huì)導(dǎo)致模型在真實(shí)數(shù)據(jù)上反而變差。一個(gè)比較穩(wěn)妥的做法是訓(xùn)練集 80% 真實(shí)數(shù)據(jù) 20% 合成數(shù)據(jù) 驗(yàn)證集 100% 真實(shí)數(shù)據(jù)先用這個(gè)比例評(píng)估再根據(jù)驗(yàn)證集表現(xiàn)逐步調(diào)整。如果合成數(shù)據(jù)覆蓋了真實(shí)場(chǎng)景缺乏的長(zhǎng)尾情況可以適當(dāng)提高比例。6.3 后訓(xùn)練超參數(shù)調(diào)優(yōu)建議超參數(shù)建議范圍說明LoRA rank8 ~ 32rank 越大表達(dá)能力越強(qiáng)但顯存占用也更高learning rate1e-5 ~ 5e-4視覺語言模型微調(diào)通常比純文本模型更小的學(xué)習(xí)率batch size1 ~ 8根據(jù)顯存調(diào)整配合梯度累積epoch2 ~ 5從 2 開始觀察驗(yàn)證集損失防止過擬合warmup ratio0.03 ~ 0.1避免訓(xùn)練初期不穩(wěn)定6.4 安全與合規(guī)邊界在智慧城市場(chǎng)景中處理視頻數(shù)據(jù)時(shí)要特別注意隱私和合規(guī)問題。實(shí)際項(xiàng)目中建議做到以下幾點(diǎn)對(duì)涉及個(gè)人的視頻幀做匿名化處理例如人臉模糊、車牌脫敏。只在授權(quán)范圍內(nèi)采集和使用真實(shí)數(shù)據(jù)。使用 Cosmos 生成合成數(shù)據(jù)時(shí)保留提示詞和生成參數(shù)方便追溯數(shù)據(jù)來源。對(duì)外發(fā)布模型權(quán)重時(shí)檢查基座模型的許可協(xié)議是否允許二次分發(fā)。7. 總結(jié)與下一步學(xué)習(xí)路線到這里我們完整走通了一條“Cosmos 3 合成數(shù)據(jù)生成 → VLM 后訓(xùn)練 → 智慧城市推理”的技術(shù)鏈路。你掌握的是一套可以復(fù)用到多個(gè)物理 AI 場(chǎng)景的實(shí)驗(yàn)流程而不只是某個(gè)具體項(xiàng)目的配置。下一步可以從這幾個(gè)方向繼續(xù)深入把合成視頻從單一視角擴(kuò)展到多相機(jī)視角研究世界模型中的 3D 一致性問題。對(duì)比不同后訓(xùn)練方法SFT、LoRA、DPO在垂直場(chǎng)景中的效果差異。嘗試把后訓(xùn)練好的 VLM 接入實(shí)際機(jī)器人控制鏈路用人類反饋進(jìn)一步優(yōu)化行為策略。研究推理加速方案將模型部署到邊緣端服務(wù)于實(shí)時(shí)智慧城市監(jiān)控。實(shí)際項(xiàng)目中優(yōu)先關(guān)注數(shù)據(jù)質(zhì)量和評(píng)估指標(biāo)不要一上來就追求大模型。合成數(shù)據(jù)幫你拓寬數(shù)據(jù)邊界后訓(xùn)練幫你對(duì)齊業(yè)務(wù)需求VLM 推理幫你把能力落到具體應(yīng)用中三步缺一不可。希望這篇文章能幫你少踩一些坑也歡迎在評(píng)論區(qū)交流你的實(shí)測(cè)結(jié)果。