ABEJA Tech Blog

中の人の興味のある情報を発信していきます

SmolVLA×SO-101で色付きキューブ搬送【同期推論】

はじめに

こんにちは!ABEJAでエンジニアをしている宇留嶋です。2025年5月にオープンソース化されたSO‑101ロボットアームとHugg­ing FaceのLeRobotライブラリを活用し今回Vision‑Language‑Action(VLA)モデルSmolVLAをファインチューニングして「色付きキューブを所定エリアに運ぶ」タスクに挑戦しました。本記事では、データセット作成から学習・評価までの手順と結果をご紹介します。

SO‑101アームの組み立て・模倣学習やTPU製グリッパー検証については、以前公開した以下の記事もぜひご覧ください。 tech-blog.abeja.asia tech-blog.abeja.asia tech-blog.abeja.asia

SmolVLAの非同期推論はこちらの記事で検証しております。 tech-blog.abeja.asia

SmolVLAとは

SmolVLA

SmolVLAは小型で効率的なオープンソースのVision‑Language‑Actionモデルです。450Mパラメータで単一GPU/CPUでも学習・推論でき、巨大モデルの高コスト問題を避けることができます。LeRobotコミュニティデータの約2.29万エピソードだけで事前学習されており、層スキップや視覚トークン削減、フローマッチングで高速化しています。また非同期推論スタックにより「知覚 → 行動予測 → 実行」をパイプライン化し、高い制御レートを実現している点も特徴です。(arXiv, Hugging Face)

タスク設定とデータセット作成

タスク概要

今回タスクは以下を設定しました。

  • 対象物:赤・青 2 色のキューブ(各 2 cm³)
  • 目標:キューブを黒い四角形エリアの内部へ移動させる

タスク

環境

カメラは以下の3台を使用しました。

  • MacBook M3 内蔵カメラ
  • iPhone 14
  • InnoMaker UVCカメラ(SO-ARMのリストカメラとして利用)

カメラ位置は以下画像の通りです。

カメラ位置

データセット作成

データセット作成には30fps, 1エピソード30秒で記録しました。収集したデータはHugging Faceへ公開しました。 データの視覚的な確認には公式スペースのLeRobot Dataset Visualizerを活用すると便利です。

実際にデータセット作成に使用したコマンド

uv run python -m lerobot.record \
  --robot.type=so101_follower \
  --robot.port="/dev/tty.usbmodem5A4B0468471" \ # フォローアームポート情報
  --robot.cameras="{
      top: {type: opencv, index_or_path: 1, width: 640, height: 480},
      iphone: {type: opencv, index_or_path: 2, width: 1280, height: 720},
      wrist: {type: opencv, index_or_path: 0, width: 640, height: 360}
  }" \  # 各種カメラ設定
  --robot.id=main_follower \
  --dataset.repo_id="repo_id" # Hugging Face Datasetへpushするリポジトリ名 \
  --dataset.single_task="Move the red cube into the black square area." # 指示テキスト \
  --dataset.num_episodes=5 # エピソード数 \
  --dataset.episode_time_s=30 # エピソード時間  \
  --dataset.reset_time_s=5 # エピソードリセット時間 \
  --dataset.fps=30 # fps \
  --dataset.video=true \
  --dataset.push_to_hub=true \
  --teleop.type=so101_leader \
  --teleop.port="/dev/tty.usbmodem5A4B0468211" # リーダーアームポート情報 \
  --teleop.id=main_leader \
  --display_data=true \
  --play_sounds=true

今回作成したデータセット

タスク エピソード数 テキストプロンプト データセット
赤キューブ 100 Move the red cube into the black square area. Hugging Face Dataset URL
青キューブ 100 Move the blue cube into the black square area. Hugging Face Dataset URL

LeRobot Dataset Visualizerを使った可視化 https://huggingface.co/spaces/lerobot/visualize_dataset?path=%2Fyuto-urushima%2Fso101_move_blue_cube_001_020%2Fepisode_0

データセットビューワ

テキストプロンプトはデータセットのメタデータとして meta/episodes.jsonl および meta/tasks.jsonl に、

"task": "Move the blue cube into the black square area."

という形で保存されます。

SmolVLA のファインチューニング

ベースモデル lerobot/smolvla_baseを起点として、今回作成したデータセットでファインチューニングしました。主要パラメータは以下のとおりです。

  • 学習ステップ数:20k
  • バッチサイズ:64
  • 計算資源:Google Colab A100 × 1

コマンドは以下になります。

!python lerobot/src/lerobot/scripts/train.py \
  --policy.path=lerobot/smolvla_base \
  --dataset.repo_id="yuto-urushima/so101_move_cube"  # データセット名 \
  --batch_size=64 # バッチサイズ \
  --steps=20000 # 学習ステップ数 \
  --output_dir="output_dir" # モデルのアウトプット先 \
  --job_name="job_name" # ジョブ名 \
  --policy.device="cuda" # モデルをどの計算機で学習するか cuda | mps | cpu \
  --wandb.enable="true" # wandbにlogを出すか \
  --policy.repo_id="repo_id" # Hugging Face Modelへpushするリポジトリ名

スパイクはあるもののLossは下がっていました。

wandb log

ファインチューニングには約5時間かかりました。 モデルはsmolvla-move-cubeにて公開しています。

評価と結果

評価はMacBook(Apple Silicon, mps)上でSmolVLAモデルを動作させて実施しました。 ファインチューニング済みモデルを SO‑101にデプロイし、各タスクを25エピソードづつテストを行いました。 以下実際にSmolVLAを使ってSO-ARMを動かすコマンドになります。

uv run python -m lerobot.record \
  --robot.type=so101_follower \
  --robot.port="/dev/tty.usbmodem5A4B0468471"  # フォローアームポート情報 \
  --robot.cameras="{}" # 各種カメラ設定 \
  --robot.id=main_follower \
  --dataset.repo_id="repo_id" # Hugging Face Datasetへpushするリポジトリ名 \
  --dataset.single_task="Move the red cube into the black square area." # 指示テキスト \
  --dataset.num_episodes=25 # エピソード数 \
  --dataset.episode_time_s=30 # エピソード時間 \
  --dataset.reset_time_s=5 # エピソードリセット時間 \
  --dataset.fps=30 # fps \
  --dataset.push_to_hub=true \
  --policy.path="yuto-urushima/smolvla-move-cube" # モデルのリポジトリ名 \
  --policy.device="mps" # モデルをどの計算機で動かすか cuda | mps | cpu \
  --display_data=true

結果としては以下のように70%以上タスクを完了することができました。

キューブの色 検証回数 成功 成功率
25 19 76%
25 18 72%

失敗ケースでは、

  • キューブを把持できない
  • episode timeをオーバーしてしまう

といったパターンが観察されました。

一度は把持に失敗しましたが、再試行で掴み直しに成功しました。データ収集時にキューブの位置を約1 cmずつ意図的にずらしていたことが、わずかな誤差への耐性を学習させ、結果としてこのリカバリ動作につながった可能性があります。

  • 青キューブ成功例

    www.youtube.com

    赤キューブだけでなく青キューブでもタスクを完遂し、本モデルが単一タスクに閉じないマルチタスク性を獲得していることがわかります。

  • 赤キューブ失敗例

    www.youtube.com

    一度把持に失敗しキューブが大きく動いてしまうとその後リトライしても失敗が続いてしまいます。

汎用性の評価

SmolVLAモデルの汎用性を検証するため、白色と青色のキューブを並べて「Move the white cube into the black square area.」というテキストプロンプトでタスクを実行しました。

結果は5回実行して5回ともアームは微動だにせず、汎用性は現れていませんでした。

実験結果の動画

www.youtube.com

考察とまとめ

SmolVLAを自作データでファインチューニングした結果、SO‑101アームは赤・青キューブ移動タスクをそれぞれ76%、72%の成功率でこなせました。 以前公式チュートリアルの公開データセットをそのまま使い、環境も可能な限り再現してファインチューニングを行いましたが、タスクは一度も達成できませんでした。そこで今回学習用データの収集から推論までを同一環境・同一セッティングで統一し自前で高品質なデータを集めたところ、モデルは比較的安定してタスクをこなすようになりました。手間を惜しまずタスク固有のデータを整えることが最終的な性能に直結すると身をもって確認できました。 キューブの初期位置を少しずらしながらデータセットを作成しており、把持の再トライなど細かな挙動を学習させる上で一定の効果を持ったと推測しています。

一方で把持に失敗して再取得できない、episode timeをオーバーしてしまうといった典型的な失敗パターンがありました。 また白キューブタスクの実験によって今回のケースでは汎用性は見られませんでした。 リカバリ挙動を十分に含んだデータ、多様な言語表現・外観条件をカバーするデータを拡充すると改善するかもしれません。

今後はデータ拡充による再実験を行い、今回同期処理で動かした推論部分については、知覚・行動予測・実行をパイプライン化する非同期推論へ移行し評価する予定です。こうした改良を重ねることでSmolVLAのポテンシャルをより引き出していきたいと思います。

We Are Hiring!

ABEJAは、テクノロジーの社会実装に挑戦する仲間を募集しています。AI・ロボティクスの最前線で一緒にチャレンジしたい方は、ぜひ採用ページをご覧ください! http://careers.abejainc.com