メインコンテンツへスキップ
見出し画像

Genesis 入門 (4) - 並列シミュレーション

    「Genesis」の並列シミュレーションについてまとめました。

    ・Parallel Simulation

    前回

    1. 並列シミュレーション

    GPUを使用してシミュレーションを高速化する最大の利点は、シーンレベルの並列処理が可能になり、数千の環境で同時にロボットを学習できることです。

    「Genesis」では、並列シミュレーションの作成は簡単です。シーンを構築するときに、追加のパラメーター n_envs を追加して、必要な環境の数をシミュレータに伝えるだけです。

    並列化操作を示すために バッチ処理 (batching) という用語を使用します。

    import genesis as gs
    import torch
    
    # 初期化
    gs.init(backend=gs.gpu)
    
    # シーンの作成
    scene = gs.Scene(
        show_viewer = True,
        viewer_options = gs.options.ViewerOptions(
            camera_pos = (3.5, -1.0, 2.5),
            camera_lookat = (0.0, 0.0, 0.5),
            camera_fov = 40,
        ),
        rigid_options = gs.options.RigidOptions(
            dt = 0.01,
        ),
    )
    
    # シーンにエンティティを追加
    plane = scene.add_entity(
        gs.morphs.Plane(),
    )
    franka = scene.add_entity(
        gs.morphs.MJCF(file='xml/franka_emika_panda/panda.xml'),
    )
    
    # シーンのビルド
    B = 20
    scene.build(
        n_envs=B, 
        env_spacing=(1.0, 1.0)
    )
    
    # エンティティの自由度の目標位置を設定
    franka.control_dofs_position(
        torch.tile(
            torch.tensor([0, 0, 0, -1.0, 0, 0, 0, 0.02, 0.02], device=gs.device), (B, 1)
        ),
    )
    
    # ステップ実行
    for i in range(1000):
        scene.step()

    上記のスクリプトは、scene.build() に2つの追加パラメータが追加されていることを除いて、Hello, Genesis とほぼ同じです。

    ・n_envs
    作成するバッチ環境の数を指定します。

    ・env_spacing
    生成された並列環境は同一の状態を共有します。視覚化の目的で、このパラメータを指定して、ビジュアライザーに、各環境間の距離 (x, y) メートルでグリッドにすべての環境を分散するように指示できます。これは視覚化の動作にのみ影響し、各環境内のエンティティの実際の位置は変更されないことに注意してください。

    画像

    2. バッチ環境でロボットを操作

    前のチュートリアルでは franka.control_dofs_position() などのAPIを使用しました。これで、入力変数に追加のバッチ次元が必要であることを除いて、まったく同じAPIを使用してバッチ環境でロボットを操作できます。

    franka.control_dofs_position(torch.zeros(B, 9, device=gs.device))

    シミュレーションはGPU上で実行されているため、CPUとGPU間のデータ転送オーバーヘッドを削減するために、NumPy配列の代わりに gs.device を使用して選択されたtorchテンソルを使用できます (ただし、NumPy 配列も機能します)。これにより、バッチサイズが大きいテンソルを頻繁に送信する必要がある場合に、性能が大幅に向上する可能性があります。

    上記の呼び出しは、バッチ環境内のすべてのロボットを制御します。環境のサブセットのみを制御する場合は、envs_idx を追加で渡すことができますが、位置テンソルのバッチ次元のサイズが envs_idx の長さと一致することを確認してください。

    # 1、5、7 の 3 つの環境のみを操作
    franka.control_dofs_position(
        position = torch.zeros(3, 9, device=gs.device),
        envs_idx = torch.tensor([1, 5, 7], device=gs.device),
    )

    この呼び出しは、選択された3つの環境にのみゼロ位置コマンドを送信します。

    Genesisの動作確認 (4)https://t.co/BU9mVsCaLB pic.twitter.com/eiT3mKhwIc

    — 布留川英一 / Hidekazu Furukawa (@npaka123) December 21, 2024

    3. 未来的な速度の確認

    「Genesis」は最大数万の並列環境をサポートし、これにより前例のないシミュレーション速度を実現します。次に、ビューアをオフにして、バッチサイズを 30000 に変更します (GPU の VRAM が比較的小さい場合は、より小さいサイズを検討してください)。

    import torch
    import genesis as gs
    
    # 初期化
    gs.init(backend=gs.gpu)
    
    # シーンの作成
    scene = gs.Scene(
        show_viewer = False,
        rigid_options = gs.options.RigidOptions(
            dt = 0.01,
        ),
    )
    
    # シーンにエンティティ追加
    plane = scene.add_entity(
        gs.morphs.Plane(),
    )
    franka = scene.add_entity(
        gs.morphs.MJCF(file='xml/franka_emika_panda/panda.xml'),
    )
    
    # シーンのビルド
    scene.build(n_envs=30000)
    
    # エンティティの自由度の目標位置を設定
    franka.control_dofs_position(
        torch.tile(
            torch.tensor([0, 0, 0, -1.0, 0, 0, 0, 0.02, 0.02], device=gs.device), (30000, 1)
        ),
    )
    
    # ステップ実行
    for i in range(1000):
        scene.step()

    上記のスクリプトを RTX 4090 と 14900K を搭載したデスクトップで実行すると、未来的なシミュレーション速度が得られます。毎秒 4300 万フレーム以上、これはリアルタイムよりも 430,000 倍高速です。

    画像

    ・FPS ロギング
    デフォルトでは、genesis logger はターミナルにリアルタイムのシミュレーション速度を表示します。シーンの作成時に show_FPS=False を設定すると、この動作を無効にすることができます。

    【おまけ】 Macのコード

    import genesis as gs
    import torch
    
    def main():
        # 初期化
        gs.init(backend=gs.cpu)
    
        # シーンの作成
        scene = gs.Scene(
            show_viewer = True,
            viewer_options = gs.options.ViewerOptions(
                camera_pos = (3.5, -1.0, 2.5),
                camera_lookat = (0.0, 0.0, 0.5),
                camera_fov = 40,
            ),
            rigid_options = gs.options.RigidOptions(
                dt = 0.01,
            ),
        )
    
        # シーンにエンティティを追加
        plane = scene.add_entity(
            gs.morphs.Plane(),
        )
        franka = scene.add_entity(
            gs.morphs.MJCF(file='xml/franka_emika_panda/panda.xml'),
        )
    
        # シーンのビルド
        B=20
        scene.build(n_envs=B, env_spacing=(1.0, 1.0))
    
        # スレッドの開始
        gs.tools.run_in_another_thread(fn=run_sim, args=(scene, franka, B))
    
        # シミュレータの開始
        scene.viewer.start()
    
    
    def run_sim(scene, franka, B):
        # エンティティの自由度の目標位置を設定
        franka.control_dofs_position(
            torch.tile(
                torch.tensor([0, 0, 0, -1.0, 0, 0, 0, 0.02, 0.02], device=gs.device), (B, 1)
            ),
        )
    
        # ステップ実行
        for i in range(1000):
            scene.step()
    
    
    if __name__ == "__main__":
        main()

    次回



     
     

    npaka

     
     
    プログラマー。iPhone / Android / Unity / ROS / AI / AR / VR / RasPi / ロボット / ガジェット。年2冊ペースで技術書を執筆。アニソン / カラオケ / ギター / 猫 twitter : @npaka123

    あなたへのおすすめ