Phase 1:别用 Label Studio 的 Source Storage 接本地文件
Phase-1 概览 里那条警示展开版——把 Label Studio 指向本地目录用 Source Storage 是看起来最自然的选择,也是错的。
Source Storage 长啥样
Label Studio 在 Settings → Cloud Storage → Add Source Storage 下有个功能,可以让一个 project 指向一个目录(或者 S3 bucket、GCS bucket 等等)。UI 上写着「Files in this storage will be available as tasks in this project」。你想:完美,我有个 data/review_frames/ 目录塞满 JPEG,指过去,每张 JPEG 变成一个 task。云端 bucket pattern 的本地版。
第一次试还真能 work。task 出现了,开始标。
实际发生什么
Source Storage 会给配置目录下每一个文件(递归)自动建一个 task。每张 JPEG、每个 JSON、每张 thumbnail 残留。然后这些 task 会叠加在你通过 Import 按钮导入的 task 之上。
冲突场景:
- 你跑预标注管线,按 episode 写出
data/label_studio/<task>/episodes/<ep>_project_b.json。 - 把这些 aggregate 成
project_b_handobj.json,Import 进 LS。现在你有 N 个带预标注的 task。 - Source Storage 配在
data/review_frames/。它扫描目录,找到你的 JPEG,再给每张 JPEG 建一个 task——但这个 task 不带预标注,因为预标注是 Import 那一步加的。
现在每张 JPEG 在 project 里有两个 task:Import 进来的那份(带预测、你要的)和 Source Storage 自动建的那份(裸的、没用)。LS UI 把它们当两个 task 显示;标注员可能点进错的那半边;你一天后查谁标了什么的时候才发现。
更糟的是,Source Storage 一旦跑 sync,会顺带给 .DS_Store、半渲染失败的 JPEG、.dvc 缓存等等都建 task。task 数量爆炸。
正确做法
完全跳过 Source Storage,用 LS 的本地文件服务:
export LOCAL_FILES_SERVING_ENABLED=true
export LOCAL_FILES_DOCUMENT_ROOT="$(pwd)/data"
label-studio start --port 8080 --data-dir data/label-studio-data
这会在 /data/local-files/?d=<rel> 开一个本地文件服务,<rel> 是相对 LOCAL_FILES_DOCUMENT_ROOT 的路径。然后任务 JSON 里就这么引文件:
{
"data": {
"frame": "/data/local-files/?d=review_frames/ego/demo/001/frame_000090.jpg"
}
}
标注员打开 task 时 LS 自己把文件吐出来。没有 Source Storage、没有幽灵 task、没有自动 sync。哪些文件成为 task 由你的 Import JSON 决定。
Source Storage 到底为啥存在
它在你没有预标注管线、文件本身就是工作单元、希望让 LS 当「该标啥」的真理来源时是真的有用。从零开始打标,把 Source Storage 指向一个 bucket,task 白给。
一旦你有了管线、给每个 task 带 predictions,这个心智模型就崩了:task 的身份现在住在管线输出的 JSON 里,不在文件里。这时 Source Storage 和 Import 就是两套都想拥有 task 列表的系统,必定撞车。
总结
- Source Storage 给配置根目录下每个文件自动建一个 task。有预标注管线的情况下跟 Import 撞。
- 用
LOCAL_FILES_SERVING_ENABLED=true+LOCAL_FILES_DOCUMENT_ROOT,任务 JSON 里写/data/local-files/?d=<rel>。 - Source Storage 对从零开始的标注没问题。对任何「预测预填」的管线都是错的。