mcpField
R
rerun-lerobot

rerun-lerobot

github.com/rerun-ioデータ・データベース11.7k120 回インストール今日更新
リポジトリ

rerun-lerobot について

rerun-lerobotは、LeRobotデータセットの閲覧や変換を扱うRerun向けスキルです。内蔵インポーターと遅延評価のLeRobotReaderの使い分けに加え、ダウンロード、エピソード別のRRD作成、ロボットモデルの接続を説明します。

主な機能

  1. 01内蔵インポーターでデータセットを表示
  2. 02遅延読み込みでエピソード別にRRDを作成
  3. 03指定エピソードをダウンロードして検証
  4. 04URDFの関節を状態データに対応付け

活用シーン

  1. 01ViewerでLeRobotデータセットを閲覧
  2. 02エピソードごとにRRDファイルを出力
  3. 03エピソードデータにロボット運動学モデルを追加

MCP 対応

MCPのopen_urlでデータセットディレクトリを開いて閲覧する方法に触れていますが、MCPサーバー機能は説明されていません。

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/rerun-io/rerun --skill rerun-lerobot

インストール後、Claude Code で/rerun-lerobotを入力して読み込まれたか確認します。

同梱ファイルscripts/fetch_lerobot_episodes.pyscripts/find_lerobot_dataset.py

詳細

Rerun LeRobot の取り込み

方法は2つあり、表示するのか変換するのかによって選ぶ方法が異なります。

  • 表示するだけですか? Rerun には組み込みの LeRobot インポーターがあります。log_file_from_path(またはビューアー、CLI での rerun <dir>)にデータセットの ディレクトリ を指定すると、変換コードなしでエピソード、カメラ動画、状態/アクションのテーブルを取り込みます。
  • 変換しますか? rr.experimental.LeRobotReader は、データセットをエピソードごとに遅延チャンクストリームとして読み込みます。エピソードごとの RRD やレンズを作成する場合に適しています。

ダウンロードには huggingface_hub が必要です。

Step 0: データセットを選び、HF トークンを確認する

以下の2つのスクリプトは、このファイルと同じ場所にある scripts/ にあり、uv で単独実行できます。huggingface_hub はインラインで宣言されているため、環境のセットアップは不要です。

データセットの取得コストを決める要素は2つありますが、Hub の検索結果にはどちらも表示されません。 候補ごとに、1回の呼び出しで両方を取得してください。

uv run scripts/find_lerobot_dataset.py <query> --robot-type <robot> --want 5

codebase_version によって、一部だけダウンロードできるかどうかが決まります。

  • v2.1 以前では、エピソードごとに1つの parquet と1つの mp4 が保存されます(video_path は episode_{episode_index:06d}.mp4 で終わります)。そのため、「最初の N エピソードだけ」をダウンロードする場合、そのエピソードだけがダウンロードされます。
  • v3.0では、すべてのエピソードが少数の大きなファイルに連結されます(video_path は file-{file_index:03d}.mp4 で終わります)。そのため、一部だけを選んでもダウンロード全体と同じコストがかかります。 ユーザーが数エピソードだけを希望する場合は、ダウンロードに限り、v2.1 のデータセットを優先してください。 ファイルがローカルにあれば、LeRobotReader はどちらのバージョンからでも単一のエピソードを読み取れます。

カメラフレームの保存形式によってサイズが決まり、その差は2桁に及びます。 frames 列と MB/ep 列にその情報が表示されます。

  • mp4:video 型の特徴量で、parquet の隣にエピソードごとに1つのファイルがあります。
  • inline:image 型の特徴量で、エピソードの parquet 内に生フレームが保存されます。同じ映像でも、こちらのほうがはるかに大きくなります。

どちらのスクリプトも対象データセットの実際のサイズを報告するので、推測ではなくその数値を使ってください。 ダウンロードを始める前にユーザーにサイズを伝え、もう一方の形式にしかないものを希望された場合を除き、mp4 を優先してください。

公開データセットでは HF_TOKEN は不要ですが、設定されていない場合、Hub によってダウンロードがレート制限され、速度が抑えられます。 未設定の場合はその旨を伝え、読み取りトークンを作成するために https://huggingface.co/settings/tokens を案内し、その後 export HF_TOKEN=hf_…(または hf auth login)を実行するよう伝えてください。 必須にはせず、認証なしで続行して、ユーザーに判断を委ねてください。

[ -n "$HF_TOKEN" ] || echo "HF_TOKEN unset — downloads will be throttled"

Step 1: データセット -> 結合済み RRD を1つ作成する

すべてのエピソードを1つのファイルにまとめたい場合にのみ必要です。たとえば、単一の RRD を誰かに渡す場合や、データセットのディレクトリから再読み込みできないデータを再処理する場合です。 エピソードごとのセグメントを作成する場合は、Step 2 に進み、LeRobotReader でデータセットを直接読み込んでください。

from huggingface_hub import snapshot_download
import rerun as rr

dataset_dir = snapshot_download(repo_id=repo_id, repo_type="dataset", local_dir=dest)

with rr.RecordingStream("rerun_example_lerobot") as rec:
    rec.save(str(combined_rrd))
    rec.log_file_from_path(str(dataset_dir))  # the built-in importer

インポーターは、エピソードごとに1つのレコーディング(episode_1 のようなレコーディング ID)と、メタデータのみのルートレコーディングを出力し、すべてを単一の RRD に格納します。

ここでの rr.RecordingStream + log_file_from_path はインポーターの初期化です。取り込みパイプラインで RecordingStream が適切なのはここだけです(メッセージごとのログ記録ではなく、組み込みインポーターを動作させます)。これを rr.log を使ったメッセージごとのループに一般化しないでください。インポート後のすべての処理では、リーダーとレンズを使って再処理してください(rerun-chunk-processing:Chunk API と logging API の比較を参照)。

最初の数エピソードだけをダウンロードする
uv run scripts/fetch_lerobot_episodes.py <repo_id> --episodes 5   # prints the dataset directory

開始前にダウンロードサイズを表示し、meta/* と必要な episode_%06d ファイルをダウンロードして、meta/ をそれに合わせて絞り込み、要求したエピソードがちょうど揃ったことを検証して、取得した内容を出力します。 最後の行はデータセットのディレクトリです。その後に find や du を続けないでください。 同じことを手作業で行うと、次の3つの問題が起きます。

  • インポーターは meta/ にあるエピソード一覧を反復処理するため、meta/ を絞り込まないと、存在しないエピソードごとに警告が出ます。
  • snapshot_download は既存のディレクトリに書き込むため、以前の実行で別の N を使ったときに残ったエピソードが消えず、結果が膨らみます。
  • どちらの問題も、ビューアーで録画数を数えるまで見つかりません。そのため、このスクリプトは確認を利用者に任せず、アサーションで検証します。
ビューアーで見るだけですか?

RRD は必要ありません。ビューアーはデータセットのディレクトリをそのままインポートします。 通常のパス(rerun /path/to/dataset、または MCP 経由の open_url)を渡してください。 各エピソードはそれぞれ別の録画として読み込まれ、recording_id は episode_0、episode_1、…になります。

ステップ 2:エピソードごとに 1 つの RRD

カタログの各セグメントは 1 ファイル 1 録画であり、登録時には recording_id がセグメント ID になります。

LeRobotReader はステップ 1 の統合 RRD を先に作成せず、直接読み込みます。

reader = rr.experimental.LeRobotReader(dataset_dir)  # v2 or v3
for episode in reader.episodes():
    episode_id = f"episode_{episode:05d}"  # zero-padded; see below
    reader.stream(episode).write_rrd(
        rrd_dir / f"{episode_id}.rrd",
        application_id="my_dataset",
        recording_id=episode_id,
    )

ストリーミングは最初から最後まで遅延実行されるため、メモリ使用量はエピソードやデータセットのサイズではなく、チャンクのサイズによって制限されます。また、動画はエピソードの時間範囲に合わせて切り出されます。 B フレームのない動画(AV1、LeRobot のデフォルトコーデック)は直接ストリーミングされます。再エンコードが必要なストリーム(B フレームを含む H.264、または GOP の途中から始まる時間範囲)では、PATH 上に ffmpeg が必要です。 stream() では、entity_path_prefix、timeline、動画を完全に除外する video_mode="skip" も指定できます。

レンズを追加したり、トピックを削除したり、データを修正したりする場合は、ストリームと書き込みの間に処理を挟んでください。rerun-chunk-processing を参照してください。

すでにある RRD を分割する

ステップ 1 で作成した統合 RRD がすでにある場合、またはデータがデータセットのディレクトリ以外から取得された場合は、代わりに RrdReader で分割します。

reader = rr.chunk.RrdReader(str(combined_rrd))
for entry in reader.recordings():
    store = reader.store(store=entry)
    if not store.schema().entity_paths():  # skip the metadata-only root recording
        continue
    episode_id = zero_pad(entry.recording_id)  # episode_1 -> episode_00001
    with rr.RecordingStream("rerun_example_lerobot", recording_id=episode_id, send_properties=False) as rec:
        rec.save(str(rrd_dir / f"{episode_id}.rrd"))
        rec.send_chunks(store)

一見わかりにくい点が 2 つあります。

  • エピソード ID のゼロ埋めを行います。 episode_10 は辞書順で episode_2 より前に並びます。セグメントテーブルとビューアーは辞書順で並べ替えるため、recording_id を再割り当てするときは、固定幅になるようゼロ埋めしてください。
  • 新しいストリームで send_properties=False を指定します。 これにより、コピーしたチャンクの上に新しい録画プロパティが追加されるのを防げます。

send_chunks はソースストアの ID を保持しません。新しいストリームの recording_id が優先され、これによって名前を変更できます。

エピソードのクリーンアップ(トピックの削除、データの修正、派生コンポーネントの追加)が必要な場合は、読み込みと書き込みの間にレンズを適用してストアを処理します。reader.stream(store=entry).drop(...).lenses(...) の後に collect().write_rrd(..., recording_id=episode_id) を実行してください(rerun-chunk-processing を参照)。

計算レイヤーとエピソードごとのプロパティには、rerun-data-model の標準パターンを適用します(レイヤーの recording_id はエピソードのセグメント ID と一致する必要があります)。

ステップ 3:ロボットモデルを追加する(URDF)

LeRobot データセットに含まれているのは関節の値であり、ロボットではありません。 URDF がないと、カメラ映像と関節プロットは表示できますが、3D アームは表示されません。通常、データを見たいと依頼したユーザーが思い描いているのは、そのようなものではありません。 URDF を追加するのは順運動学のレイヤーです。これを担うのが rerun-urdf で、このセクションでは LeRobot 固有の接続方法だけを説明します。

  • URDF。 meta/info.json の robot_type に URDF の名前が記載されています(so100、so101、aloha など)。rerun-urdf にソースの一覧があります。
  • 関節名。 meta/info.json の features.observation.state.names に、列の順序で関節名が記載されています。 各ソース名を、対応する URDF の関節名に明示的にマッピングしてください。プレフィックスを削除すれば有効な URDF 名になるとは限りません。
  • 値。 observation.state は計測されたポーズで、順運動学に使用する値です。action は指令されたポーズであり、ロボットではなくプロットに使用します。
  • 単位とキャリブレーション。 データセットとロボットのドキュメントで、単位、符号、オフセットを確認してください。 ポーズを信頼する前に、エピソードの parquet に対して rerun-urdf の check_joint_mapping.py を実行してください。

順運動学のソースはエピソードごとの parquet です。インポート済みの RRD からではなく、直接読み取ります。

ParquetReader(str(episode_parquet)).stream(
    column_grouping="individual",
    index_columns=[IndexColumn.sequence("frame_index")],
).drop(content="/__properties/**")

frame_index はインポーターも使用するインデックスなので、順運動学の変換結果は動画やプロットと揃います。 URDF モデルのストリームと順運動学のストリームを各エピソードの RRD にマージし、エピソードの recording_id を保持してください(rerun-urdf の「最小構成」を参照)。 データセット全体で使用する場合、モデルは各セグメントではなく共有アセットに置きます。こちらも rerun-urdf を参照してください。

注意点

  1. log_file_from_path の対象は、データセット内のファイルではなく、データセットのルートディレクトリである必要があります。LeRobotReader も同様です。
  2. ゼロ埋めされていないエピソード ID は後続処理で正しく並べ替えられません。登録する前にゼロ埋めしてください。
  3. 結合後の RRD にはメタデータのみのルートレコーディングが含まれます。エンティティパスのないストアはスキップしてください。そうしないと空のセグメントを登録することになります。
  4. 一部しかダウンロードされていないデータセットも正常にインポートされますが、meta/ に記載されていてディスク上にないエピソードごとに警告が一度表示されます。
  5. 以前の実行で使ったディレクトリにサブセットをダウンロードすると、以前のエピソードが残ります。空のディレクトリから始めてください。
  6. image 型(インライン)のデータセットは、エピソードごとのサイズが mp4 のものの約 100 倍になることがあります。ダウンロード後ではなく、ダウンロード前に確認してください。
  7. 符号と単位を確認してください。たとえば、度単位の observation.state をラジアンを想定するロボットモデルに渡すと、順運動学の結果が誤る可能性があります。

参考資料

  • rerun-chunk-processing(LazyChunkStream、レンズ、RrdReader)
  • rerun-urdf(ロボットモデルの追加と関節値のマッピング)
  • https://github.com/rerun-io/rerun/tree/main/examples/python/dataloader の prepare_dataset.py(ダウンロード → インポート → 分割 → 登録を行う、完全で実行可能な例)および train.py(rerun.experimental.dataloader を介したトレーニング側での利用)

コメント