news 2026/9/18 3:50:46

vLLM-Omni 运行 ByteDance Lance:统一 AR + 扩散多模态 3B 模型的离线推理与在线服务实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
vLLM-Omni 运行 ByteDance Lance:统一 AR + 扩散多模态 3B 模型的离线推理与在线服务实战

vLLM-Omni 运行 ByteDance Lance:统一 AR + 扩散多模态 3B 模型的离线推理与在线服务实战

【免费下载链接】vllm-omniA framework for efficient model inference with omni-modality models项目地址: https://gitcode.com/GitHub_Trending/vl/vllm-omni

本文基于仓库 recipes/ByteDance/Lance.md 编写。Lance 是字节跳动开源的 3B 统一自回归(AR)+ 扩散多模态模型,在 Qwen2.5-VL 骨干上同时支持文生图、图生图、文生视频、视频编辑以及图像/视频理解六类单阶段任务。通过本文你可以掌握:在 vLLM-Omni 中完成 Lance 的环境准备、六类任务的离线推理命令、采样与扩散参数调优,以及基于 OpenAI 兼容 API 的在线服务部署与客户端调用,并了解其背后"复用 BAGEL 变换器核心、特化 ViT/VAE/检查点布局"的实现原理。

一、Lance 模型是什么

Lance(bytedance-research/Lance)是一个3B 规模的统一自回归 + 扩散多模态模型,采用 Qwen2.5-VL 骨干(backbone),一次加载即可覆盖文本、图像、视频三类模态的生成与理解任务:

  • text2img:文生图
  • text2video:文生视频
  • img2img(image edit):图生图 / 图像编辑
  • video2video(video edit):视频编辑
  • img2text(image understanding):图像理解(caption / VQA)
  • video2text(video understanding):视频理解

在 vLLM-Omni 中,Lance 属于BAGEL 血缘(BAGEL-lineage)模型:其发布的检查点与 BAGEL 使用相同的*_moe_genMixture-of-Transformers(MoT)权重布局,因此 vLLM-Omni 直接复用 BAGEL 的变换器核心,仅针对三处做特化:

  1. 视觉编码器(ViT):改用 Qwen2.5-VL 视觉塔(而非 BAGEL 的 SigLIP);
  2. 变分自编码器(VAE):改用 Wan2.2(Wan2.2_VAE.pth,而非 BAGEL 自带的 autoencoder);
  3. 检查点布局:适配 HuggingFace 仓库内多子目录的打包结构。

从源码看,vllm_omni/diffusion/models/lance/pipeline_lance.py中的LancePipeline直接继承自BagelPipeline,其文档字符串明确指出:"只有模型构建过程不同,且仅局限于三个位置"——检查点布局、理解用 ViT、VAE。生成/前向机制整体原样复用 BAGEL,这也是整个集成能快速落地的基础。

模型仓库结构

HuggingFace 仓库bytedance-research/Lance将全部权重打包在一个仓库内,无需额外下载:

  • Lance_3B/:图像路径对应的 LLM 检查点;
  • Lance_3B_Video/:视频路径所需的 LLM 检查点(含 3-Dlatent_pos_embed位置嵌入表);
  • Qwen2.5-VL-ViT/:图像/视频理解所需的视觉塔(vit.safetensors);
  • Wan2.2_VAE.pth:Wan2.2 VAE 权重。

与 BAGEL 不同,Lance 的 HuggingFaceconfig.json只是描述性元数据(没有model_type字段),加载器无法仅凭模型目录自动探测管线类型,因此 vLLM-Omni 通过部署配置显式指定pipeline: lance(见下文"在线服务"一节)。

检查点与管线形态

  • 六类单阶段任务Lance_3B检查点上全部支持;
  • text2video 与 video2video额外需要Lance_3B_Video子检查点,用于加载 3-Dlatent_pos_embed表(形状(126976, 2048));
  • 两阶段 AR + DiT 拓扑(AR thinker + diffusion transformer)当前暂未启用,需要LanceConfig/LanceProcessorvllm包中完成注册(属于独立的上游 PR)。

二、硬件与运行环境

  • 操作系统:Linux
  • Python:3.12
  • 驱动 / 运行时:CUDA ≥ 12.4
  • vLLM-Omni 版本:0.18.x.dev
  • GPU:单卡 16 GB+ 显存(BF16)即可运行Lance_3B,官方验证环境为 NVIDIA B300 / A100 80GB

显存占用参考(BF16):LLM + Qwen2.5-VL ViT + Wan2.2 VAE 合计约7 GB,单卡 16 GB 以上即可舒适运行Lance_3B

三、离线推理:六类任务的完整命令

离线推理统一入口是 examples/offline_inference/lance/end2end.py,通过--modality切换任务类型。脚本内部会:

  1. render_lance_prompt按 Qwen chat 模板包装提示词,并用<|vision_start|><|video_pad|><|vision_end|>视觉块占位;
  2. 构造Omni引擎(单阶段扩散,无需 deploy YAML,pipelineenforce_eagertrust_remote_codemax_num_seqs=1等以平铺 kwargs 传入);
  3. --steps--cfg-text-scale--timestep-shift等写入扩散采样参数,调用omni.generate(...)
  4. 图像输出保存为 PNG,视频输出编码为 MP4(fps参数控制帧率,默认 12,与上游 Lance 的save_fps=12一致;MP4 编码失败时回退为逐帧 PNG 落盘)。

3.1 文生图(text2img,默认)

python examples/offline_inference/lance/end2end.py \ --model bytedance-research/Lance \ --prompts "a corgi astronaut on the moon, cinematic" \ --steps 30 --cfg-text-scale 4.0 --timestep-shift 3.5 \ --height 1024 --width 1024 \ --seed 42 --output ./out

默认值与上游inference_lance.sh保持一致:30 步去噪、timestep-shift 3.5、文本 CFG 4.0、seed 42、1024×1024。可通过--height/--width覆盖分辨率;--height/--width未指定时默认取max_hw(1024)。

3.2 图像编辑(img2img)

python examples/offline_inference/lance/end2end.py \ --model bytedance-research/Lance --modality img2img \ --image-path /path/to/input.png \ --prompts "Convert this into a vibrant cartoon-style illustration" \ --steps 30 --cfg-text-scale 4.0 --timestep-shift 3.5 \ --output ./out

关键原理:Lance 原生 VAE prefill 会把 Wan2.2 潜变量(latents)散列(scatter)进 LLM 的 query 序列,无需额外的独立图像编码器。输入图片经 PIL 打开为 RGB 后,通过multi_modal_data: {"img2img": img}传入,提示词以image_edit任务渲染。

3.3 文生视频(text2video)

python examples/offline_inference/lance/end2end.py \ --model bytedance-research/Lance/Lance_3B_Video --modality text2video \ --num-frames 25 --video-height 480 --video-width 768 \ --prompts "a cat playing piano, cinematic" \ --steps 30 --fps 8 --output ./out
  • --num-frames:RGB 帧数(默认 25,上限 121);
  • --video-height/--video-width:视频帧分辨率(默认 480×768)。

任何视频路径都必须显式指定Lance_3B_Video子检查点,以加载 3-Dlatent_pos_embed表。若仅指向顶层仓库,vllm-omni 会静默加载图像版表(形状(4096, 2048)),一旦t_lat >= 1立即越界报错。离线脚本对此做了防御:当--modalitytext2video/video2video/video2text/image2video时,若模型路径不以Lance_3B_Video结尾且本地存在该子目录,会自动改写模型路径。

3.4 图像 / 视频理解(img2text / video2text)

# Image → text(caption / VQA) python examples/offline_inference/lance/end2end.py \ --model bytedance-research/Lance --modality img2text \ --image-path /path/to/photo.jpg \ --prompts "Describe this image in detail." \ --do-sample --text-temperature 0.8 # Video → text python examples/offline_inference/lance/end2end.py \ --model bytedance-research/Lance --modality video2text \ --video-path /path/to/clip.mp4 \ --prompts "What is happening in this video?"

理解路径默认开启采样--do-sample默认True),--text-temperature 0.8。原因在源码注释中写得很清楚:Lance 的贪心解码器对许多提示词会立即输出 EOS,温度低于约 0.7 时同样容易提前结束,0.8 是一个可靠默认值。可用--no-sample关闭采样(贪心解码),用--max-text-tokens(默认 512)控制生成文本最大 token 数。

理解路径的system_prompt可通过--system-prompt覆盖。源码指出:x2t 路径默认使用 caption 风格的系统提示("Generate a detailed and accurate description of the image/video..."),如果不提供 system prompt,模型会倾向于描述而非按指令回答;例如希望模型回答具体问题时,可传入"Look at the image carefully and answer the question."之类的 per-example QA 指令。

3.5 额外能力:image2video 与 video2video

离线脚本还支持image2video(图像 + 文本 → 长视频)与video2video(视频编辑):

# 图像生成视频(不锁首帧:图片作为 1 帧参考,VAE+ViT prefill 后生成全新多帧视频) python examples/offline_inference/lance/end2end.py \ --model bytedance-research/Lance/Lance_3B_Video --modality image2video \ --image-path /path/to/image.png \ --prompts "a corgi walking on the moon" \ --num-frames 25 --video-height 480 --video-width 768 \ --output ./out

image2video通过multi_modal_data: {"first_frame": img}传入参考帧,提示词以i2v任务渲染(复用 t2v 的系统提示词池);video2video通过multi_modal_data: {"video": video_path}传入源视频,以video_edit任务渲染。

3.6 提示词渲染机制(源码视角)

vllm_omni/diffusion/models/lance/prompts.py 定义了与上游 Lance 训练分布完全一致的提示词格式:

  • 每个任务有专属系统提示词(SYSTEM_PROMPTS字典),描述应关注的内容要素(颜色、数量、文字、形状、尺寸、纹理、物体与背景的空间关系、运动/镜头移动等);
  • 提示词按 Qwen chat 模板包装:<|im_start|>system\n…<|im_end|>\n<|im_start|>user\n…<|im_end|>\n<|im_start|>assistant\n
  • 视觉内容占位符为<|vision_start|><|video_pad|><|vision_end|>——与直觉相反,即使输入是图像,上游 Lance 默认也使用<|video_pad|>(除非设置force_video_pad=False),vLLM-Omni 忠实复刻了这一行为。

四、在线服务:OpenAI 兼容 API

Lance 的所有单阶段模态均通过 OpenAI 兼容的/v1/chat/completionsAPI 提供在线服务。

4.1 启动服务

一键启动脚本为 examples/online_serving/lance/run_server.sh:

bash examples/online_serving/lance/run_server.sh # 或带覆盖参数 MODEL=bytedance-research/Lance \ DEPLOY_CONFIG=vllm_omni/deploy/lance.yaml \ PORT=8091 \ bash examples/online_serving/lance/run_server.sh

脚本内部执行的是vllm serve "$MODEL" --omni --deploy-config "$DEPLOY_CONFIG" --port "$PORT"。三个环境变量的默认值分别为:MODEL=bytedance-research/LanceDEPLOY_CONFIG=vllm_omni/deploy/lance.yamlPORT=8091

若运行text2video/video2video,设置MODEL=bytedance-research/Lance/Lance_3B_Video

4.2 部署配置解读

vllm_omni/deploy/lance.yaml 是单阶段扩散管线选择器,全文如下:

# Lance(ByteDance)— single-stage diffusion pipeline selector. pipeline: lance async_chunk: false stages: - stage_id: 0 max_num_batched_tokens: 32768 max_num_seqs: 1 enforce_eager: true trust_remote_code: true enable_prefix_caching: false devices: "0" default_sampling_params: seed: 42

关键点:

  • pipeline: lance:因为 Lance 的 HFconfig.jsonmodel_type,加载器无法自动探测,必须显式声明使用 Lance 管线;单阶段、无多阶段编排
  • max_num_batched_tokens: 32768max_num_seqs: 1:单序列大 batch 的扩散推理特征;
  • enforce_eager: true:禁用图编译,配合扩散模型动态形状;
  • trust_remote_code: true:允许加载远程代码;
  • enable_prefix_caching: falseasync_chunk: false:单条请求场景下关闭前缀缓存与异步分块。

值得注意的是,E2E 测试 tests/e2e/online_serving/test_lance.py 选择不依赖 YAML,而是把这些引擎旋钮作为 CLI 参数直接传入vllm-omni serve,等效命令为:

vllm-omni serve "bytedance-research/Lance" --omni \ --pipeline lance --enforce-eager --trust-remote-code --port 8091 \ --max-num-batched-tokens 32768 --max-num-seqs 1 \ --no-enable-prefix-caching --no-async-chunk

两种方式等价——deploy YAML 或平铺 CLI 参数都会由create_default_diffusion物化为 stage 配置。

4.3 发送请求

客户端为 examples/online_serving/lance/openai_chat_client.py,与 BAGEL 共用同一套 OpenAI 消息格式与modalities/num_inference_steps/seed/height/width旋钮:

# 文生图 python examples/online_serving/lance/openai_chat_client.py \ --prompt "A cute corgi astronaut on the moon, cinematic" \ --modality text2img --output corgi.png # 图像编辑 python examples/online_serving/lance/openai_chat_client.py \ --prompt "Convert this into a vibrant cartoon-style illustration" \ --modality img2img --image-url path/to/photo.png \ --output edited.png # 图像理解 python examples/online_serving/lance/openai_chat_client.py \ --prompt "Describe this image" \ --modality img2text --image-url photo.jpg

客户端实现要点(源码可见):

  • 提示词以<|im_start|>prompt<|im_end|>包裹;本地图片自动 base64 编码为data:image/jpeg;base64,...,远程 URL 直接透传;
  • modalities字段置于 payload 顶层(["image"]["text"]),num_inference_stepsseedheightwidthnegative_prompt同样置于顶层——注释明确说明 vLLM 会忽略extra_body,参数必须直接放在 payload 中;
  • 响应解析先遍历所有choices查找image_url类型的图像输出(base64 解码落盘),再回退提取文本输出(理解任务);
  • 客户端默认参数:--height/--width 512--steps 25--seed 42;若需要与离线推理默认一致,请显式传--steps 30 --height 1024 --width 1024

五、验证与测试

在线服务的端到端验证可直接运行仓库测试:

pytest -s -v tests/e2e/online_serving/test_lance.py

该测试(tests/e2e/online_serving/test_lance.py)验证:

  1. test_lance_text2img_online:text2img 请求经 OpenAI 兼容 API 返回 base64 图像;
  2. test_lance_img2img_online:img2img 请求(渲染image_edit提示词 + base64 图像消息)返回编辑后图像。

测试内部使用render_lance_prompt构造与上游一致的提示词,并显式设置VLLM_WORKER_MULTIPROC_METHOD=spawnstage_init_timeout=300秒。注意测试标有hardware_test标记,需要真实 GPU 环境。

六、实现原理与位置编码细节

6.1 三处特化 vs BAGEL 复用

vllm_omni/diffusion/models/lance/lance_transformer.py 承载了模型层特化:

  • LanceBagel:继承 BAGEL 的vae2llm/llm2vae/time_embedder/latent_pos_embed连接器布局,仅调整模型构建;
  • LanceQwen2_5_VLNaViTWrapper+LanceZeroVitPosEmbed:接入 Qwen2.5-VL 视觉塔,使用 Qwen2-VL 图像处理器 + no-op 连接器 /vit_pos_embed
  • LanceIdentityConnector:身份连接器;
  • LancePositionEmbedding3D:3-D 潜在位置嵌入(视频路径);
  • LanceWanVAE(wan_vae.py):封装 Wan2.2 VAE,含decode_video多帧解码路径。

6.2 mRoPE 位置编码

rope_scaling = {"type": "mrope", "mrope_section": [16, 24, 24]}通过BagelRotaryEmbedding贯通(BagelRotaryEmbedding现在会按rope_type自动分派):

  • text2img 使用标量位置 id(与 BAGEL 等价);
  • img2text / video / 编辑路径按轴传递 3-D 位置 id(per-axis 3-D position ids)。

从 pipeline_lance.py 的构建逻辑看,若 LLM config 未带rope_scaling,会写入默认值{"rope_type": "mrope", "mrope_section": [16, 24, 24]}。图像版latent_pos_embed形状为(4096, 2048)(对应max_latent_size = 64),视频版为(126976, 2048)(对应max_num_frames × max_latent_size²)。

6.3 已知限制与注意事项

按仓库文档与源码记录,以下事实需在实操中留意:

  • video_edit 在同等分辨率下质量偏抽象(不如 text2video):已知存在 VAE-prefill 与 gen-latent 块之间的 position-id 偏移问题,但功能上端到端正确
  • 理解路径的贪心 EOS 问题:务必使用默认采样(温度 0.8),否则可能得到空输出;
  • flash attention 更贴近上游数值:离线脚本默认设置DIFFUSION_ATTENTION_BACKEND=FLASH_ATTN(上游使用flash_attn_varlen_func;SDPA 在 36 层 Qwen2 栈上会积累约 5 倍数值漂移,B300 上尤为明显),除非显式指定其他后端;
  • 两阶段 AR + DiT 拓扑暂未接入:当前仅单阶段管线可用;
  • 视频路径务必使用Lance_3B_Video子检查点,否则 3-D 位置表缺失会导致越界错误;
  • HuggingFace 仓库已捆绑全部子检查点(Lance_3B/Lance_3B_Video/Qwen2.5-VL-ViT/Wan2.2_VAE.pth),无需单独下载。

七、快速参考:常用参数一览

参数默认值说明
--modalitytext2imgtext2img/img2text/text2video/video2text/img2img/video2video/image2video
--steps30去噪步数(上游默认)
--cfg-text-scale4.0文本 CFG 强度
--timestep-shift3.5Flow-match 时间步偏移
--seed42随机种子
--height/--width1024×1024图像分辨率(t2i)
--num-frames25视频 RGB 帧数(上限 121)
--video-height/--video-width480×768视频分辨率
--fps12输出 MP4 帧率(与上游save_fps=12一致)
--max-text-tokens512理解路径最大生成 token 数
--do-sample/--no-sample采样开理解路径采样开关(贪心易触发即时 EOS)
--text-temperature0.8理解路径采样温度
--system-prompt覆盖任务系统提示词(问答场景必用)
--negative-prompt负向提示词
--txt-prompts从文件逐行读取提示词

八、相关资源索引

  • Recipe 文档:recipes/ByteDance/Lance.md
  • 离线推理示例:examples/offline_inference/lance/end2end.py、README、gradio_demo.py
  • 在线服务示例:examples/online_serving/lance/run_server.sh、openai_chat_client.py、README
  • 部署配置:vllm_omni/deploy/lance.yaml
  • 管线实现:pipeline_lance.py、lance_transformer.py、prompts.py、wan_vae.py
  • E2E 测试:tests/e2e/online_serving/test_lance.py

【免费下载链接】vllm-omniA framework for efficient model inference with omni-modality models项目地址: https://gitcode.com/GitHub_Trending/vl/vllm-omni

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/18 3:50:15

微搭低代码实现MBA培训线索分配与审核:状态机与数据源方法实战

1. 线索分配这个模块&#xff0c;为什么是MBA培训系统的分水岭做微搭低代码MBA培训管理系统做到第12篇&#xff0c;前面我们已经把课程展示、学员档案、报名缴费这些基础链路都搭完了&#xff0c;系统跑起来似乎没什么大问题。但真正让这套系统从"内部管理工具"变成&…

作者头像 李华
网站建设 2026/9/18 3:48:23

硬件级USB切换器如何实现双机协同与外设共享

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/18 3:48:18

C盘满了怎么清理:7款磁盘分析工具横评与WizTree实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/18 3:47:48

用书签脚本一键导出豆包对话记录:原理与实操

1. 起因&#xff1a;豆包的对话记录&#xff0c;为什么非要用脚本导出先交代一下背景。我在豆包里攒了几十段调试代码、写文案、梳理需求的对话&#xff0c;某天想把这些内容整理进本地知识库&#xff0c;结果发现手动一段段复制实在太痛苦了。豆包App端可以逐条选中复制&#…

作者头像 李华
网站建设 2026/9/18 3:46:28

如果 Rene 只做 newsletter 挑论文,TaoToken Key 该放在哪一步

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华