LeRobot documentation

LeRobotDataset v3.0

You are viewing main version, which requires installation from source. If you'd like regular pip install, checkout the latest stable version (v0.6.1).
Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

LeRobotDataset v3.0

LeRobotDataset v3.0 là định dạng chuẩn hóa cho dữ liệu học tập của robot. Nó cung cấp khả năng truy cập thống nhất vào dữ liệu chuỗi thời gian đa phương thức, tín hiệu cảm giác - vận động và video đa camera, cũng như các metadata phong phú để lập chỉ mục, tìm kiếm và trực quan hóa trên Hugging Face Hub.

Để xem một dataset ở định dạng này chứa những gì trước khi đọc về cấu trúc của nó, hãy mở một dataset trong LeRobot Dataset Visualizer: các bản ghi camera, biểu đồ trạng thái và hành động được đồng bộ hóa, cùng mọi episode, ngay trong trình duyệt. Xem Explore a Dataset in the Browser.

Tài liệu này sẽ hướng dẫn bạn:

  • Hiểu thiết kế và bố cục thư mục của v3.0
  • Ghi lại một bộ dữ liệu và đẩy nó lên Hub
  • Tải bộ dữ liệu để huấn luyện với LeRobotDataset
  • Dòng dữ liệu mà không cần tải xuống bằng StreamingLeRobotDataset
  • Áp dụng các phép biến đổi ảnh để tăng cường dữ liệu trong quá trình huấn luyện
  • Chuyển đổi các bộ dữ liệu v2.1 hiện có sang v3.0
  • Thử nghiệm với các định dạng và triển khai LeRobotDataset khác như Lance

Những gì mới trong v3

  • Lưu trữ dựa trên tệp: Nhiều tập (episodes) trong mỗi tệp Parquet/MP4 (phiên bản v2 sử dụng một tệp cho mỗi tập).
  • Metadata quan hệ: Ranh giới tập và tra cứu được giải quyết thông qua metadata, không phải tên tệp.
  • Truyền trực tiếp trên Hub: Sử dụng các bộ dữ liệu trực tiếp từ Hub với StreamingLeRobotDataset.
  • Giảm áp lực lên hệ thống tệp: Ít tệp hơn, tệp lớn hơn ⇒ khởi tạo nhanh hơn và ít vấn đề hơn khi mở rộng quy mô.
  • Tổ chức thống nhất: Bố cục thư mục gọn gàng với các mẫu đường dẫn nhất quán xuyên suốt dữ liệu và video.
  • Các backend lưu trữ Dataset: Datasets cũng có thể được lưu trữ dưới dạng bảng LanceDB để truy cập ngẫu nhiên và lập chỉ mục trực tiếp từ object storage (xem backend dataset LanceDB).

Cài đặt

LeRobotDataset v3.0 được bao gồm trong lerobot >= 0.4.0. Hãy làm theo Hướng dẫn cài đặt để cài đặt.

Ghi lại một bộ dữ liệu

Chạy lệnh bên dưới để ghi lại một bộ dữ liệu với SO-101 và đẩy lên Hub:

lerobot-record \
  --robot.type=so101_follower \
  --robot.port=/dev/tty.usbmodem585A0076841 \
  --robot.id=my_awesome_follower_arm \
  --robot.cameras="{ front: {type: opencv, index_or_path: 0, width: 1920, height: 1080, fps: 30}}" \
  --teleop.type=so101_leader \
  --teleop.port=/dev/tty.usbmodem58760431551 \
  --teleop.id=my_awesome_leader_arm \
  --display_data=true \
  --dataset.repo_id=${HF_USER}/record-test \
  --dataset.num_episodes=5 \
  --dataset.single_task="Grab the black cube" \
  --dataset.streaming_encoding=true \
  --dataset.encoder_threads=2
# Optional: --dataset.rgb_encoder.vcodec=auto

Xem hướng dẫn ghi hình để biết thêm chi tiết.

Thiết kế định dạng

Một nguyên tắc cốt lõi của v3 là tách biệt lưu trữ khỏi API người dùng: dữ liệu được lưu trữ hiệu quả (ít tệp lớn), trong khi API công khai cung cấp khả năng truy cập trực quan ở cấp độ episode.

v3 có ba trụ cột:

  1. Dữ liệu bảng: Các tín hiệu tần số cao, số chiều thấp (trạng thái, hành động, mốc thời gian) được lưu trữ trong Apache Parquet. Việc truy cập được thực hiện bằng cách ánh xạ bộ nhớ hoặc truyền trực tiếp thông qua stack datasets.
  2. Dữ liệu thị giác: Các khung hình từ camera được ghép nối và mã hóa thành MP4. Các khung hình từ cùng một episode được nhóm lại; video được chia shard theo từng camera để có kích thước thực tế.
  3. Metadata: các bản ghi JSON/Parquet mô tả schema (tên tính năng, dtype, hình dạng), tốc độ khung hình, thống kê chuẩn hóa và phân đoạn episode (offset bắt đầu/kết thúc trong các tệp Parquet/MP4 dùng chung).

Để mở rộng lên hàng triệu episode, các hàng bảng và khung hình video từ nhiều episode được nối vào các tệp lớn hơn. Các view cụ thể cho từng episode được tái tạo thông qua metadata, không phải qua ranh giới tệp.

LeRobotDataset v3 diagram
Từ tập dữ liệu theo tập (episode) sang tập dữ liệu theo tệp

Bố cục thư mục (đơn giản hóa)

  • meta/info.json: schema chuẩn (features, shapes/dtypes), FPS, phiên bản codebase, và path templates để xác định vị trí các shard dữ liệu/video.
  • meta/stats.json: thống kê đặc trưng toàn cục (trung bình/độ lệch chuẩn/tối thiểu/tối đa) dùng để chuẩn hóa; được phơi bày dưới dạng dataset.meta.stats.
  • meta/tasks.parquet: mô tả các tác vụ ngôn ngữ tự nhiên được ánh xạ đến các ID số nguyên cho các chính sách có điều kiện theo tác vụ.
  • meta/episodes/: bản ghi theo từng episode (độ dài, tác vụ, offset) được lưu dưới dạng chunked Parquet để đảm bảo khả năng mở rộng.
  • data/: các shard Parquet theo từng khung hình; mỗi tệp thường chứa nhiều episode.
  • videos/: các shard MP4 cho mỗi camera; mỗi tệp thường chứa nhiều episode.

Tải một bộ dữ liệu để huấn luyện

LeRobotDataset trả về các từ điển Python chứa các tensor PyTorch và tích hợp với torch.utils.data.DataLoader. Dưới đây là một ví dụ mã nguồn cho thấy cách sử dụng nó:

import torch
from lerobot.datasets import LeRobotDataset

repo_id = "yaak-ai/L2D-v3"

# 1) Load from the Hub (cached locally)
dataset = LeRobotDataset(repo_id)

# 2) Random access by index
sample = dataset[100]
print(sample)
# {
#   'observation.state': tensor([...]),
#   'action': tensor([...]),
#   'observation.images.front_left': tensor([C, H, W]),
#   'timestamp': tensor(1.234),
#   ...
# }

# 3) Temporal windows via delta_timestamps (seconds relative to t)
delta_timestamps = {
    "observation.images.front_left": [-0.2, -0.1, 0.0]  # 0.2s and 0.1s before current frame
}

dataset = LeRobotDataset(repo_id, delta_timestamps=delta_timestamps)

# Accessing an index now returns a stack for the specified key(s)
sample = dataset[100]
print(sample["observation.images.front_left"].shape)  # [T, C, H, W], where T=3

# 4) Wrap with a DataLoader for training
batch_size = 16
data_loader = torch.utils.data.DataLoader(dataset, batch_size=batch_size)

device = "cuda" if torch.cuda.is_available() else "cpu"
for batch in data_loader:
    observations = batch["observation.state"].to(device)
    actions = batch["action"].to(device)
    images = batch["observation.images.front_left"].to(device)
    # model.forward(batch)

Dòng chảy một tập dữ liệu trong quá trình huấn luyện

Đặt --dataset.streaming=true để huấn luyện mà không cần tải trước các tệp Parquet và video của bộ dữ liệu. Các episode được lấy theo thời gian thực vào một bộ đệm trong bộ nhớ có giới hạn, và mỗi khung hình được chọn vẫn được truy cập đúng một lần mỗi epoch:

lerobot-train \
  --dataset.repo_id=yaak-ai/L2D-v3 \
  --dataset.streaming=true \
  --policy.type=act \
  --output_dir=outputs/train/act_streaming

Cùng một trình đọc này có sẵn trong Python, dành cho các bộ dữ liệu trên Hub và cho các bộ dữ liệu được lưu trữ trong HF Storage Bucket:

from lerobot.datasets import StreamingLeRobotDataset

dataset = StreamingLeRobotDataset("yaak-ai/L2D-v3")
bucket_dataset = StreamingLeRobotDataset("my-org/my-bucket", repo_type="bucket")

Từ CLI, hãy chọn một bucket bằng --dataset.repo_type=bucket hoặc --dataset.root=hf://buckets/my-org/my-bucket.

Xem Training Dataset Streaming để biết cách các worker và shard được ánh xạ tới độ song song của streaming, chỉ mục sidecar MP4, cài đặt bộ nhớ, tiếp tục và khắc phục sự cố.

StreamingLeRobotDataset
Truyền trực tiếp từ Hub để huấn luyện ngay lập tức.

Biến đổi ảnh

Biến đổi hình ảnh là các kỹ thuật tăng cường dữ liệu được áp dụng cho các khung hình từ camera trong quá trình huấn luyện nhằm cải thiện độ bền vững và khả năng tổng quát hóa của mô hình. LeRobot hỗ trợ nhiều loại biến đổi khác nhau, bao gồm điều chỉnh độ sáng, độ tương phản, độ bão hòa, sắc độ và độ sắc nét.

Sử dụng transforms trong quá trình tạo/ghi lại tập dữ liệu

Hiện tại, các phép biến đổi chỉ được áp dụng trong quá trình huấn luyện, không áp dụng khi ghi nhận. Khi bạn tạo hoặc ghi nhận một tập dữ liệu, các hình ảnh thô được lưu trữ mà không có phép biến đổi. Điều này cho phép bạn thử nghiệm các phương pháp tăng cường dữ liệu khác nhau sau đó mà không cần ghi nhận lại dữ liệu.

Thêm các phép biến đổi vào các bộ dữ liệu hiện có (API)

Sử dụng tham số image_transforms khi tải bộ dữ liệu để huấn luyện:

from lerobot.datasets import LeRobotDataset
from lerobot.transforms import ImageTransforms, ImageTransformsConfig, ImageTransformConfig

# Option 1: Use default transform configuration (disabled by default)
transforms_config = ImageTransformsConfig(
    enable=True,  # Enable transforms
    max_num_transforms=3,  # Apply up to 3 transforms per frame
    random_order=False,  # Apply in standard order
)
transforms = ImageTransforms(transforms_config)

dataset = LeRobotDataset(
    repo_id="your-username/your-dataset",
    image_transforms=transforms
)

# Option 2: Create custom transform configuration
custom_transforms_config = ImageTransformsConfig(
    enable=True,
    max_num_transforms=2,
    random_order=True,
    tfs={
        "brightness": ImageTransformConfig(
            weight=1.0,
            type="ColorJitter",
            kwargs={"brightness": (0.7, 1.3)}  # Adjust brightness range
        ),
        "contrast": ImageTransformConfig(
            weight=2.0,  # Higher weight = more likely to be selected
            type="ColorJitter",
            kwargs={"contrast": (0.8, 1.2)}
        ),
        "sharpness": ImageTransformConfig(
            weight=0.5,  # Lower weight = less likely to be selected
            type="SharpnessJitter",
            kwargs={"sharpness": (0.3, 2.0)}
        ),
    }
)

dataset = LeRobotDataset(
    repo_id="your-username/your-dataset",
    image_transforms=ImageTransforms(custom_transforms_config)
)

# Option 3: Use pure torchvision transforms
from torchvision.transforms import v2

torchvision_transforms = v2.Compose([
    v2.ColorJitter(brightness=0.2, contrast=0.2, saturation=0.2, hue=0.1),
    v2.GaussianBlur(kernel_size=3, sigma=(0.1, 2.0)),
])

dataset = LeRobotDataset(
    repo_id="your-username/your-dataset",
    image_transforms=torchvision_transforms
)

Các loại biến đổi khả dụng

type của một transform có thể là bất kỳ class nào từ torchvision.transforms.v2, ví dụ:

  • ColorJitter: Điều chỉnh độ sáng, độ tương phản, độ bão hòa và sắc độ
  • SharpnessJitter: Điều chỉnh độ sắc nét của ảnh một cách ngẫu nhiên
  • RandomAffine, RandomRotation: nhiễu hình học
  • GaussianNoise, MotionBlur, JPEGCompression, GaussianPatchBrightness, RandomShadow, CoarseDropout, GammaCorrection, PlanckianJitter: Hiệu ứng camera và ánh sáng thường thấy trên robot thực
  • Identity: Không biến đổi (hữu ích cho việc kiểm thử)

Bất kỳ lớp nào khác của torchvision.transforms.v2 cũng có thể được đặt tên như một type (ví dụ RandomResizedCrop hoặc GaussianBlur); nó được áp dụng cho từng mẫu một. Bạn cũng có thể truyền trực tiếp một torchvision transform vào tham số image_transforms.

Mọi transform giờ đây đều được batch, và các transform batched giống nhau chạy trên cả hai backend. Các lớp theo mẫu (SharpnessJitter, GaussianNoise, MotionBlur, GaussianPatchBrightness, RandomShadow, CoarseDropout, GammaCorrection, PlanckianJitter, RandomSubsetApply) và make_transform_from_config vẫn có thể import được như các front end đã bị deprecate trên các bản thay thế Batched* của chúng và sẽ cảnh báo khi sử dụng; chúng sẽ bị loại bỏ trong một bản phát hành tương lai. ImageTransforms là một torch.nn.Module thông thường nhận tensor (C, H, W) hoặc (T, C, H, W). Các cấu hình gọi tên transform bằng type không bị ảnh hưởng.

Thay đổi hành vi đối với các công thức hiện có. Quá trình huấn luyện đọc các khung hình dưới dạng uint8, và các phép biến đổi LeRobot khác ngoài ColorJitter, RandomAffine và RandomRotation trước đây sẽ trả về đầu vào không phải float mà không thay đổi. Do đó, các công thức bật GaussianNoise, MotionBlur, GaussianPatchBrightness, RandomShadow, CoarseDropout, GammaCorrection hoặc PlanckianJitter trước đó đã được huấn luyện mà không áp dụng chúng. Giờ đây, chúng được áp dụng trên cả hai backend, vì vậy một công thức như vậy sẽ được huấn luyện khác so với trước: nó nhận được phép tăng cường dữ liệu mà nó đã yêu cầu. Các phép biến đổi vốn đã được áp dụng sẽ không thay đổi, ngoại trừ việc làm tròn, vì đường dẫn batched tính toán bằng float và chỉ làm tròn một lần ở cuối thay vì sau mỗi phép biến đổi.

Các tùy chọn cấu hình

  • enable: Bật/tắt các phép biến đổi (mặc định: False)
  • max_num_transforms: Số lượng biến đổi tối đa được áp dụng cho mỗi khung hình (mặc định: 3)
  • random_order: Áp dụng các phép biến đổi theo thứ tự ngẫu nhiên so với thứ tự chuẩn (mặc định: False)
  • weight: Xác suất lấy mẫu cho mỗi phép biến đổi (giá trị cao hơn = khả năng cao hơn, nếu tổng các trọng số không bằng 1, chúng sẽ được chuẩn hóa)
  • kwargs: Các tham số cụ thể cho phép biến đổi (ví dụ: khoảng độ sáng)
  • backend: Nơi các transforms được thực thi trong quá trình huấn luyện, "dataloader" (mặc định) hoặc "gpu"; xem bên dưới
  • gpu_compile: Trên backend "gpu", torch.compile các biến đổi dạng batch (mặc định: True)
  • gpu_chunk_size: Trên backend "gpu", tăng cường từng nhóm mẫu có kích thước này để giới hạn bộ nhớ tạm thời (mặc định: 32)

Chạy các phép biến đổi trên GPU

Mặc định, các transforms được thực hiện theo từng mẫu trong các worker của DataLoader. Với nhiều camera, đây thường là phần tốn kém nhất mà các worker thực hiện, khiến GPU phải chờ dữ liệu. Đặt backend=gpu để các worker chỉ giải mã và áp dụng cùng các transforms cho mỗi batch trên thiết bị của policy:

lerobot-train \
  --dataset.repo_id=your-username/your-dataset \
  --dataset.image_transforms.enable=true \
  --dataset.image_transforms.backend=gpu \
  --policy.type=act \
  --policy.device=cuda

Việc ngẫu nhiên hóa không thay đổi: mỗi mẫu tự rút các phép biến đổi và tham số của riêng mình, và các khung hình trong lịch sử của một camera sẽ dùng chung chúng. Tăng cường dữ liệu chỉ được áp dụng cho các lô huấn luyện, trước bộ tiền xử lý chính sách; các lô đánh giá, các lượt rollout và các checkpoint đã lưu giữ nguyên không thay đổi.

Những điều cần biết:

  • Yêu cầu một bộ tăng tốc; --policy.device=cpu sẽ bị từ chối. Một dataset được xây dựng thủ công với callable image_transforms riêng của nó cũng sẽ bị từ chối, vì những callable này được thực thi trong các worker.
  • Hỗ trợ mọi loại transform mà backend dataloader hỗ trợ. Các loại không có triển khai dạng batch (JPEGCompression, và các lớp torchvision khác ngoài ColorJitter, RandomAffine, RandomRotation và Identity) được áp dụng lần lượt từng mẫu một bên trong batch, do đó không nhận được lợi ích tăng tốc; JPEGCompression cũng phải đi qua CPU. Một transform làm thay đổi kích thước khung hình sẽ bị từ chối trên một batch có nhiều hơn một mẫu.
  • Có thể tái lập từ --seed, với mỗi tiến trình được gán hạt giống khác nhau. Việc tăng cường dữ liệu không tiêu thụ luồng ngẫu nhiên của chính sách, và gpu_compile cùng gpu_chunk_size không làm thay đổi những gì được áp dụng.
  • Cả hai backend đều chạy các biến đổi dạng batch giống nhau ở dạng float và làm tròn một lần ở cuối, do đó một mẫu được tăng cường trên backend này sẽ bằng cùng mẫu đó được tăng cường trên backend kia khi sử dụng cùng các tham số.
  • gpu_compile mất 15-30 giây một lần cho mỗi hình ảnh shape. Bộ nhớ đỉnh khoảng hai bản sao float của các hình ảnh trong batch cộng thêm vài bản sao của một chunk; giảm gpu_chunk_size nếu bộ nhớ hạn chế. random_order=true nhân thời gian transform lên max_num_transforms lần.

Chuyển từ v2.1 → v3.0

Bộ chuyển đổi (converter) tập hợp các tệp theo từng tập (episode) thành các shard lớn hơn và ghi các offset/metadata của tập. Hãy chuyển đổi bộ dữ liệu của bạn bằng cách làm theo các hướng dẫn bên dưới.

# Convert an existing v2.1 dataset hosted on the Hub:
python -m lerobot.scripts.convert_dataset_v21_to_v30 --repo-id=<HF_USER/DATASET_ID>

Nó hoạt động như thế nào

  • Gộp các tệp parquet: episode_000000.parquet, episode_000001.parquet, … → file-000.parquet, …
  • Gộp các tệp mp4: episode_000000.mp4, episode_000001.mp4, … → file-000.mp4, …
  • Cập nhật meta/episodes/* (Parquet phân mảnh) với độ dài, tác vụ và vị trí byte/khung cho từng tập.

Các vấn đề thường gặp

Luôn gọi finalize() trước khi đẩy

Khi tạo hoặc ghi các bộ dữ liệu, bạn phải gọi dataset.finalize() để đóng các trình ghi parquet một cách chính xác. Xem PR #1903 để biết thêm chi tiết.

from lerobot.datasets import LeRobotDataset

# Create dataset and record episodes
dataset = LeRobotDataset.create(...)

for episode in range(num_episodes):
    # Record frames
    for frame in episode_data:
        dataset.add_frame(frame)
    dataset.save_episode()

# Call finalize() when done recording and before push_to_hub()
dataset.finalize()  # Closes parquet writers, writes metadata footers
dataset.push_to_hub()

Tại sao điều này là cần thiết?

Dataset v3.0 sử dụng ghi parquet tăng dần với metadata được đệm để tối ưu hiệu suất. Phương thức finalize():

  • Xả mọi metadata tập được đệm xuống đĩa
  • Đóng các trình ghi parquet để ghi metadata phần chân, nếu không các tệp parquet sẽ bị hỏng
  • Đảm bảo tập dữ liệu hợp lệ để tải

Nếu không gọi finalize(), các tệp parquet của bạn sẽ không hoàn chỉnh và bộ dữ liệu sẽ không được nạp đúng cách.

Các định dạng và triển khai khác

Hậu trường bộ dữ liệu LanceDB

Một dataset v3 cũng có thể được lưu trữ dưới dạng bảng LanceDB. LanceDB là một data lakehouse đa phương thức được xây dựng trên định dạng Lance cho các mẫu truy cập của AI: truy cập ngẫu nhiên nhanh đến bất kỳ hàng nào cùng với byte video của nó, và các chỉ mục scalar, vector và full-text trên cùng các bảng, nhờ đó EDA, khai thác, tuyển chọn và huấn luyện được thực hiện trực tiếp từ object storage. Bố cục giữ nguyên meta/ và thêm bảng frames cho dữ liệu bảng tính cùng bảng videos chứa các tệp MP4 dưới dạng blob. "storage_format": "lance" trong meta/info.json chọn trình đọc; API LeRobotDataset, các mục và pipeline huấn luyện không thay đổi.

  • Đào tạo trực tiếp từ Hub hoặc HF Storage Buckets với các GPU được cung cấp dữ liệu. Các khung ngẫu nhiên được đọc tại chỗ, chỉ đọc các byte mà mỗi batch cần, do đó mỗi batch là một lần xáo trộn toàn cục và không có gì được tải xuống trước.
  • Chuyển đổi với chi phí tương đương sao chép tệp. Video không được mã hóa lại, do đó các mục giống hệt về bit so với nguồn. DROID chuyển đổi trong 34 phút.
  • Kỹ thuật đặc trưng không sao chép (zero-copy). Thêm các cột như điểm số, nhúng (embeddings) hoặc nhãn đã hiệu chỉnh vào các bảng mà trình huấn luyện đọc, mà không cần ghi đè lại các video hay sao chép bộ dữ liệu, sau đó lọc và tìm kiếm trên chúng bằng các chỉ mục. Trình đọc sẽ bỏ qua các cột mà nó không nhận biết.

Để tìm hiểu cách hoạt động, các bài kiểm tra hiệu năng và ví dụ, hãy xem hướng dẫn LanceDB LeRobot.

Các tính năng camera phải được hỗ trợ bằng video. Các tập dữ liệu lưu trữ khung hình camera dưới dạng ảnh không được trình đọc hỗ trợ và cần được mã hóa lại thành video trước khi chuyển đổi.

Đọc các tập dữ liệu Lance cần thêm phần phụ lancedb (pip install "lerobot[lancedb]"). Định dạng này chỉ đọc: hãy ghi và chỉnh sửa các tập dữ liệu ở định dạng mặc định, sau đó chuyển đổi chúng bằng gói lerobot-lancedb:

pip install "lerobot-lancedb"
lerobot-lance-convert --repo-id lerobot/pusht --out ./pusht-lance  # or --root <local dataset dir>

Việc tải sử dụng cùng một lớp:

from lerobot.datasets import LeRobotDataset

# Hub dataset repo
dataset = LeRobotDataset("lance-format/pusht-lance")

# HF Storage Bucket, read in place
dataset = LeRobotDataset("my-org/pusht-lance", repo_type="bucket")

# the same bucket as a root URI (other object store URIs work the same way)
dataset = LeRobotDataset("lerobot/pusht", root="hf://buckets/my-org/pusht-lance")

Các tùy chọn HF Storage Bucket hoạt động trong lerobot-train:

lerobot-train \
  --dataset.repo_id=my-org/pusht-lance \
  --dataset.repo_type=bucket \
  --policy.type=act

Visualization hoạt động với cả hai trình xem. lerobot-dataset-viz --repo-id lance-format/pusht-lance --episode-index 0 mở một episode trong Rerun như bình thường, và --display-mode foxglove cung cấp nó cho Foxglove qua WebSocket. Dù theo cách nào, chỉ các khung hình trên màn hình mới được lấy, không có xuất hay tải xuống MCAP.

Update on GitHub