CVAT 即时数据准备(Data on the fly):惰性分块、媒体缓存与 manifest 驱动的任务数据加速
CVAT 即时数据准备Data on the fly惰性分块、媒体缓存与 manifest 驱动的任务数据加速【免费下载链接】cvatComputer Vision Annotation Tool (CVAT) is a leading platform for building high-quality visual datasets for vision AI. It offers open-source, cloud, and enterprise products, as well as labeling services, for image, video, and 3D annotation with AI-assisted labeling, quality assurance, team collaboration, analytics, and developer APIs.项目地址: https://gitcode.com/GitHub_Trending/cvat/cvat本文讲解 CVATComputer Vision Annotation Tool中的 “Data preparation on the fly” 机制创建任务时只采集最少的元数据客户端首次请求时再按需生成数据块chunk并写入有限大小的缓存。读完本文你将理解该机制的工作原理、启用方式Use Cache开关、配套的manifest.jsonl上传流程以及从源码层面MediaCache、RQ 任务队列、缓存键命名看清“缓存未命中时如何重建分块”的完整调用链。一、机制概述元数据先行数据按需生成根据官方文档 Data preparation on the fly 的定义Data on the fly 处理是一种工作方式其核心思想是创建任务时CVAT 只采集创建任务所必需的最少元数据如媒体类型、文件数量、分辨率、帧数等而不会立即解码视频或拷贝全部图像。客户端发起请求时利用这些预存的元信息现场创建出所需的 chunk帧数据块并将其放入缓存。缓存策略生成的 chunk 存储在大小受限的缓存中淘汰策略优先移除热度较低访问较少的条目文档原话a cache of the limited size with a policy of evicting less popular items。请求路径收到客户端请求后先按 key 查缓存命中则直接返回未命中则用元信息创建 chunk 并写回缓存。这种工作方式带来的直接收益是缩短任务创建时间——创建阶段不必等待视频抽帧、图像打包等重操作以有界缓存替代全量存储——数据块按热度淘汰服务器磁盘占用可控。源码印证缓存键、队列与创建流程从源码结构看文档中描述的“搜索缓存 → 未命中则创建”流程由 cvat/apps/engine/cache.py 中的MediaCache类实现关键事实均可在该文件中找到对应证据_get_or_set_cache_item()即“先查缓存、未命中再创建”的入口cache.py#L210-L225先调用_get_cache_item(key)命中直接返回否则调用_create_cache_item(key, create_callback)。chunk 的实际生成不在 Web 请求进程内同步完成而是通过RQ 队列异步执行MediaCache使用名为chunks的队列_QUEUE_NAME settings.CVAT_QUEUES.CHUNKS.value作业 ID 前缀chunks:prepare-item-见 cache.py#L192-L198。当运行环境不在 RQ worker 内时_create_cache_item()会把create_callback封装为Callback入队然后阻塞轮询等待作业完成wait_for_rq_jobcache.py#L125-L139轮询间隔与超时分别由CVAT_CHUNK_CREATE_CHECK_INTERVAL与CVAT_CHUNK_CREATE_TIMEOUT控制。缓存键按对象类型与分块编号生成例如task_{id}_chunk_{n}_{quality}、segment_{id}_chunk_{n}_{quality}、job_{id}_chunk_{n}_{quality}以及对象级前缀task_ / segment_ / job_ / cloudstorage_见_make_cache_key_prefix与_make_chunk_keycache.py#L372-L395。quality帧质量参与键名意味着不同图像质量档位的 chunk 互不共享缓存是“按 (对象, 分块号, 质量) 三元组”组织的。缓存后端是 Django 的mediacache_CACHE_NAME media底层为 Redis即文档所说“limited size”的物理承载。缓存条目完整性校验和与时间戳MediaCache对每个缓存条目保存四元组(data, mime, crc32_checksum, timestamp)_CacheItem类型别名cache.py#L63-L64读取校验_get_cache_item()读取条目后会重新计算zlib.crc32校验和并比对不匹配则视为未命中日志Cache item ... checksum mismatchcache.py#L332-L356失效时间戳条目携带生成时间_validate_cache_item_timestamp()会比较条目时间与任务/分段的chunks_updated_date不一致时抛出CvatChunkTimestampMismatchErrorcache.py#L358-L366。从源码结构看这是“任务数据更新如修改分段后旧 chunk 自动失效”的机制基础。单块大小上限并非任意大的 chunk 都能入缓存_create_and_set_cache_item()在写入前检查条目大小超过CVAT_CACHE_ITEM_MAX_SIZE即抛出CacheTooLargeDataErrorcache.py#L269-L276。该上限在 cvat/apps/engine/default_settings.py#L24 中默认为500 * 1024 * 1024500 MB。这解释了文档“cache of the limited size”的另一层含义除缓存总容量受限外单个 chunk 也有硬上限。二、优点与局限文档明确列出的三类代价原文档在优点之外明确指出了 Data on the fly 的三个固有局限使用与评估该功能时应逐一对照首次访问更慢chunk 尚未缓存时首次请求要等待解码、打包、入队、轮询完成的完整链路对应源码中enqueue_create_chunk_jobwait_for_rq_job的同步等待因此“第一次访问数据会花更多时间”。部分视频会回退到默认方式即使视频带有合法 manifest若视频关键帧keyframe数量不足以支撑平滑解码任务数据块仍会按默认方式即创建任务时生成。文档对此的解释是manifest 记录了每帧的pts与校验和但随机 seek 解码依赖关键帧密度关键帧稀疏时“按 manifest 跳帧解码”无法稳定工作。访问时源不可达则失败数据尚未缓存时若源文件如云存储对象、挂载的 file share 文件在访问时刻不可达chunk 无法生成、数据也就取不到。换言之缓存命中是唯一的“离线可用”保障——这也暗示对长期任务预热常用分块是有价值的运维手段。三、启用方式任务配置中的Use Cache开关原文档说明为新任务启用或关闭该功能在任务创建配置页使用Use Cache开关文档内部链接指向 workspace 任务页的 Create Annotation Task 小节。该开关在后端对应任务数据序列化的布尔字段use_cache默认值为False即默认关闭创建时按传统方式预生成分块其定义见 cvat/apps/engine/serializers.py#L2627-L2633use_cache serializers.BooleanField( defaultFalse, help_texttextwrap.dedent(\ Enable or disable task data chunk caching for the task. ), )通过 REST API 创建任务时即在data对象中传use_cache: true。与use_cache同属一份数据配置、理解 Data on the fly 时值得同步掌握的参数字段与校验逻辑见 serializers.py#L2684-L2729字段含义约束源码校验chunk_size每个 chunk 的最大帧数必须为正整数validate_chunk_sizeframe_filter帧过滤唯一支持的语法是stepN每 N 帧取 1 帧正则step\s*\s*([1-9]\d*)校验validate_frame_filtersorting_method文件排序方式选predefined时按 manifest 文件顺序排列源文件见下文 manifest 小节copy_data创建任务时把 file share 数据拷贝进 CVAT使命务不再依赖文件共享的可用性布尔值copy_data与 Data on the fly 是两种相反的取舍前者用创建时间换运行期可用性后者用首次访问延迟换创建时间与磁盘占用。文档列出的第三个局限访问时源不可达即失败正是copy_data试图规避的场景。四、随数据一起上传 manifestmanifest.jsonl的准备与格式原文档最后一节指出创建任务时可以随视频或图像数据集一起上传一个manifest.jsonl文件manifest 的准备方法见 Dataset Manifest。该机制与 Data on the fly 的耦合点在源码中非常明确——cvat/apps/engine/cache.py#L40-L47 从media_extractors导入的正是成对的普通读取器与 manifest 读取器from cvat.apps.engine.media_extractors import ( ImageReaderWithManifest, VideoReader, VideoReaderWithManifest, ... )从源码结构看VideoReaderWithManifest/ImageReaderWithManifest就是“用 manifest 元信息重建 chunk”的实现路径manifest 提供了帧序号、pts时间戳与帧md5校验和使服务器可以按关键帧 seek 后解码到目标帧而无需线性扫全视频。manifest 文件格式JSONLmanifest 是 JSONL 文本文件分视频与图像/3D 数据两种子格式格式规范见 dataset_manifest.md视频 manifest描述单个视频pts为帧应展示的时间checksum为解码帧的 md5{version:1.0} {type:video} {properties:{name:video.mp4,resolution:[1280,720],length:778}} {number:0,pts:0,checksum:17bb40d76887b56fe8213c6fded3d540} {number:135,pts:486000,checksum:9da9b4d42c1206d71bf17a7070a05847}图像 manifest描述有序图像集合{version:1.0} {type:images} {name:image1,extension:.jpg,width:720,height:405,meta:{related_images:[]},checksum:548918ec4b56132a5cff1d4acabe9947}注意视频 manifest 中逐帧条目是可重复行示例中的number以 135 为间隔递增——这与“关键帧稀疏的视频可能不满足 Data on the fly 要求”的说法相呼应条目本身可以稀疏对应关键帧位置能否平滑解码最终取决于视频本身。用官方 CLI 工具生成 manifestCVAT 提供专用 Python 工具 utils/dataset_manifest/create.py用法摘自 dataset_manifest.mdusage: create.py [-h] [--force] [--output-dir .] source positional arguments: source Source paths optional arguments: -h, --help show this help message and exit --force Use this flag to prepare the manifest file for video data if by default the video does not meet the requirements and a manifest file is not prepared --output-dir OUTPUT_DIR Directory where the manifest file will be saved其中--force的含义正对应本文第二个局限默认情况下若视频不满足要求如关键帧不足则不生成 manifest加--force可强制生成。典型示例# 关键帧充足的视频 python utils/dataset_manifest/create.py ~/Documents/video.mp4 # 关键帧不足的视频强制生成 python utils/dataset_manifest/create.py --force --output-dir ~/Documents ~/Documents/video.mp4 # 图像目录 / glob 模式支持 *、?、[] python utils/dataset_manifest/create.py --output-dir ~/Documents ~/Documents/images/ python utils/dataset_manifest/create.py --output-dir ~/Documents /home/${USER}/Documents/**/image*.jpeg推荐使用 Docker 镜像内的脚本与服务端解码环境一致避免本地 ffmpeg 版本差异导致结果不同docker run -it --rm -u $(id -u):$(id -g) \ -v ${PWD}:/local \ --entrypoint python3 \ cvat/server \ /opt/cvat/utils/dataset_manifest/create.py --output-dir /local /local/path/to/sources若不用 Docker 直接运行需要安装 ffmpeg 开发库与 utils/dataset_manifest/requirements.in 所列 Python 依赖安装步骤详见 dataset_manifest.md。manifest 与任务创建的配套规则以下规则来自 dataset_manifest.md在启用 Data on the fly缓存模式时直接相关manifest 文件可放在输入文件列表中与视频或图像数据集一起上传当排序方式选predefined时源文件将按.jsonlmanifest 中的顺序排列图像压缩包如.zip使用predefined排序时必须提供位于压缩包之外与压缩包并列在输入列表中的 manifest 文件输入列表中若存在多个 manifest 文件会直接报错。五、请求路径复盘一次“缓存未命中”到底发生了什么把文档描述与源码证据串起来一次客户端请求在 Data on the fly 模式下的完整路径是前端按 chunk 请求帧数据chunk 数量由chunk_size决定frame_filter可为stepN抽帧后端用(对象, chunk 号, quality)构造缓存键查media缓存_get_or_set_cache_item未命中时若当前进程在 RQ worker 内则直接执行创建回调否则将_create_and_set_cache_item作为作业ID 形如chunks:prepare-item-{key}入队wait_for_rq_job按CVAT_CHUNK_CREATE_CHECK_INTERVAL轮询超过CVAT_CHUNK_CREATE_TIMEOUT报超时worker 中解码/打包该 chunkmanifest 存在时走VideoReaderWithManifest等 manifest 读取器计算 crc32 校验和与时间戳写入缓存并广播cache_item_created_signal缓存创建/读取事件同时用于统计与调试信号定义见 cvat/apps/engine/cache_signals.py请求进程再次读取缓存条目做校验和与时间戳验证后返回给客户端。由此可以推断文档三条局限在源码中的落点首次访问慢 步骤 3 的同步等待关键帧不足回退 manifest 读取器前置校验失败后退回默认创建路径源不可达失败 步骤 4 中解码器打开源文件失败作业以ChunkCreationError形态失败。六、实践建议小结创建大量长视频任务开启Use Cache可显著加快创建流程但要接受首帧加载延迟源位于易失位置临时挂载、按量计费的云存储任务运行期内保持源可达或对热数据使用copy_data准备 manifest优先用cvat/server镜像内脚本生成视频关键帧稀疏时留意--force的行为边界——即使强制生成了 manifest运行时仍可能因关键帧不足回退到创建时生成 chunk容量规划单 chunk 上限 500 MBCVAT_CACHE_ITEM_MAX_SIZEdefault_settings.py#L24与 Redismedia缓存的总容量共同约束“能缓存多少热数据”chunk_size与image_quality的取值应与此匹配。【免费下载链接】cvatComputer Vision Annotation Tool (CVAT) is a leading platform for building high-quality visual datasets for vision AI. It offers open-source, cloud, and enterprise products, as well as labeling services, for image, video, and 3D annotation with AI-assisted labeling, quality assurance, team collaboration, analytics, and developer APIs.项目地址: https://gitcode.com/GitHub_Trending/cvat/cvat创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考