Skip to content
指南阅读约需 11 分钟

用视觉 AI 加速图像和视频标注

在 Potato 中配置 YOLO、Ollama、OpenAI 和 Claude 视觉端点,让模型提出边界框和标签,由标注者接受或拒绝。

Potato Team

用检测模型画框,用视觉语言模型做判断,再让标注者接受或拒绝模型提出的结果,而不是手工画出每一个区域。

Potato 2.1 加入了视觉 AI 支持,把模型建议放进图像和视频标注界面。YOLO 这类检测器找出目标并画出候选框供审核。GPT-4o、Claude 或本地 Ollama 模型这类视觉语言模型对整张图像或某个区域分类,并解释分类的依据。模型提出的任何结果,在标注者接受之前都不会成为标注。

本指南介绍四种视觉端点、每种端点支持的辅助模式,以及如何在同一个项目里搭配使用视觉端点和文本端点。完整的 API 参考见视觉 AI 源文档。

需要准备的东西

视觉 AI 需要 Potato 2.1.0 或更高版本:

bash
pip install --upgrade potato-annotation

选哪个端点决定了其余的设置:

  • YOLO 在本地运行:pip install ultralytics opencv-python
  • Ollama 在本地运行:从 ollama.ai 安装并拉取一个视觉模型
  • OpenAI 需要一个能访问 GPT-4o 的 API 密钥
  • Anthropic 需要一个能访问 Claude 视觉模型的 API 密钥

用 YOLO 做目标检测

任务是给常见物体画边界框、而且图像不该离开本机时,选 YOLO。它每张图只花几毫秒就能检测出人、车、动物和家具,返回的是坐标而不是文字,这正是画框任务需要的。

方案级的 ai_support 块决定标注者看到哪些按钮,项目级的块决定由哪个模型来回应。把两者分开,一个项目才能只在检测方案上启用 AI,其余方案保持不动。

yaml
annotation_task_name: "Object Detection with YOLO"
task_dir: "."
 
data_files:
  - data/images.json
 
item_properties:
  id_key: id
  text_key: image_url
 
instance_display:
  fields:
    - key: image_url
      type: image
      display_options:
        max_width: 800
        zoomable: true
 
annotation_schemes:
  - annotation_type: image_annotation
    name: objects
    description: "Draw a box around every object and label it"
    source_field: "image_url"
    tools:
      - bbox
    labels:
      - name: "person"
        color: "#FF6B6B"
      - name: "car"
        color: "#4ECDC4"
      - name: "dog"
        color: "#45B7D1"
      - name: "cat"
        color: "#96CEB4"
 
    ai_support:
      enabled: true
      features:
        detection: true
        pre_annotate: true
        hint: true
 
ai_support:
  enabled: true
  endpoint_type: "yolo"
  ai_config:
    model: "yolov8m.pt"
    confidence_threshold: 0.5
 
output_annotation_dir: "annotation_output/"
user_config:
  allow_all_users: true

数据文件每行一个 JSON 对象,图像路径或 URL 放在 text_key 指定的字段里:

json
{"id": "img_001", "image_url": "images/street_scene_1.jpg"}
{"id": "img_002", "image_url": "images/park_photo.jpg"}
{"id": "img_003", "image_url": "https://example.com/images/office.jpg"}

挑选模型大小

模型大小是在延迟和召回之间取舍,而这个取舍的两头都要花标注者的时间。漏检目标的模型会把预标注重新变回画框任务,每张图要跑几秒的模型则让标注者在条目之间干等。中间几档是通常的选择,不是因为它们在哪一头胜出,而是因为它们把两头的代价都压得比较小。

模型大小速度准确度适用场景
yolov8n.pt6 MB最快较低快速试做
yolov8s.pt22 MB快不错均衡的工作量
yolov8m.pt50 MB中等更好通用
yolov8l.pt84 MB较慢高准确度要紧时
yolov8x.pt131 MB最慢最高追求最高精度

对于 YOLO 内置类别以外的物体,YOLO-World 做开放词表检测:

yaml
ai_config:
  model: "yolo-world"
  confidence_threshold: 0.3

设置置信度阈值

阈值决定你交给标注者的是哪一种活。阈值低,框就多,他们的时间花在拒绝误报上。阈值高,框就少,时间花在补画模型漏掉的目标上。从 0.5 开始,看第一批数据里哪一种修正占多数,再调:

yaml
ai_config:
  confidence_threshold: 0.3  # more detections, more false positives
yaml
ai_config:
  confidence_threshold: 0.7  # fewer detections, higher precision

用 Ollama 视觉模型做本地场景理解

Ollama 在你自己的硬件上跑视觉语言模型。与 YOLO 不同,这些模型读的是整个场景并写出解释,这是分类任务需要、而检测器给不了的。数据不离开本机,所以同一套设置也覆盖那些不能送到托管 API 的数据集。

bash
curl -fsSL https://ollama.ai/install.sh | sh
ollama pull llava

下面这个项目用本地模型对场景类型分类。这里没有方案级的 ai_support 块,因为分类功能在这里是项目级的,而不是挂在某个画图工具上:

yaml
annotation_task_name: "Image Classification with Ollama Vision"
task_dir: "."
 
data_files:
  - data/images.json
 
item_properties:
  id_key: id
  text_key: image_url
 
instance_display:
  fields:
    - key: image_url
      type: image
      display_options:
        max_width: 600
        zoomable: true
 
annotation_schemes:
  - annotation_type: radio
    name: scene_type
    description: "What type of scene is shown?"
    labels:
      - indoor
      - outdoor_urban
      - outdoor_nature
      - aerial
      - underwater
 
ai_support:
  enabled: true
  endpoint_type: "ollama_vision"
  ai_config:
    model: "llava:latest"
    base_url: "http://localhost:11434"
    max_tokens: 500
    temperature: 0.1
 
output_annotation_dir: "annotation_output/"
user_config:
  allow_all_users: true

低 temperature 在这里比在写作任务里更要紧。同一张图像出现两次,应该得到同一个建议标签,而在高温度下采样的模型有时会自相矛盾,标注者读到的是工具的噪声,而不是模型的不确定。

Potato 支持 LLaVA 的 7B、13B 和 34B 三种规模,还有 LLaVA-LLaMA3、BakLLaVA、11B 和 90B 的 Llama 3.2 Vision、Qwen2.5-VL 以及 Moondream。小模型回答得够快,能让标注者不停下来;标签取决于细节时,大模型值得多等。

OpenAI 视觉

GPT-4o 通过同一个 ai_support 块处理图像,其中 detail 设置控制送出图像的多少:

yaml
ai_support:
  enabled: true
  endpoint_type: "openai_vision"
  ai_config:
    api_key: "${OPENAI_API_KEY}"
    model: "gpt-4o"
    max_tokens: 1000
    detail: "auto"
bash
export OPENAI_API_KEY="sk-..."

low 送出缩小过的图像,更便宜,对场景级分类也够快。high 送出完整分辨率,找小物体需要它。auto 交给 API 自己选。这个设置按图像计费,所以值得在跑大批量之前就定好,而不是等账单出来。

Anthropic 视觉

Claude 的视觉模型读取图像上下文,并写出分类背后的推理,所以在标注者需要的是解释而不是一个框的任务里很合适:

yaml
ai_support:
  enabled: true
  endpoint_type: "anthropic_vision"
  ai_config:
    api_key: "${ANTHROPIC_API_KEY}"
    model: "claude-sonnet-4-20250514"
    max_tokens: 1024
bash
export ANTHROPIC_API_KEY="sk-ant-..."

辅助模式

每种模式都会给标注者的工具栏加一个按钮,也改变向模型提出的要求。只打开任务需要的那几个,因为每多一个按钮,标注者在每个条目上就多一个要做的决定。

检测找出与你配置的标签相符的物体,用虚线覆盖层显示出来。标注者逐张处理图像、希望每张图都有个起点时,用这个模式:

yaml
ai_support:
  enabled: true
  features:
    detection: true

预标注一次性把检测器跑遍所有数据,标注者打开每个条目时建议已经在上面了。这是在大数据集上划算的模式,也是最需要校准好阈值的模式,因为这一遍跑完以后没人会再去看设置:

yaml
ai_support:
  enabled: true
  features:
    pre_annotate: true

分类给选中的区域或整张图像打标签,返回一个带置信度分数的建议标签。提示给出指引但不给答案,适合用在标注者培训阶段,在那里把标签直接给出去什么也教不会:

yaml
ai_support:
  enabled: true
  features:
    classification: true
    hint: true

接受和拒绝建议

建议以虚线覆盖层出现,在标注者动手之前一直只是建议。双击覆盖层把它变成真正的标注,右键点击把它丢掉,工具栏上还有“全部接受”和“清除”,用在所有建议全对或者全错的条目上。

接受这一步是标注文件保持诚实的原因。导出的是人接受过的东西,而不是模型提出的东西,所以调得不好的阈值只会费掉标注时间,不会悄悄把错标签写进数据集。这也让接受和拒绝的计数在试点期间值得盯着,因为标注者把大多数建议都拒绝掉的一轮,先告诉你的是阈值的事,之后才是模型的事。

视频:场景切分

视频方案有自己的一套功能,涵盖场景边界、帧分类、关键帧和跟踪。max_frames 限制模型从片段里采样多少帧,这是同时影响准确度和等待时间的主要杠杆:

yaml
annotation_schemes:
  - annotation_type: video_annotation
    name: scenes
    description: "Segment this video into scenes"
    mode: segment
    labels:
      - name: "intro"
        color: "#4ECDC4"
      - name: "main_content"
        color: "#FF6B6B"
      - name: "outro"
        color: "#45B7D1"
 
    ai_support:
      enabled: true
      features:
        scene_detection: true
        pre_annotate: true
        hint: true
 
ai_support:
  enabled: true
  endpoint_type: "ollama_vision"
  ai_config:
    model: "llava:latest"
    max_frames: 10

文本一个端点,图像另一个

混用文本方案和图像方案的项目通常希望两边用不同的模型,因为画框最好的模型不是写提示最好的那个。visual_endpoint_type 和 visual_ai_config 设置第二个端点。把这个块加到已经有 ai_support 段的配置里:

yaml
ai_support:
  enabled: true
 
  endpoint_type: "ollama"
  ai_config:
    model: "llama3.2"
    include:
      all: true
 
  visual_endpoint_type: "yolo"
  visual_ai_config:
    model: "yolov8m.pt"
    confidence_threshold: 0.5

同样的搭配也适用于托管视觉模型配本地文本模型:

yaml
ai_support:
  enabled: true
  endpoint_type: "ollama"
  visual_endpoint_type: "openai_vision"
  ai_config:
    model: "llama3.2"
  visual_ai_config:
    api_key: "${OPENAI_API_KEY}"
    model: "gpt-4o"

在 2.9.1 里这一对有一个要注意的地方。AI 缓存会读这两个键,第二个端点也确实能用,但 potato validate --strict 会把它们报成无法识别,所以用了它们的配置过不了严格校验这一关。用 --strict 把关部署的项目,在上游把这件事理顺之前,最好把视觉端点和文本端点放在不同的项目里。

一个完整的例子:产品照片

这个项目让标注者框出产品和瑕疵,判断照片能不能发布,并标出照片哪里有问题。YOLO 提出边界框,两个判断类方案仍然由人来做:

yaml
annotation_task_name: "Product Photo Annotation"
task_dir: "."
 
data_files:
  - data/product_photos.json
 
item_properties:
  id_key: sku
  text_key: photo_url
 
instance_display:
  layout:
    direction: horizontal
    gap: 24px
  fields:
    - key: photo_url
      type: image
      label: "Product Photo"
      display_options:
        max_width: 600
        zoomable: true
    - key: product_description
      type: text
      label: "Product Details"
 
annotation_schemes:
  - annotation_type: image_annotation
    name: product_regions
    description: "Draw boxes around products and defects"
    source_field: "photo_url"
    tools:
      - bbox
    labels:
      - name: "product"
        color: "#4ECDC4"
      - name: "defect"
        color: "#FF6B6B"
      - name: "label"
        color: "#45B7D1"
      - name: "packaging"
        color: "#96CEB4"
 
    ai_support:
      enabled: true
      features:
        detection: true
        pre_annotate: true
 
  - annotation_type: radio
    name: photo_quality
    description: "Is this photo suitable for the product listing?"
    labels:
      - Approved
      - Needs editing
      - Reshoot required
 
  - annotation_type: multiselect
    name: quality_issues
    description: "Select any issues present"
    labels:
      - Blurry
      - Poor lighting
      - Wrong angle
      - Background clutter
      - Color inaccurate
 
ai_support:
  enabled: true
  endpoint_type: "yolo"
  ai_config:
    model: "yolov8m.pt"
    confidence_threshold: 0.5
 
output_annotation_dir: "annotation_output/"
export_annotation_format: "jsonl"
user_config:
  allow_all_users: true

要给这两个判断方案加上文本提示,把上面那对 visual_endpoint_type 配置加进这个配置里,文本模型作 endpoint_type,yolo 作视觉端点。图像方案的框仍旧来自 YOLO,单选和多选方案的提示来自文本模型。

示例数据(data/product_photos.json):

json
{"sku": "SKU-001", "photo_url": "images/products/laptop_front.jpg", "product_description": "15-inch laptop, silver finish"}
{"sku": "SKU-002", "photo_url": "images/products/headphones_side.jpg", "product_description": "Over-ear wireless headphones, black"}
{"sku": "SKU-003", "photo_url": "images/products/backpack_full.jpg", "product_description": "40L hiking backpack, navy blue"}

把设置做对

  • 在大数据集上让标注者开工之前,先跑一遍预标注。 按条目算,审核加修正比从头画要快,而且这份好处随数据集规模增长,设置的成本不会。
  • 让端点对上问题。 检测器回答“它在哪”,视觉语言模型回答“这是什么、为什么”,让其中一个去干另一个的活,产生的建议标注者很快就学会不看。
  • 在试点批次上调阈值。 从 0.5 开始,按标注者更常做哪一种修正来调。
  • 培训时用提示模式。 它给新标注者指个方向,但不把标签递过去,记录下来的仍然是他们自己的判断。
  • 把结果缓存下来。 磁盘缓存让同一张图像不会被付费分析两遍。

排查问题

“未配置视觉 AI 端点”

检查 ai_support.enabled 是不是 true,以及 endpoint_type 指的是不是一个视觉端点:yolo、ollama_vision、openai_vision 或 anthropic_vision。在图像方案上用文本端点就会出这条消息。

YOLO 检测不到你的目标

YOLO 的内置类别覆盖 80 个常见物体类别,所以这个集合之外的标签,无论阈值怎么设都匹配不上。换成 YOLO-World 拿到开放词表。如果标签确实落在 YOLO 的类别里,只是检测结果偏少,那就调低 confidence_threshold。

Ollama 报错

检查服务是不是在运行,以及你写的那个模型是不是既装好了、又支持视觉:

bash
curl http://localhost:11434/api/tags
ollama list

云 API 调用很慢

打开磁盘缓存,同一张图像就不会跨会话被分析两遍。路径相对 task_dir 解析,而且必须待在它里面:

yaml
ai_support:
  cache_config:
    disk_cache:
      enabled: true
      path: "ai_cache/visual_cache.json"

下一步