LeRobot documentation
视频编码参数
视频编码参数
启用视频存储后,LeRobot 会将每个相机流存储为 MP4 文件,而不是为每个时间步保存一个图像文件。视频编码在时间维度上进行压缩,与大量 PNG 文件相比,通常能减小数据集体积并降低 I/O 开销,同时保留 MP4 这一所有播放器和加载器都能识别的格式。
将帧编码为 MP4 是一个完整的 FFmpeg 流程:涉及编码器选择、像素格式、GOP/关键帧、质量与速度的权衡,以及可选的额外编码器标志。其中大部分参数都可以通过 rgb_encoder 进行用户自定义,它是一个嵌套的 RGBEncoderConfig(lerobot.configs.video.RGBEncoderConfig),并通过 PyAV 传递。
您可以通过 CLI 使用 --dataset.rgb_encoder.<field> 来设置这些参数(例如,使用 lerobot-record 或 lerobot-rollout)。该配置块适用于该运行中的每个相机视频流。
必须开启视频存储,
rgb_encoder才会生效——在 Python API 中设置use_videos=True,或在 CLI 中使用--dataset.video=true(录制时的默认值)。如果关闭视频,输入将保持为图像,rgb_encoder会被忽略。
有关帧写入与编码(流式与回合后)的时机、队列以及其他顶层 --dataset.* 开关的详细信息,请参阅 流式视频编码。有关编码参数对比和实验,请参阅 video-benchmark Space。
示例
lerobot-record \
--robot.type=so100_follower \
--robot.port=/dev/tty.usbmodem58760431541 \
--robot.cameras="{laptop: {type: opencv, index_or_path: 0, width: 640, height: 480, fps: 30}}" \
--robot.id=black \
--teleop.type=so100_leader \
--teleop.port=/dev/tty.usbmodem58760431551 \
--teleop.id=blue \
--dataset.repo_id=<my_username>/<my_dataset_name> \
--dataset.num_episodes=2 \
--dataset.single_task="Grab the cube" \
--dataset.streaming_encoding=true \
--dataset.encoder_threads=2 \
--dataset.rgb_encoder.vcodec=h264 \
--dataset.rgb_encoder.preset=fast \
--dataset.rgb_encoder.extra_options='{"tune": "film", "profile:v": "high", "bf": 2}' \
--display_data=true调优参数
默认值经过调优,以在典型机器人数据集上平衡压缩率、视觉质量和解码/寻址速度。更改这些值可能会影响录制(CPU 负载、丢帧)和训练(解码吞吐量、图像质量)。
仅在确有特定原因时才覆盖这些参数,并在依赖新设置之前,先测量其对流水线的影响。
以下所有标志在命令行中均以 --dataset.rgb_encoder. 为前缀。
| 参数 | 类型 | 默认 | 描述 |
|---|---|---|---|
vcodec | str | "libsvtav1" | 视频编解码器名称。"auto" 会从固定的优先级列表中选取第一个可用的硬件编码器,若不可用则回退到 libsvtav1。 |
pix_fmt | str | "yuv420p" | 输出像素格式。必须受您 FFmpeg 构建中选择的编解码器支持。 |
g | int | 2 | GOP 大小 — 每隔 g 帧一个关键帧。作为 FFmpeg 选项 g 输出。 |
crf | int 或 float | 30 | 抽象质量值,按编解码器映射(参见映射)。在映射单调的情况下,值越低表示质量越高 / 输出越大。 |
preset | int 或 str | 12 * | 编码器速度预设;其含义取决于编解码器。 * 当未设置且 vcodec=libsvtav1 时,LeRobot 默认值为 12。 |
fast_decode | int | 0 | libsvtav1:0–2,通过 svtav1-params 传递。h264 / hevc(软件):如果 >0,则设置 tune=fastdecode。其他编解码器:通常不使用。 |
video_backend | str | "pyav" | 目前仅实现了"pyav"用于视频编码。 |
extra_options | dict | {} | 在上述结构化字段之后合并的额外 FFmpeg 或特定编解码器选项。无法覆盖这些字段已设置的键。 |
深度流
深度图(Intel RealSense、Reachy 2)作为独立的视频流与 RGB 流一同存储。原始深度(uint16 毫米或 float32 米)无法通过 8 位编解码器保留,因此 LeRobot 会将每张深度图量化为 12 位编码([0, 4095])——默认采用对数量化,以匹配深度传感器 1/depth 的误差特性——然后将其打包为高比特深度的像素格式(gray12le),并使用 12 位编解码器进行编码。
float32 m →
depth_max] → 量化 12 位编码 0–4095
对数(默认)或线性 → 打包 为 gray12le
平面 → 编码 HEVC
Main 12
流 →
通过并行的 depth_encoder 模块(DepthEncoderConfig)配置深度流水线。它共享 RGBEncoderConfig 的所有字段(vcodec、pix_fmt、crf、……),并额外提供四个量化器参数,可通过 --dataset.depth_encoder.<field> 进行设置:
lerobot-record \
... \
--dataset.depth_encoder.vcodec=hevc \
--dataset.depth_encoder.depth_min=0.05 \
--dataset.depth_encoder.depth_max=5.0 \
--dataset.depth_encoder.use_log=true| 参数 | 类型 | 默认 | 描述 |
|---|---|---|---|
vcodec | str | "hevc" | HEVC Main 12(支持 12 位深度的编解码器,兼容 MP4)。 |
extra_options | dict | {"x265-params": "lossless=1"} | 深度默认设置为无损(精确往返);crf 将被忽略。传入 extra_options={} 并设置 crf 以获得更小的有损流。 |
pix_fmt | str | "gray12le" | 用于承载量化码的单通道 12 位像素格式。 |
depth_min | float | 0.01 | 以米为单位的深度映射到量子0。解码时,低于该值的数值会被截断。 |
depth_max | float | 10.0 | 以米为单位的深度映射到量子化值 4095。解码时,超出该范围的值会被截断。 |
shift | float | 3.5 | 用于对数量化中靠近零处的数值稳定性的对数前偏移量(米)。必须满足 depth_min + shift > 0。 |
use_log | bool | True | 如果 true,则在日志空间中进行量化(推荐用于典型的深度传感器)。对于均匀/线性量化,请设置为 false。 |
depth_min、depth_max和shift始终以米为单位进行解释,与输入深度的单位无关。输入会自动检测:整数数组(例如直接来自 RealSense 的uint16毫米值)被视为毫米,浮点数组被视为米。 请选择合适的depth_min/depth_max以涵盖传感器的实际工作范围——超出该范围的量化值会饱和,这可能会压缩边界处的细节。
深度特征在 meta/info.json 中通过 "is_depth_map": true 进行标记,其量化器设置(video.depth_min、video.depth_max、video.shift、video.use_log)会被持久化保存——这使得在加载时能够将深度反量化回物理单位。
加载时的输出单元
depth_encoder 是一个 记录时 的问题。深度图在 加载 时(例如在训练期间)反量化的单位由读取时标志 --dataset.depth_output_unit 单独设置:
lerobot-train \
--dataset.repo_id=<my_username>/<my_dataset_name> \
--dataset.depth_output_unit=m \
--policy.type=act| 参数 | 类型 | 默认 | 描述 |
|---|---|---|---|
depth_output_unit | str | "mm" | 物理单位深度图在加载时会被反量化为:"mm"(毫米)或 "m"(米)。 |
这纯粹是解码时的呈现选择——它不会更改存储的视频或其元数据,因此同一数据集可以读取为
mm或m,而无需重新编码。它对没有深度摄像头的数据集没有影响。
数据集元数据中的持久性
在视频流的第一帧编码完成后,编码器配置会持久化到数据集元数据(meta/info.json)中,位于每个视频特征下,并与从文件本身探测到的值并列存放。对于视频特征 observation.images.<camera>,info.json 中的布局如下:
{
"features": {
"observation.images.laptop": {
"dtype": "video",
"shape": [480, 640, 3],
"info": {
"video.height": 480,
"video.width": 640,
"video.codec": "h264",
"video.pix_fmt": "yuv420p",
"video.fps": 30,
"video.channels": 3,
"is_depth_map": false,
"video.g": 2,
"video.crf": 30,
"video.preset": "fast",
"video.fast_decode": 0,
"video.video_backend": "pyav",
"video.extra_options": { "tune": "film", "profile:v": "high", "bf": 2 }
}
}
}
}info 块由两个来源贡献:
| 源代码 | 它的来源 | 字段 |
|---|---|---|
| 流派生 | 使用 PyAV 从编码后的 MP4 中读取数据。 | video.height, video.width, video.codec, video.pix_fmt, video.fps, video.channels, is_depth_map, audio.* |
| 编码器派生 | 取自 RGBEncoderConfig / DepthEncoderConfig。 | video.g, video.crf, video.preset, video.fast_decode, video.video_backend, video.extra_options |
此块仅从第一个剧集填充一次。它假设数据集中的每个剧集都使用相同的
rgb_encoder进行编码。不支持在录制过程中更改编码器设置——info.json仅会反映用于第一个剧集的参数。
合并数据集
使用 merge_datasets 聚合数据集时,视频文件将按原样拼接(不进行重新编码),并且 info.json 中的编码器字段会按键合并:
| 合并规则 | 字段 | 行为 |
|---|---|---|
| 必须匹配 | video.codec, video.pix_fmt, video.height, video.width, video.fps | 流派生字段必须在各个源之间保持一致,否则 FFmpeg 的 concat demuxer 将会失败。 |
| 松散合并 | video.g, video.crf, video.preset, video.fast_decode, video.extra_options | 编码器调优字段。如果所有来源一致,则保留该值;否则,将其设置为 null(对于 video.extra_options 则设置为 {}),并记录一条警告。 |