少しずつ涼しさが感じられる季節になってきました。
こんにちは、GROOVE X でソフトウェアエンジニアをしているfmyです。
私は主に画像関係のアプリケーションを担当しており、去年の初冬にRustを導入していくという話をしておよそ一年が経ちました。
この記事では、導入がどのように進んだのかというお話をしたいと思います。
LOVOT 3.0の計算性能
LOVOT上で動くアプリケーションの殆どはGo, Pythonで実装を行っています。 Inside of LOVOTでの紹介記事としてはLOVOTの並行思考 with trioやLOVOT と gRPCなどがあります。 LOVOT 3.0では新たにRustを使ったアプリケーションが増えました。
なぜRustを選んだのか、という話に入る前にLOVOT 3.0の計算性能を見てみます。 LOVOT 3.0ではSoCにJetson Orin NXを採用しており、計算力に関わる項目を抜粋すると以下のような性能になっています。
Jetson Orin NX | Jetson AGX Orin | |
---|---|---|
CPU | Arm® Cortex®-A78AE v8.2 64-bit | < |
CPU Cores | 6 or 8 | 8 or 12 |
CPU Freq(GHz) | 1.4-2.0 | 1.4-2.2 |
GPU | NVIDIA Ampere architecture | < |
GPU CUDA Cores | 1024 | 1792 or 2048 |
GPU Tensor Cores | 32 | 56 or 64 |
GPU Freq Max(MHz) | 765 or 918 | 930 or 1300 |
DLA Cores | 1 or 2 | 2 |
DLA Freq(MHz) | 610 or 614 | 1400 or 1600 |
Mem(GB) | 8 or 16 | 32 or 64 |
Mem bandwidth(GB/s) | 102 | 204.8 |
AI Performance(TOPS) | 70 or 100 | 248 or 275 |
以下をもとに改変
Jetson AGX Orin Series Hardware Architecture, TB_10749-001_v1.2 | p4
NVIDIA Jetson Orin NX Series Data sheet, Jetson_Orin_NX_DS-10712-001_v0.5.pdf | p1 DeveloperGuide: Platform Power and Performance
Jetson OrinはArm Cortex A78のCPUコアにAmpere世代のGPUを搭載しています。 汎用的な計算性能を場合、一般的なLaptop向けCPUと比較すると周波数は30%以上低く、潤沢に有るとは言えません。 実際にはSoC全体の電力消費の制約などから、CPU周波数を更に下げることもあります。
一方でAI Performanceと表記される推論計算の性能は、過去の世代から大きく伸びています。これにはGPUだけでなくDLAという専用のブロックが存在することが大きいです。 上のテーブルに書いてない項目として以下のようなHA(ハードウェアアクセラレータ)を搭載しているほか、UnifiedなメモリであるためCPU-GPU間やHA間のやり取りのコストが低いのが特徴です。
- MIPI-CSIとISPのブロック
- H.264, H.265, AV1,JPEGなどのエンコーダー、デコーダー
- 画像処理に特化したPVA(Programmable Vision Accelerator)
一般的な汎用計算の効率化はもちろん大事ですが、Jetsonの性能を引き出すにはこれらHAを利用するのが効果的です。
JetsonのHAを使うには
JetsonのHAに実装された機能にアクセスするには。グラフィックならOpenGLやVulkanといったグラフィックスライブラリ、 推論や画像処理はNVIDIAの提供するCUDAやmultimedia-api、VPIといったライブラリを使います。 いずれもCで書かれており、実装するならCとの親和性が高い言語を使いたいです。
これまで採用してきたGoやPythonは、Cと連携を行うには不利です。C/C++ならば性能面でも親和性でも問題はありませんが、きれいなアプリケーションを書くには高いスキルが必要となります。 Cとの親和性があり、パフォーマンスも十分に高く、なおかつ安全に書けるということでRustが選択肢として上がりました。
Rustを活かした開発
目のデザインの話はLOVOTのひみつBLOGに記事があるのでこちらをご覧ください。 LOVOTの「目のデザイン」はセンスのかたまりだった!【前編】
LOVOT 3.0の目はRustで再実装を行いました。 以前のC++での実装は、ビジネスロジック以外にデータのパースや通信周りで書かなければならないコードが大きく、メンテナンスが難しくなっていました。 表現のコアはシェーダーであるためC++への強い依存は少なく、比較的移植はしやすいアプリケーションなので移植を決定しました。
実際、Rustでの再実装によってメンテナンス性は大きく改善され、ビジネスロジックに集中して記述ができるようになりました。 特に以下のところではRustの言語仕様、ライブラリを活かせたと思います。
- HTTP通信周りは
axum
をベースにし、非同期で実装をすることで全体的に見通しが良くなった - 内部プロトコルの文字列を手続き的にパースしていたが、traitとマクロを用いて適切な型として扱えるようになった
- OpenGLのリソース管理は、Rust側に対応する型を定義してRAIIパターンで実装できた
Rust開発を支える環境
開発の多くは一般的なx86のPCで行っており、開発PC上ではJetson固有の機能には触ることができません。 そのためJetson開発者キットをベースに、必要に応じてカメラ等をつなぐことでLOVOTの実行環境に近い開発環境を用意しています。 基本的な機能の検証にはこれがとても役に立ちました。
またJetsonをCIランナーとしても利用しており、アプリケーションのテスト、コンパイル、パッケージ作成、TensorRT推論エンジンへの変換などをCIで行っています。 コンテナからmultimedia-apiなどJetsonの固有の機能にアクセスするため、deepstream_dockerをベースにして構築しています。 互換性の心配なく適切なバイナリ、パッケージが作れるため、安定した開発ができています。
最後に
LOVOTにおけるRustの活用について簡単に紹介させていただきました。 eyeのもっと細かいTipsや、カメラパイプラインでGStreamerを使っているなどより技術的な話もいずれ記事にしたいと思います。
弊社ではRustの書けるエンジニアも募集しています。 Jetson Orinにはまだ余力もあり、LOVOTも進化の余地がまだまだあります。 日常生活の中に溶け込むロボットに興味が有る方、ハードウェアの性能を活かしたりやJetson Orinの計算能力を引き出すことに興味の有る方はぜひご応募ください。