pypose/bae

[T-RO 2026] Bundle Adjustment in the Eager Mode

📦 bae – ロボティクス向け2次スパース最適化

何であるか – bae(Bundle Adjustment Engine)は、PyTorchベースのライブラリであり、ロボティクスおよびビジョンで現れる大規模スパース問題、特にバンドル調整(BA) および ポーズグラフ最適化(PGO) に対して、正確な 2次最適化ソルバー(Levenberg-Marquardt、Schur補完)を実装しています。このライブラリはPyPoseエコシステムに基づき、そのLie群型とスパースヤコビアンユーティリティを再利用し、高性能スパース線形代数用のカスタムCUDAカーネルを追加しています。


🎯 コア機能

機能 重要性
スパースブロック行列演算 複数のカメラが3次元点を共有する際に生じるブロック構造ヤコビアンを処理し、メモリ使用量を低く抑えます。
CUDA加速 カスタムカーネルにより、BA/PGO実行時間の大部分を占める線形方程式の解法(PCG、Schur補完)を高速化します。
PyTorch統合 モデルは通常の torch.nn.Module であり、自動微分はライブラリの sjac=True パラメータと併用可能です。
Levenberg-Marquardt最適化 伝統的な非線形最小二乗ソルバーであり、今や完全なGPUサポートを備えています。
Schur補完ソルバー 線形システムをカメラ変数のみに簡略化し、非常に大きなシーンにおいてメモリ使用量を劇的に削減します。
torch.compileサポート シムにより、BA残差とスパースヤコビアンの走査をTorchDynamo/Inductorでコンパイル可能にし、ミリ秒未満のカーネル起動を実現します。
エージェントスキルファイル .agent/skills/bae-compute-graph は、LLM駆動エージェントが bae の上にカスタム計算グラフを構築するためのレシピを提供します。

🚀 一般的な利用事例

  • 構造から運動(SfM)パイプライン – フィードフォワード予測器(例:Depth Anything 3、VGGT)の後にカメラポーズと3次元点を最適化。
  • SLAMバックエンド – 大きなループと高ノイズを伴うポーズグラフ問題を解決。
  • ロボティクスの認識 – 高密度RGB-D点群の整合(RGB-Dポーズ精緻化)をリアルタイムマッピングに統合。
  • 研究プロトタイピング – 新しい残差や多様体パラメータ化を実験しながら、正確な2次更新を維持。

📦 インストール(クイックスタート)

# GitHubから直接ライブラリをインストール
python -m pip install git+https://github.com/pypose/bae.git

前提条件

  • CUDA 12.x(または13.x)ツールキット
  • 同じCUDAバージョンでコンパイルされたPyTorch 2.0+
  • オプション:スパースソルバー加速用のNVIDIA CUDSS(pip install "nvidia-cudss-cu12<0.9")
  • PyPose(スパースバックエンド)– pip install git+https://github.com/pypose/pypose.git

ソースを編集したい開発者向けには、READMEに完全な開発環境セットアップ手順(クローン、pip install -r requirements.txt、編集可能モードでインストールなど)が記載されています。


🛠️ 最小限のバンドル調整例

import torch, pypose as pp
from pypose.autograd.function import psjac
from bae.optim import LM
from bae.utils.pysolvers import PCG
from datapipes.bal_loader import get_problem

class Reproj(torch.nn.Module):
    def __init__(self, cam, pts):
        super().__init__()
        self.pose   = pp.Parameter(cam, sjac=True)   # カメラブロック
        self.points = pp.Parameter(pts, sjac=True)   # 点ブロック
        self.pose.trim_SE3_grad = True

    @psjac                                 # 構造化ヤコビアンを有効化
    def project(points, cam):
        proj = pp.SE3(cam[..., :7]).Act(points)
        proj = -proj[..., :2] / proj[..., 2:3]
        f, k1, k2 = cam[..., -3], cam[..., -2], cam[..., -1]
        n = (proj**2).sum(-1, keepdim=True)
        r = 1 + k1 * n + k2 * n**2
        return proj * r * f

    def forward(self, obs, cidx, pidx):
        pred = Reproj.project(self.points[pidx], self.pose[cidx])
        return pred - obs

# BAL問題をロード(例:problem-49-7776-pre)
prob = get_problem("problem-49-7776-pre", "ladybug", use_quat=True)
prob = {k: v.cuda() for k, v in prob.items() if isinstance(v, torch.Tensor)}

model = Reproj(prob['camera_params'].clone(), prob['points_3d'].clone()).cuda()

strategy = pp.optim.strategy.TrustRegion(up=2.0, down=0.5**4)
solver   = PCG(tol=1e-4, maxiter=250)
optim    = LM(model, strategy=strategy, solver=solver, reject=30)

for it in range(20):
    loss = optim.step({
        "observes": prob['points_2d'],
        "cidx": prob['camera_index_of_observations'],
        "pidx": prob['point_index_of_observations'],
    })
    print(f"Iter {it:02d} – loss {loss.item():.6f}")

このループはGPU上で完全なLevenberg-Marquardtステップを実行し、カメラポーズ(SE(3) Lie群パラメータとして)と3次元点座標の両方を更新します。


🤖 エージェントスキルサポート

このリポジトリには、カスタム残差グラフ(例:IMU要因やループクロージャー制約の追加)を構築する方法を記述したスキル(.agent/skills/bae-compute-graph)が同梱されています。LLM駆動のコーディングアシスタントはこのスキルをインポートすることで、新しい最適化問題用のボイラープレートコードを自動生成できます。


📚 詳細なリソースと引用


🏁 まとめ

bae は、現代のビジュアルSLAM、SfM、ロボティクス認識パイプラインの中心にあるスパースでブロック構造を持つ問題に対して、GPUネイティブで正確な2次最適化を提供します。PyTorchの自動微分とカスタムCUDAカーネルを活用することで、迅速なプロトタイピングとプロダクションレベルのパフォーマンスのギャップを埋めています。

関連

  • プロジェクト
  • プロジェクト
  • プロジェクト
  • プロジェクト
  • プロジェクト