![[VAMS] NVIDIA Isaac Lab のトレーニング機能で SO-ARM101 の Reach を強化学習させてみました](https://devio2024-media.developers.io/image/upload/f_auto,q_auto,w_3840/v1781821950/user-gen-eyecatch/eshqacmgoh8dhitnojz1.png)
[VAMS] NVIDIA Isaac Lab のトレーニング機能で SO-ARM101 の Reach を強化学習させてみました
1 はじめに
製造ビジネステクノロジー部の平内(SIN)です。
VAMS(Visual Asset Management System)は、3D/ビジュアルアセットをクラウド管理する AWS のオープンソース基盤ですが、Web UI から NVIDIA Isaac Lab を使ったトレーニングを操作できるパイプラインが用意されています。
ただし、この Isaac Lab のパイプラインには、SO-ARM101 は含まれていませんでした。そこで、MuammerBay が配布する SO-ARM101 用のパッケージを「カスタム環境(tar.gz)」として使用し、以前のブログで作業した Reach(強化学習)タスクの差分も乗せて学習を回してみました。
カスタム環境は S3 にアップロードして取り込みますが、そのままでは VAMS 側でタスクが gym.register されず、学習を動かすにはいくつか手を加える必要がありました。
本稿では、こちらの構築手順や、つまずいた点などを紹介させていただきます。
最終的に、SO-ARM101 の Reach タスクを VAMS 上で学習させ、学習済みポリシーをアセットとして保存するところまで確認できました。


2 構成
VAMS の構成は以下のとおりです。
利用した VAMS のバージョンは、v2.5.1 です。
VAMSでは、インスタンスの起動・停止は、AWS Batch が担っていますが、keepWarmInstance: falseと設定することで、常時起動は0台となり、ジョブ実行時のみの起動とすることができます。
なお、起動する GPU インスタンスの種類は VAMS のコンストラクトで定義されており、候補は優先順に g6(L4)→ g6e(L40S)→ g5(A10G)となっていました。
なお、Isaac Lab パイプラインは OpenSearch に依存しないため、Serverless の常駐費を回避するため、OpenSearch は無効化しました。
3 作業手順
作業全体の流れと各スクリプトは GitHub に公開しています。詳細な手順は README / runbook を参照してください。
(1) NGC 認証
Isaac Lab の学習コンテナは nvcr.io/nvidia/isaac-lab をベースにビルドするため、NVIDIA NGC へのログインが必要です。ログインしていないとイメージ取得で Access Denied になります。
$ docker login nvcr.io
# Username: $oauthtoken
# Password: NGC の API キー
(2) デプロイ
deploy.sh が、VAMS の clone・カスタム環境向けパッチ適用・cdk deploy までを行います。
$ bash scripts/deploy.sh
完了後の Outputs から、Web UI の URL・Cognito ユーザープール ID・アセット用 S3 バケット名を控えておきます。

(3) 管理者ログイン
管理者ユーザのメールはダミーのため、CLI から Cognito でパスワードを設定してから、cdk の Outputs で表示された URL で、ログインします。
$ aws cognito-idp admin-set-user-password \
--user-pool-id <UserPoolId> --username administrator \
--password '<大文字を含むパスワード>' --permanent --region ap-northeast-1
vams-core-prod-ap-northeast-1.WebsiteEndpointURLOutput = https://xxxxxxxxxxxxxxx.cloudfront.net


(4) Database とアセットを作成する
学習対象を入れる「Database」と「アセット」を Web UI で作成します。
左メニュー「Manage → Databases」→ 右上「Create Database」。Database ID に任意の名前(例 so-arm101-db)を入力して作成します。



左メニュー「Manage → Create Asset」から、いま作った Database を選び、Asset 名(例 soarm101)を入力して作成します。学習を起動するだけならファイルのアップロードは不要です。






(5) カスタム環境(tar.gz)を作成し、S3 へアップロードする
SO-ARM101 のロボット定義と Reach タスクを tar.gz にまとめ、アセット用の S3 バケットにアップロードします。
AssetS3Bucket は、cdk の Output AssetS3BucketNameOutput0 に出力された名前になります。
$ bash custom-env/build-custom-env.sh
$ aws s3 cp custom-env/dist/so-arm101-reach-grasp-env.tar.gz \
s3://<AssetS3Bucket>/custom-env/so-arm101-reach-grasp-env.tar.gz --region ap-northeast-1
生成: xxxx/custom-env/dist/so-arm101-reach-grasp-env.tar.gz
次: VAMS のアセットへアップロード → 学習 config の task に Isaac-SO-ARM101-Reach-Grasp-v0 を指定
upload: so-arm101-reach-grasp-env.tar.gz to s3://xxxxxxxx/custom-env/so-arm101-reach-grasp-env.tar.gz
(6) パイプラインに学習設定(Input Parameters)を入れる
「どのタスクを・どのカスタム環境で学習するか」を、Isaac Lab 学習パイプラインに設定します。
左メニュー「Orchestrate & Automate → Pipelines」を開きます。
一覧から isaaclab-training を選択し、「Edit」をクリックします。
「Input Parameters」欄に次の JSON を貼り付け、「Update Pipeline」で保存します。
{
"trainingConfig": {
"mode": "train",
"task": "Isaac-SO-ARM101-Reach-Grasp-v0",
"rlLibrary": "rsl_rl",
"numEnvs": 4096,
"maxIterations": 500,
"customEnvironmentS3Uri": "s3://<AssetS3Bucket>/custom-env/so-arm101-reach-grasp-env.tar.gz"
},
"computeConfig": { "numNodes": 1 }
}
※ cdk deploy を再実行すると、この設定は既定値(Cartpole)に戻ります。


(7) ワークフローを実行する
Isaac Lab パイプラインは GLOBAL データベースに属しており、autoRegisterWithVAMS によってデプロイ時に GLOBAL のワークフロー(isaaclab-training)が自動登録されています。これをアセットに対して実行します。
Manage → Assets and Filesから、アセット soarm101 を開きます

Workflowsタブ から Execute Workflowをクリックします。

「Select Workflow」で、isaaclab-training (GLOBAL) を選択し、Execute Workflowをクリックします。

「Execute Workflow」を押すと、AWS Batch で GPU インスタンスが起動し、SO-ARM101 の Reach タスクの学習が始まります。

インスタンスが上がっている状況は、AWS BatchのジョブやEC2インスタンスでも確認できます。


(8) 学習を確認する
学習の進行は、AWS Batch のログ(CloudWatch の /aws/batch/job)で確認できます。SO-ARM101 固有の報酬(Episode_Reward/end_effector_position_tracking、position_success_1cm など)が出力され、学習が進むにつれて上昇していきます。

学習が完了すると、学習済みポリシー(checkpoints/model_*.pt)と metrics.csv が、アセットの File Manager に登録されます。

(9) 後片付け
検証が終わったら、必ずスタックを削除します。使用していなくても、NAT Gateway などに課金があることにご注意ください。
$ bash scripts/destroy.sh
4 VAMS の Isaac Lab パイプラインとカスタム環境の仕組み
(1) パイプラインの有効化
VAMS は複数の処理パイプラインを持ち、config.json の app.pipelines.useXXX.enabled で「どれをデプロイするか」を選びます。今回は、Isaac Lab を設定しています。
"pipelines": {
"useIsaacLabTraining": {
"enabled": true,
"acceptNvidiaEula": true, // 未設定だとコンテナビルドが失敗する
"keepWarmInstance": false // GPU の常時起動を避ける
}
}
useIsaacLabTraining のenabled: true で Isaac Lab 学習パイプライン(Batch GPU 環境・学習コンテナ・Lambda・Step Functions)がデプロイされ、Web UI の Pipelines/Workflows 一覧に isaaclab-training / isaaclab-evaluation が登録されます。
(2) 学習コンテナ(__main__.py)
学習の本体は、AWS Batch の GPU コンテナ内で実行される __main__.py です。VAMS が Step Functions 経由でジョブを起動すると、このスクリプトが動きます。
GitHub: backendPipelines/simulation/isaacLabTraining/container/main.py
主な処理は次のとおりです。
- ジョブ設定 JSON を受け取り、
task/numEnvs/customEnvironmentS3Uriなどを解釈 customEnvironmentS3Uriがあれば、S3 から tar.gz を取得して pip インストール./isaaclab.sh -p scripts/reinforcement_learning/rsl_rl/train.py --task ...で学習を実行- 成果物(checkpoints / metrics)を S3(アセット)へアップロード
- Step Functions に完了を通知
(3) カスタム環境(tar.gz)
Isaac Lab 標準に含まれないロボット/タスクは、pip インストール可能な Python パッケージとして持ち込みます。今回の tar.gz の構造は次のとおりです。
so-arm101-reach-grasp-env.tar.gz
├── pyproject.toml
└── src/isaac_so_arm101/
├── robots/trs_so101/ # SO-ARM101 のロボット定義(URDF / メッシュ)
└── tasks/reach/ # Reach-Grasp タスク(gym.register / 報酬 / PPO 設定)
build-custom-env.sh で、ベース(MuammerBay)に fork(furuya02)の Reach-Grasp 差分を重ね、tar.gz 化しています。
(4) タスク登録
Isaac Lab のタスクは、定義モジュールが import された時 gym.register(...) により自動登録されるのですが、VAMS の train.py では、それがうまく動作しませんでした。
そこで、学習コンテナ側(__main__.py)で、カスタム環境をインストールした直後に、標準 train.py の import isaaclab_tasks の直後へ import isaac_so_arm101.tasks を入れました。
これにより Isaac-SO-ARM101-Reach-Grasp-v0 を学習できるようになりました。
5 スクリプト
(1) deploy.sh
VAMS の clone・パッチ適用・設定反映・デプロイを行います。
BUILDX_NO_DEFAULT_ATTESTATIONS=1を設定(後述)- Location API キーの残骸を削除(再デプロイ衝突の防止)
custom-env/patch-vams-container.shでカスタム環境向けのコンテナ修正を適用config/config-patch.jqで OpenSearch none / Isaac Lab 有効化 / VPC を反映cdk deploy --all
(2) build-custom-env.sh
ベース(MuammerBay)と fork(furuya02)を clone し、Reach-Grasp の差分を重ねて tar.gz を生成しています。pyproject に gymnasium.envs エントリポイントを追記する処理も含みます。
(3) patch-vams-container.sh
VAMS の学習コンテナ(__main__.py)に、カスタム環境を通すための修正を当てています。
pip install -e <archive>をpip install --no-deps <archive>に変更- インストール後に、標準 train.py へカスタム環境のタスク import を差し込む処理を追加
(4) destroy.sh
cdk destroy --all でスタックを削除します。Location API キーの削除を含みます。
6 つまずき
作業中につまずいた点を紹介させてください。
- コンテナビルドが
pull access denied for cdk-<hash>で失敗: 新しめの buildx と Rancher Desktop / containerd image store の組み合わせで、docker runできない形式のイメージが生成されることがありました。BUILDX_NO_DEFAULT_ATTESTATIONS=1を設定して回避しました(環境依存だと思います)。 pip install -eがアーカイブ非対応: tar.gz には使えなかったため、--no-depsでの通常インストールに変更しました。- タスク登録: 前述のとおり、標準 train.py への import 追加で対応しました。
- ステータスの確認はログで: 学習が失敗していても VAMS の表示が「成功」になる場合がありました。ログでの確認が必要だと思います。
- 削除時の残リソース: destroy 時に一部リソース(Location API キーやサブネットに残る ENI など)が残って失敗することがありました。対処は README のトラブルシュートにまとめました。
7 最後に
VAMS の Isaac Lab トレーニング機能を使って、SO-ARM101 の Reach タスクを GPU 上で学習させ、学習済みポリシーをアセットとして管理するところまで確認できました。Web UI からマネージドに学習を回せるのは、非常に快適な環境だと思いました。
なお、「VAMS で Isaac Lab を試す」だけであれば、カスタム環境は不要です。Isaac Lab 標準のタスク(Isaac-Cartpole-Direct-v0 や Isaac-Reach-Franka-v0 など)であれば、Input Parameters の task に標準タスク名を指定するだけで学習できます。
本記事で使用したコードは、以下に置きました。









