Transformers处理多模态输入批次
来源:17golang原创
时间:2026-11-15 12:35:13 317浏览 收藏
在 Transformers 中处理多模态输入批次,最稳妥的做法是把每条样本先整理成统一的“文本 + 媒体 + ID”记录,再交给对应模型的 AutoProcessor 统一预处理。这样可以同时处理不同长度的文本、图片和部分模型支持的视频输入,并让生成结果按原始样本回填。
官方地址:https://huggingface.co/docs/transformers/
核心结论:不要手动把图片张量和文本张量拼在一起。批处理的边界应放在 processor:由它负责聊天模板、分词、图像或视频预处理、padding 和模型需要的字段;业务代码只负责样本结构、显存分批和结果顺序。
1. 先把每条多模态样本整理成同一种结构
批处理失败通常不是因为 batch 这个参数本身,而是不同样本的消息结构不一致。例如第一条样本只有文本,第二条有一张图片,第三条有两张图片或一段视频。如果业务层直接把它们混成一个列表,后面很难判断生成结果对应哪条记录。
建议在进入 Transformers 前保留一个稳定的样本 ID,并把媒体顺序写进 content 数组。对支持聊天模板的视觉语言模型,文本和媒体都作为内容块出现;对普通图文模型,则可以分别准备 text 和 images 列表。

from pathlib import Path
def build_record(sample_id, image_path, prompt):
# 每条记录保留稳定 ID,后面回填生成结果时不依赖 batch 下标
return {
"id": sample_id,
"image_path": str(Path(image_path)),
"prompt": prompt,
}
records = [
build_record("A101", "/data/images/a101.jpg", "描述图片中的主要对象"),
build_record("A102", "/data/images/a102.jpg", "判断图片是否适合归档"),
]
# 同一条记录的媒体与文本顺序固定,避免多模态占位符错位
conversations = [
[{
"role": "user",
"content": [
{"type": "image", "path": item["image_path"]},
{"type": "text", "text": item["prompt"]},
],
}]
for item in records
]
上面的路径只是示例数据位置,不代表某个模型或机器上的真实目录。需要多张图片时,在同一个 content 列表中按固定顺序增加多个 image 块;不要把一张样本的图片拆到另一条样本里。
2. 用 AutoProcessor 一次生成批次输入
Processor 是多模态批处理的关键边界。官方文档中,processor 会把文本转换为模型需要的文本张量,把图片转换为像素值;不同模型还可能返回图像网格或其他视觉字段。调用时重点关注四个参数:
tokenize=True:把聊天内容转成模型可用的 token。padding=True:把同一批不同长度的文本补齐到批次可计算的形状。return_dict=True:返回带字段名的批次对象,不依赖位置猜字段。return_tensors="pt":生成 PyTorch 张量;如果模型使用其他框架,要跟随对应配置。
支持聊天模板的视觉语言模型可以使用 apply_chat_template,它会把消息格式、媒体占位符和处理器预处理放到同一条路径中:
import torch
from transformers import AutoProcessor
model_id = "Qwen/Qwen2.5-VL-3B-Instruct"
processor = AutoProcessor.from_pretrained(model_id)
# 对话列表按样本排列;每个元素是一条完整对话
inputs = processor.apply_chat_template(
conversations,
add_generation_prompt=True, # 给生成模型留下 assistant 的起始位置
tokenize=True,
return_dict=True,
return_tensors="pt",
padding=True, # 文本长度不同时由 processor 补齐
)
# BatchFeature 的字段名由模型决定,不能假设只有 input_ids
print(list(inputs.keys()))
# 常见字段包括 input_ids、attention_mask、pixel_values,具体以模型为准
这里不建议先对每张图片手工 resize、归一化,再尝试和 token 张量拼接。视觉编码器的尺寸、均值、方差和图像网格规则属于模型处理器配置,手工覆盖容易让输入形状看似正确、语义却不匹配。
3. 普通图文模型与聊天模板要分开看
并非所有多模态 checkpoint 都使用同一种消息格式。普通的图文处理路径往往是“文本列表 + 图片列表”,而视觉聊天模型通常需要包含 role 和 content 的消息列表。不要只因为模型名称里有 vision 就照搬另一种写法,先看该 checkpoint 的 processor 和模型文档。
如果是普通图文输入,结构通常更接近下面这样:
from PIL import Image
texts = [item["prompt"] for item in records]
images = [Image.open(item["image_path"]).convert("RGB") for item in records]
# processor 同时完成文本编码、图像预处理和批次 padding
batch = processor(
text=texts,
images=images,
padding=True,
return_tensors="pt",
)
# 文件句柄不应长期占用;读取完成后主动关闭图片对象
for image in images:
image.close()
如果是聊天模板,则要让每条样本的媒体占位符和真实媒体一一对应。对视频输入,只有在模型支持视频时才使用 type="video";较长视频可使用文档提供的固定 num_frames 或 FPS 抽样参数。抽样数量应与模型能力和显存预算一起确定,不能把“帧越多越好”当成通用规则。
4. 用 micro-batch 控制显存,再调用 generate
一批样本同时包含图片或视频时,显存消耗不只取决于文本 token 数,还和图片分辨率、视觉 patch 数、视频帧数以及模型结构有关。因此生产代码通常保留一个逻辑大批次,但按固定大小切成多个 micro-batch。

import torch
from transformers import AutoModelForImageTextToText
device = "cuda" if torch.cuda.is_available() else "cpu"
model = AutoModelForImageTextToText.from_pretrained(model_id).to(device)
def move_batch(batch, target_device):
# BatchFeature 中的张量逐项搬运,非张量配置保持原值
return {
key: value.to(target_device) if hasattr(value, "to") else value
for key, value in batch.items()
}
def run_micro_batch(batch):
# 推理阶段关闭梯度,降低不必要的显存占用
batch = move_batch(batch, device)
with torch.inference_mode():
return model.generate(**batch, max_new_tokens=64)
# 实际项目中应让 processor 为每个 micro-batch 重新组装输入
outputs = run_micro_batch(inputs)
texts = processor.batch_decode(outputs, skip_special_tokens=True)
# 这里只展示解码接口;不要把示例文本当成模型真实输出
更稳妥的资源策略是先用很小的 micro_batch_size 跑通,再根据峰值显存逐步调大。视频场景还要单独限制帧数;同样的 batch size,在静态图片和视频输入上并不代表相同的显存压力。
5. 按原始 ID 拆回结果,避免顺序错位
只使用列表下标关联结果,在重试、分批或过滤失败样本后很容易错位。建议每次将记录 ID 与生成结果一起保存;如果某个 micro-batch 失败,只重试该 micro-batch,并保留其他批次已经完成的结果。
def attach_results(records, texts):
# 生成结果数量不匹配时立即报错,避免静默错位
if len(records) != len(texts):
raise ValueError("样本数量与生成结果数量不一致")
return [
{"id": record["id"], "text": text}
for record, text in zip(records, texts)
]
results = attach_results(records, texts)
# 后续写数据库或消息队列时使用 results 中的 id,而不是重新依赖位置
如果处理流程会过滤掉损坏图片或超长文本,应在过滤时同步维护记录列表,并把被跳过的 ID 记录为失败状态。这样重试任务仍然可以根据 ID 找回原始媒体和提示词。
6. 生产环境的配置、日志与发布检查
企业级批处理至少要把以下边界写进配置或运行日志:
| 边界 | 建议记录 | 目的 |
|---|---|---|
| 输入 | 样本 ID、媒体数量、媒体类型、文本长度 | 定位结构不一致与异常样本 |
| 处理器 | 模型 ID、processor 配置版本、padding 策略 | 解释字段形状和预处理差异 |
| 资源 | micro-batch 大小、视频帧数、峰值显存 | 避免批次突然放大导致 OOM |
| 输出 | 成功 ID、失败 ID、重试次数、结果顺序 | 支持幂等回填与问题追踪 |
日志中不要写入图片私有路径、访问令牌或原始敏感内容。对需要长期运行的服务,可以将处理器和模型在进程启动时加载一次,把每次请求只留在样本组装、推理和结果落库这三个边界内。
总结
Transformers 多模态批处理可以归纳为五步:统一样本结构,使用对应的 processor,按模型要求生成带字段名的 batch,在显存边界内拆成 micro-batch,最后按样本 ID 回填结果。图片、视频和聊天模板并不是可以互换的输入格式,真正稳定的实现依赖 checkpoint 的官方 processor 配置。
常见问题
为什么不能直接把图片张量和 input_ids 拼起来?
不同模型对图像预处理、视觉占位符和额外字段的要求不同。应让对应的 processor 生成完整输入,再把返回的字段交给模型。
padding=True 会不会把图片也补成相同内容?
padding 主要针对批次中的可变长度文本或处理器定义的序列字段。视觉字段如何组织由具体 processor 决定,不能用文本 padding 的直觉推断所有模型。
视频批处理为什么还要限制帧数?
帧数会直接影响视觉输入规模和显存消耗,而且模型通常有训练时的帧数能力范围。应该根据模型文档和资源预算选择固定帧数或 FPS 抽样。
-
Golang · Go教程 | 1个月前 | goroutine · Context · Go教程 · 批处理 · 批处理 Timer WithTimeout Go context WithCancelCause 父子取消链441 收藏
-
403 收藏
-
229 收藏
-
338 收藏
-
307 收藏
-
340 收藏
-
210 收藏
-
211 收藏
-
124 收藏
-
268 收藏
-
261 收藏
-
212 收藏
-
科技周边 · 人工智能 | 15小时前 | python · 人工智能 · 并行处理 index Hugging Face Datasets Datasets shard num_shards contiguous417 收藏
-
280 收藏
-
科技周边 · 人工智能 | 15小时前 | python · Transformers TextIteratorStreamer 流式生成 AsyncTextIteratorStreamer StoppingCriteria198 收藏
-
279 收藏
-
161 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习