Huggingface.js documentation

@huggingface/lerobot

Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

@huggingface/lerobot

Hugging Face Hub에 ν˜ΈμŠ€νŒ…λœ LeRobot λ‘œλ΄‡ 데이터셋을 μœ„ν•œ νŒŒμ„œμž…λ‹ˆλ‹€.

λͺ¨λ“  λ°μ΄ν„°λŠ” ranged HTTP μš”μ²­μ„ 톡해 μ½νžˆλ―€λ‘œ, λΈŒλΌμš°μ €μ™€ Nodeμ—μ„œ λͺ¨λ‘ λ³€κ²½ 없이 μž‘λ™ν•˜λ©°, 데이터셋에 λŒ€ν•œ μ§ˆλ¬Έμ— λ‹΅ν•˜κΈ° μœ„ν•΄ 전체 데이터셋을 λ‹€μš΄λ‘œλ“œν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

μ™œ

LeRobot 데이터셋은 두 κ°€μ§€ λ ˆμ΄μ•„μ›ƒμœΌλ‘œ μ‘΄μž¬ν•©λ‹ˆλ‹€. v2.0 / v2.1μ—μ„œλŠ” 각 μ—ν”Όμ†Œλ“œκ°€ 자체 λΉ„λ””μ˜€μ™€ parquet νŒŒμΌμ„ κ°€μ§€λ©°, μ—ν”Όμ†Œλ“œ μΈλ±μŠ€λŠ” JSON Lines νŒŒμΌμž…λ‹ˆλ‹€. v3.0μ—μ„œλŠ” μ—ν”Όμ†Œλ“œκ°€ 곡유 파일둜 μ—°κ²°λ˜κ³  μΈλ±μŠ€κ°€ parquetμ΄λ―€λ‘œ, μ—ν”Όμ†Œλ“œλŠ” 더 큰 파일 μ•ˆμ˜ λ°”μ΄νŠΈ λ²”μœ„μ™€ μ‹œκ°„ λ²”μœ„λ₯Ό μ˜λ―Έν•©λ‹ˆλ‹€.

이 νŒ¨ν‚€μ§€λŠ” κ·Έ 차이λ₯Ό ν•˜λ‚˜μ˜ 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 none

offset은 인덱슀 λ‚΄μ˜ μœ„μΉ˜λ₯Ό μ„Έλ©°, 데이터셋이 μ—ν”Όμ†Œλ“œλ₯Ό 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λŠ” ν•΄λ‹Ή μ—ν”Όμ†Œλ“œμ˜ ν”„λ ˆμž„ 행을 가리킀며, observation.state λ˜λŠ” actionλ₯Ό 직접 차트둜 ν‘œμ‹œν•˜λ €λŠ” 호좜자λ₯Ό μœ„ν•œ κ²ƒμž…λ‹ˆλ‹€. fromRowλŠ” ν¬ν•¨λ˜κ³  toRowλŠ” μ œμ™Έλ©λ‹ˆλ‹€. λ‘˜ λ‹€ 데이터셋 μ „μ²΄μ˜ μΈλ±μŠ€κ°€ μ•„λ‹ˆλΌ data.url λ‚΄λΆ€μ˜ ν–‰ μ˜€ν”„μ…‹μž…λ‹ˆλ‹€. v3의 경우, νŽ˜μ΄μ§€κ°€ 데이터 파일 μ€‘κ°„μ—μ„œ μ‹œμž‘λ˜λ©΄ μ—ν”Όμ†Œλ“œλ₯Ό λ‚˜μ—΄ν•  λ•Œ ν•΄λ‹Ή 파일의 parquet ν‘Έν„°λ₯Ό μ½μ–΄μ„œ μ‹œμž‘ μœ„μΉ˜λ₯Ό μ°ΎμŠ΅λ‹ˆλ‹€. νŒŒμΌμ„ 읽을 수 μ—†κ±°λ‚˜ μ—ν”Όμ†Œλ“œ 메타데이터와 μΌμΉ˜ν•˜μ§€ μ•ŠμœΌλ©΄ dataκ°€ μ—†μŠ΅λ‹ˆλ‹€.

LeRobotDataset ν•˜λ‚˜λ₯Ό μœ μ§€ν•˜λ©΄μ„œ μ—ν”Όμ†Œλ“œλ₯Ό νŽ˜μ΄μ§€λ³„λ‘œ νƒμƒ‰ν•©λ‹ˆλ‹€. info()와 λ§ˆμ°¬κ°€μ§€λ‘œ, v3.0 인덱슀 파일 쀑 이미 νƒμƒ‰ν•œ νŒŒμΌμ„ κΈ°μ–΅ν•˜λ―€λ‘œ μ΄ν›„μ˜ νŽ˜μ΄μ§€λ‚˜ episode() μ‘°νšŒλŠ” ν•΄λ‹Ή 데이터λ₯Ό ν¬ν•¨ν•˜λŠ” 파일둜 λ°”λ‘œ μ΄λ™ν•©λ‹ˆλ‹€.

리비전 κ³ μ •

κ²°κ³Όκ°€ 어디에 μ €μž₯λ˜κ±°λ‚˜ μΊμ‹œλ˜λŠ” 경우, λ‚˜μ€‘μ— pushλ₯Ό 톡해 νŒŒμ‹±ν•œ λ‚΄μš©μ΄ λ³€κ²½λ˜μ§€ μ•Šλ„λ‘ 항상 commit shaλ₯Ό μ „λ‹¬ν•˜μ„Έμš”:

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의 λΈŒλΌμš°μ €μ—μ„œλŠ” μ„Έμ…˜ μΏ ν‚€λ§Œ 있으면 μΆ©λΆ„ν•©λ‹ˆλ‹€:

const dataset = new LeRobotDataset(repoId, {
	fetch: (url, init) => fetch(url, { ...init, credentials: "same-origin" }),
});

fetching 없이 νŒŒμ‹±

parseInfoλŠ” 순수 ν•¨μˆ˜λ‘œ, 이미 λ°”μ΄νŠΈλ₯Ό κ°€μ§„ ν˜ΈμΆœμžμ—κ²Œ μ ν•©ν•©λ‹ˆλ‹€:

import { parseInfo } from "@huggingface/lerobot";

const info = parseInfo(await readFile("meta/info.json", "utf8"));

μ‚¬μš©ν•  수 μžˆλŠ” info 파일이 μ•„λ‹Œ λͺ¨λ“  ν•­λͺ©μ—μ„œ μ˜ˆμ™Έλ₯Ό λ°œμƒμ‹œν‚€λ©°, μ—¬κΈ°μ—λŠ” LFS 포인터, 잘린 읽기, 이 νŒ¨ν‚€μ§€κ°€ κ΅¬ν˜„ν•˜μ§€ μ•Šμ€ codebase_version이 ν¬ν•¨λ©λ‹ˆλ‹€.

Update on GitHub