並行処理

リアルタイムSLAMシステムは並列性を積極的に利用する。約33ms(30Hz)というフレーム予算の中で、特徴抽出、マッチング、最適化、マップ管理をすべてカバーしなければならない。SLAMにおける並行処理は、命令レベルのSIMDからマルチスレッドアーキテクチャ、GPUオフロードまで、複数の階層にわたって存在する。

SIMD: SSE/AVX/Neon

SIMD(Single Instruction, Multiple Data)命令は、1命令あたり4〜16個の値を処理する。x86ではSSE/AVX、ARM(つまりほとんどのロボット、スマートフォン、組み込みボード)ではNeonが使われる。特徴点レベルの画像処理は、この典型的な恩恵を受ける対象である——ORB記述子の計算とマッチングは、ARM上のNeonイントリンシックから大きな利益を得る。定番の例は、ORBマッチングの内側ループであるバイナリ記述子間のハミング距離である。

// Hamming distance of two 256-bit ORB descriptors: XOR + popcount
int hamming(const uint64_t* a, const uint64_t* b) {
    int d = 0;
    for (int i = 0; i < 4; ++i)
        d += __builtin_popcountll(a[i] ^ b[i]);  // 64 bits per instruction
    return d;
}

EigenやOpenCVのようなライブラリは内部でSIMDを使用しているが、SLAMフロントエンドのホットループはしばしば手動でベクトル化される。

OpenMP

OpenMPは、コンパイラプラグマによる粗粒度のCPU並列性を提供する。

#pragma omp parallel for
for (int i = 0; i < num_cells; ++i) {
    extractFeatures(image_grid[i]);   // per-patch feature extraction
}

これは、画像パッチ全体にわたる特徴抽出の並列化、点ごとの残差評価、ステレオマッチングの行など、データ並列な作業に適している——1行の記述で、明示的なスレッド管理も不要である。効果が出るのは、各イテレーションが独立していて、スレッドのフォーク/ジョインのコストを償却できるだけの十分な作業量がある場合に限られる。

CUDA

CUDAは、大規模並列ワークロード向けにNVIDIA GPUをターゲットとする。密な深度推定、ニューラルネットワークの推論、密なボリュメトリックマッピング(KinectFusionのTSDF統合はGPU向けに設計された)がその対象である。トレードオフは、ホスト-デバイス間のメモリ転送コストと、追加されるデプロイの複雑さである——CPUで2msかかるステージも、往復コピーに3msかかるなら、GPUで0.5msにする価値がないかもしれない。ステージをGPUに移す前にプロファイルを取り、移す場合はパイプラインの各ステージ間でデータをデバイス上に保持し続けること。

マルチスレッドSLAMアーキテクチャ

データ並列性を超えて、SLAMシステムは並行パイプラインとして構成される。時間的に重要なトラッキング(フレームごと)と、バックグラウンドのマッピング(キーフレームごと)には別々のスレッドが割り当てられる。ORB-SLAM3は、Tracking、Local Mapping、Loop Closingの3つのスレッドを使用し、ミューテックス下でマップを共有する。この分離はPTAMから継承されたもので、リアルタイムSLAMにおいて間違いなく最も影響力のあるアーキテクチャ上のアイデアの一つである。

重要なスキルは、C++のプリミティブとその規律ある使用法である。

std::mutex map_mutex;

// Tracking thread: brief, fine-grained locking
{
    std::lock_guard<std::mutex> lock(map_mutex);
    local_points = map.getLocalPoints(current_pose);  // copy out, then unlock
}
trackAgainst(local_points);  // heavy work happens outside the lock

よくある落とし穴

SLAMにおける意義

論文のプロトタイプと実運用可能なSLAMシステムの違いは、通常アルゴリズムの新規性ではなくエンジニアリングのスループットである。同じ数学でも、SIMDによる記述子計算、OpenMPフロントエンド、適切に分離されたスレッドアーキテクチャによって10倍速くなる。電力予算が厳しい組み込みプラットフォームでは、NeonとGPUを活用することがリアルタイム性を達成する唯一の手段になることも多い。

ハンズオン

関連ノート