Huggingface.js documentation
@huggingface/lerobot
@huggingface/lerobot
用于解析托管在 Hugging Face Hub 上的 LeRobot 机器人数据集的解析器。
所有内容均通过范围 HTTP 请求读取,因此可在浏览器和 Node 中直接运行,且无需下载整个数据集即可回答关于该数据集的问题。
为什么
LeRobot 数据集有两种布局。在 v2.0 / v2.1 中,每个 episode 都有独立的视频和 parquet 文件,且 episode 索引是一个 JSON Lines 文件。在 v3.0 中,episode 被拼接进共享文件,索引为 parquet 格式,因此一个 episode 是较大文件中的一个字节范围和时间范围。
该包通过统一的 LeRobotEpisode 结构隐藏了这一差异。
安装
npm install @huggingface/lerobot
hyparquet 随附提供,用于读取 v3.0 剧集索引和帧数据。fzstd 在 hyparquet 内置的 SNAPPY 之外增加了 ZSTD 支持。两者均按需导入,因此仅需调用 info() 或列出 v2 剧集的调用方永远不会加载它们。
用法
import { LeRobotDataset } from "@huggingface/lerobot";
const dataset = new LeRobotDataset("lerobot/svla_so101_pickplace");
const info = await dataset.info();
// {
// codebaseVersion: "v3.0",
// robotType: "so100_follower",
// fps: 30,
// totalEpisodes: 50,
// totalFrames: 11939,
// cameras: [{ key: "observation.images.up", width: 640, height: 480, codec: "av1" }, ...],
// joints: { "observation.state": ["shoulder_pan.pos", "shoulder_lift.pos", ...] },
// ...
// }
const episodes = await dataset.episodes({ limit: 10 });
// [
// {
// index: 0,
// length: 303,
// durationSec: 10.1,
// tasks: ["pink lego brick into the transparent box"],
// videos: [{ cameraKey: "observation.images.up", url: "https://...", fromSec: 0, toSec: 10.1 }, ...],
// data: { url: "https://.../data/chunk-000/file-000.parquet", fromRow: 0, toRow: 303 },
// },
// ...
// ]
const episode = await dataset.episode(42);
// The episode whose `index` is 42, or undefined when there is noneoffset 统计的是索引中的位置,只有当数据集按 0、1、2、… 对剧集编号时,这些位置才与剧集索引一致。有些数据集从 10 开始编号,或跳过了已删除的剧集,因此请使用 episode(index) 来打开指定的剧集。对于按 0、1、2、… 编号的数据集,其开销与 episodes({ offset: index, limit: 1 }) 相同。
videos[].fromSec / toSec 是剧集在 url 中的偏移量。在 v3.0 中,多个剧集共享同一个文件,因此需要定位到 fromSec 并在 toSec 处停止;而在 v2.x 中,每个剧集都有独立文件,该范围恰好覆盖整个文件。
data 指向该 episode 的帧行,供希望自行绘制 observation.state 或 action 的调用方使用。fromRow 为包含边界,toRow 为不包含边界;两者均为 data.url 内部的行偏移量,而非整个数据集的索引。对于 v3,当某一页从数据文件中间开始读取时,列出 episodes 也会读取该文件的 parquet footer,以确定其起始位置。如果该文件无法读取或与 episode 元数据不一致,则 data 字段将不存在。
在分页浏览 episode 时,只需保留一个 LeRobotDataset:与 info() 类似,它会记住已遍历的 v3.0 索引文件,因此后续的翻页或 episode() 查找会直接定位到包含该数据的文件。
固定修订版本
在结果被存储或缓存到任何位置时,始终传入 commit sha,这样后续的 push 操作就无法更改你解析的内容:
const dataset = new LeRobotDataset("lerobot/svla_so101_pickplace", {
revision: "f641879e22172be7e8161d5e6c1503c2d2feb657",
});私有和受控数据集
传入您自己的 fetch 以添加凭据:
const dataset = new LeRobotDataset("my-org/private-dataset", {
additionalFetchHeaders: { Authorization: `Bearer ${accessToken}` },
});在 huggingface.co 的浏览器中,会话 Cookie 就足够了:
const dataset = new LeRobotDataset(repoId, {
fetch: (url, init) => fetch(url, { ...init, credentials: "same-origin" }),
});不获取数据的情况下进行解析
parseInfo 是纯函数,适用于已经拥有字节数据的调用方:
import { parseInfo } from "@huggingface/lerobot";
const info = parseInfo(await readFile("meta/info.json", "utf8"));对于任何无法使用的信息文件,包括 LFS 指针、截断的读取内容,或本包未实现的 codebase_version,它都会抛出异常。