图片注释由作者(Author)提供。原图取自Pexels。
开个头近年来,计算机视觉领域见证了基础模型的兴起,这些模型使得无需训练定制模型就可以对图像进行标注。我们看到了如CLIP [2]用于分类,GroundingDINO [3]用于目标检测,还有SAM [4]用于分割——每个模型在其领域内表现出色,。但如果有一个单一的模型能够同时处理所有这些任务,那会怎样呢?
本教程将介绍Florence-2 [1]——一个新颖的开源视觉-语言模型,设计用于处理包括图像描述、物体检测、图像分割和OCR在内的多种视觉和多模态任务。
伴随一个Colab笔记本,我们一起看看Florence-2的零样本标注能力(zero-shot annotation),它能否给一张旧相机的图片添加注释。
佛罗伦萨-2背景
微软于 2024 年 6 月发布了 Florence-2。它被设计在一个单一模型中执行多种视觉任务。它是一个开源模型,可在 Hugging Face 上找到,遵循宽松的 MIT 许可协议。
尽管它的规模相对较小,只有0.23B和0.77B参数版本,Florence-2依然达到了最先进的(SOTA)性能。小巧的规模使得它能在计算资源有限的设备上高效部署,同时保持快速推理速度。
该模型是在一个名为FLD-5B的巨大高质量数据集上进行预训练的,该数据集包含5.4B条注释基于126百万张图片。这使得Florence-2在无需额外训练的情况下,在许多任务中展现出优秀的零样本学习能力。
Florence-2模型原始开源权重文件支持以下几种任务:
可以通过微调模型来支持其他未支持的任务。
任务格式:
受到大型语言模型(LLMs)的启发,Florence-2 是一种序列到序列的模型。它接受图像和文本指令作为输入,并输出文本结果。输入或输出的文本可能是指纯文本或图像中的一个区域。区域格式会根据任务的不同而有所变化。
- 框:
' <X1><Y1><X2><Y2> ‘
,用于对象检测任务。这四个坐标表示框的左上角和右下角的位置。 - 四角框:
' <X1><Y1><X2><Y2><X3><Y3><X4><Y4> ‘
,用于文本检测,用这四个坐标来定位包围文本的四角。 - 多边形区域:
' <X1><Y1>...,<Xn><Yn> ‘
,用于分割任务,这些坐标按顺时针顺序排列,代表多边形的各个顶点。
zh: 建筑
佛罗伦萨-2采用标准的编码器-解码器转换器架构。其工作流程如下:
- 输入图像通过DaViT视觉编码器[5]进行编码。
- 文本提示使用BART[6]嵌入,使用了一个扩展的分词器和词嵌入层。
- 视觉和文本嵌入被合并在一起。
- 这些合并后的嵌入通过基于Transformer的多模态编码解码器进行处理以生成响应。
- 在训练过程中,模型通过最小化交叉熵损失,类似于标准语言模型。
佛罗伦萨-2的建筑架构图。来源:link。
代码实现部分正在加载 Florence-2 模型和一张样本图片
安装并导入了所需的库(如附带的Colab笔记本中所示)之后,我们开始加载Florence-2模型、处理器以及相机输入的图像,
# 加载模型:
model_id = 'microsoft/Florence-2-large'
model = AutoModelForCausalLM.from_pretrained(model_id, trust_remote_code=True, torch_dtype='auto').eval().cuda()
processor = AutoProcessor.from_pretrained(model_id, trust_remote_code=True)
# 加载图像:
image = Image.open(img_path)
辅助功能
在本教程中,我们将使用几个辅助函数。其中最重要的是run_example
函数,该函数会从Florence-2模型生成响应。
run_example
函数将任务提示文本与任何额外的文本输入(如果有额外的文本输入的话)结合成一个单一的提示。使用processor
,它生成文本和图像嵌入,这些嵌入被用作模型的输入。真正的魔法发生在这里,即在model.generate
步骤,模型会生成其响应。下面是一些关键参数的说明:
- max_new_tokens=1024 :设置输出的最大长度,允许生成详细回答。
- do_sample=False :确保响应是确定的。
- num_beams=3 :在每个步骤中实现束搜索方法,考虑最有可能的前3个令牌,探索多个潜在序列,以找到最佳整体结果。
- early_stopping=False :确保束搜索直到所有束达到最大长度或生成序列结束标志。
最后,模型的输出结果通过processor.batch_decode
进行解码,并用processor.post_process_generation
进行后处理,以生成最终的文本回复,然后由run_example
函数返回该结果。
def run_example(image, task_prompt, text_input=''):
prompt = task_prompt + text_input
inputs = processor(text=prompt, images=image, return_tensors="pt").to('cuda', torch.float16)
generated_ids = model.generate(
input_ids=inputs["input_ids"].cuda(),
pixel_values=inputs["pixel_values"].cuda(),
max_new_tokens=1024,
do_sample=False,
num_beams=3,
early_stopping=False,
)
generated_text = processor.batch_decode(generated_ids, skip_special_tokens=False)[0]
parsed_answer = processor.post_process_generation(
generated_text,
task=task_prompt,
image_size=(image.width, image.height)
)
return parsed_answer
此外,我们使用辅助函数来可视化结果的辅助函数(draw_bbox
、draw_ocr_bboxes
和 draw_polygon
),并处理边界框格式之间的转换(convert_bbox_to_florence-2
和 convert_florence-2_to_bbox
)。这些功能可以在随附的Colab笔记本中进行探索。
改正为:
任务佛罗伦萨2可以完成多种视觉任务。让我们看看它的能力,从图像描述这项任务开始。
1. 字幕生成相关任务.1.1 生成字幕,就是给视频加字幕的意思。
佛罗伦萨-2可以生成不同程度的图像描述,使用'<CAPTION>'
、'<DETAILED_CAPTION>'
或'<MORE_DETAILED_CAPTION>'
这些任务提示。
print (run_example(image, task_prompt='<CAPTION>'))
# 输出:'一个黑色相机放在木桌上。'
print (run_example(image, task_prompt='<DETAILED_CAPTION>'))
# 输出:'图片特写了一台柯达V35 35毫米胶卷相机放在木桌上,背景模糊。'
print (run_example(image, task_prompt='<MORE_DETAILED_CAPTION>'))
# 输出:'图片特写了一台柯达VR35数码相机。相机是黑色的,左上角有柯达标志。机身是由木材制成,并有纹理的握把便于操作。镜头位于机身中心,并被一个金色的环包围。右上角有一个小LCD屏幕和一个闪光灯。背景模糊,但看起来像是一个树木茂密的地方,有树木和植被。'
该模型准确地描述了图像及其周围环境。它甚至能够识别相机的品牌和型号,展示了其OCR功能。然而,在'<MORE_DETAILED_CAPTION>'
任务中存在细微的不一致,这在零样本模型中是正常的。
1.2 为给定边界框生成标注
弗罗伦萨-2可以为图像中由边界框定义的特定区域生成描述。为此,它将边界框的位置作为输入。你可以使用'<REGION_TO_CATEGORY>'
提取类别,或使用'<REGION_TO_DESCRIPTION>'
提取描述。
为了方便你,我在Colab笔记本中添加了一个小部件,使你能够画出边界框,并且包含将其转换为Florence-2格式的代码。
task_prompt = '<REGION_TO_CATEGORY>'
box_str = '<loc_335><loc_412><loc_653><loc_832>'
results = run_example(image, task_prompt, text_input=box_str)
# 输出:'相机镜头'
task_prompt = '<区域到描述>'
box_str = '<loc_335><loc_412><loc_653><loc_832>'
results = run_example(图像, task_prompt, text_input=box_str)
# 输出结果:'camera'
在这种情况下,'<REGION_TO_CATEGORY>'
识别了镜头这一部分,而 '<REGION_TO_DESCRIPTION>'
则没有那么具体。然而,这种识别效果可能会随着不同的图像而有所不同。
2.1 生成对象的边界框和文字标签
弗罗伦萨-2 可以识别图像中密集的区域或对象,并提供它们的边界框坐标及其相关标签。要提取并标注边界框,使用以下 <OD>
任务指令:
results = run_example(image, task_prompt='<OD>')
draw_bbox(image, results['<OD>'])
要提取带标注的边界框,请使用 ' <DENSE_REGION_CAPTION> '
提示:
task_prompt results = run_example(image, task_prompt= '<DENSE_REGION_CAPTION>')
绘制边界框(image, results['<DENSE_REGION_CAPTION>'])
左边这张图展示了’<OD>'任务的结果,而右边这张图展示了‘<DENSE_REGION_CAPTION>’的结果。
2.2 文本引导的物体检测
佛罗伦萨-2也可以根据文本进行对象检测。通过输入特定对象的名称或描述,佛罗伦萨-2可以检测出指定对象的边界框。
任务提示 = '<CAPTION_TO_PHRASE_GROUNDING>'
结果 = 运行示例(图像,任务提示, 文本输入="lens. camera. table. logo. flash.")
绘制边界框(图像, 结果['<CAPTION_TO_PHRASE_GROUNDING>'])
将以下词汇与图片中的元素对应起来:镜头、相机、桌子、标志和闪光灯。
3. 词语分割相关的任务:佛罗伦萨2还可以生成根据文本的分割多边形 ('引用表达式分割'
) 或根据边界框的分割多边形 ('区域到分割'
):
results = run_example(image, task_prompt='<指代表达分割任务>', text_input="相机")
draw_polygons(image, results[task_prompt])
results = run_example(image, task_prompt='<REGION_TO_SEGMENTATION>', text_input="<loc_345><loc_417><loc_648><loc_845>")
# 将图像分割为指定区域
draw_polygons(output_image, results['<REGION_TO_SEGMENTATION>'])
# 绘制分割结果的多边形
左边的图片显示了使用“camera”文本输入的指代表达分割任务的结果。右边的图片显示了输入的是镜头周围的边界框的区域到分割任务的结果。
4. OCR相关任务:弗罗伦萨-2具有强大的OCR功能。它可以通过'<OCR>'
任务从图像中提取文本,并使用'<OCR_WITH_REGION>'
提取文本及其位置信息:
结果 = 运行示例(image, task_prompt)
绘制OCR边界框(image, 结果['<OCR_WITH_REGION>'])
结束语
Florence-2 是一个多功能的视觉语言模型(VLM),可以在一个模型中处理多种视觉任务。它在图像描述、物体检测、分割和 OCR 等各种任务中的零样本任务表现令人印象深刻。虽然 Florence-2 在初始状态下表现良好,但进一步微调可以更好地适应新任务或提高在独特定制数据集上的表现。
感谢阅读!祝贺你终于走到这里。点击 👍 来表达你的赞赏,让算法也开心一下 🤓
想学更多吗?
完整代码的Colab笔记本版本: 参考资料代码链接: 链接
[1] Florence-2:为多种视觉任务实现统一表示.
[2] CLIP:基于自然语言监督的学习可转移的视觉模型
[3] Grounding DINO: 让DINO与预训练结合以实现面向开放集物体检测.
[4] SAM2:在图像和视频中进行任意分割.
[5] DaViT: 双注意力视觉变换器.
[6] BART:序列到序列去噪预训练的BART,用于自然语言生成、翻译和理解的预训练模型,https://arxiv.org/pdf/1910.13461.
共同学习,写下你的评论
评论加载中...
作者其他优质文章