HN 日本語サマリー

← 一覧へ戻る
科学・技術

2ドルのマイクロコントローラーでSIMDアクセラレーションされたコンピュータビジョン

SIMD-accelerated computer vision on a $2 microcontroller (shraiwi.com)

110 pointsby zdw29 コメント

要約

ESP32-S3マイクロコントローラーの128ビットSIMD命令を活用した、高速なFAST特徴検出器が開発されました。この実装は、標準的な実装と比較して約2倍のパフォーマンスを達成し、QVGA(320x240)フレームの処理に約6ミリ秒かかります。開発者は、ESP32-S3のアセンブリ言語の基本を学び、その制約を回避するために独自のレジスタアロケータも作成しました。

全文翻訳

2ドルのマイクロコントローラーでSIMDアクセラレーションされたコンピュータビジョン

ESP32-S3の128ビットSIMD命令を活用した、高速なFAST特徴検出器を開発しました。標準実装と比較して約2倍のパフォーマンスを達成し、QVGA(320x240)フレームの処理に約6ミリ秒かかります。ソースコードはこちらで見つけられます。

ESP32-S3は、その価格にしては驚異的なマイクロコントローラーです。控えめなプラスチックパッケージの中には、最大240MHzで動作するデュアルコアCPUと、WiFiおよびBluetooth Low Energy無線を含む多数のペリフェラルが搭載されています。そのテクニカルリファレンスマニュアルを調べていたところ、このチップが限定的なSIMD命令セットをサポートしていることを発見しました。平均的なコーヒーよりも安いシリコンでこれはかなりクールです。これを使ってどんなエキサイティングなことができるか見てみましょう!

SIMDアクセラレーションされたFASTコーナー検出器を開発する過程で、ESP32-S3のアセンブリの基本を学び、その特異な制約を回避し、独自の基本的なレジスタアロケータbasmを書き上げました。


さらにウェブを検索したところ、これらの命令は実際には秘密ではなく、比較的知られていないことがわかりました。私は自分でそれらを実験し、オンラインで見つけられるものよりも高度なコードを書きたいと思いました。最近コンピュータビジョンに非常に興味があったので、ESP32-S3用のFAST特徴検出器のSIMDアクセラレーション実装を開発することにしました。

SIMD命令を使用したサンプルコードを探すことから始めました。執筆時点では、3つのソースしか見つけられませんでした。

  1. Larry Bank氏のブログ:彼はこの機能を探求し、最小限の例を提供しています。
  2. Espressifのesp-dspライブラリ:DSP風機能(畳み込み、FFTなど)に使用されます。
  3. Espressifのesp-dlライブラリ:オンチップAIアクセラレーションに使用されます。

それらを精査した後、ESP32-S3のアセンブリはそれほど悪くないことに安堵しました。私はこの一般的な構造を採用しました。

    .section .rodata
	# read-only data here

    .section .text
    .align 4

    .global add
    .type   add,@function
# a simple function that adds two numbers
# int32_t add(int32_t a, int32_t b)
add:
    entry       sp, 48 # sp (stack pointer) is an alias for a1
    
	#define r_a a2
	#define r_b a3

	# code here
	
	add a2, r_a, r_b # a2 = a + b

	retw.n # return, with a2 containing the return value.

そこから、FASTコーナー事前テストのSIMDアクセラレーションバージョンの記述を開始しました。基本的に、各基数方向で1ピクセルをサンプリングし、少なくとも3つの「極端」なピクセルがあるかどうかをチェックします。この場合、極端なピクセルとは、中心ピクセルからの絶対差があるしきい値を超えているピクセルです。

16ピクセルを一度に計算する関数を考案しました。これは、各ベクトルレジスタが16個の8ビット値を格納できるためです。これは、各基数方向で4つのピクセル「チャンク」をサンプリングし、それらをそれぞれの中央ピクセルと比較することによって達成されます。

しかし、ここで最初の制限に遭遇しました。ISAは直接の非アラインメント読み取りを許可していません。中心ピクセルがアラインされていると仮定すると、東と西のブロックは非アラインになります。

centereastwestnorthsouth

幸いなことに、チップには2つの連結されたレジスタのスライスを別のレジスタに抽出できる命令があります。この機能を使用して、中心ブロックに隣接する2つのブロックのスライスを読み取り、抽出することで、東と西のブロックを抽出できました。

さて、ピクセルデータは手に入りました。比較に進む時間ですか?違います。ESP32-S3は符号付き8ビット数値の比較しか実装していないことが判明しました。これにより、処理が少し困難になりました。なぜなら、私のピクセルデータはすべて符号なし8ビット数値として格納されていたからです。符号なしデータを符号付きデータとして再解釈しただけでは、奇妙な結果が得られます。

>>> np.int8(np.uint8(range(0, 256, 8)))
array([   0,    8,   16,   24,   32,   40,   48,   56,   64,   72,   80,
        88,   96,  104,  112,  120, -128, -120, -112, -104,  -96,  -88,
       -80,  -72,  -64,  -56,  -48,  -40,  -32,  -24,  -16,   -8],
      dtype=int8)

範囲 [128 255] は [-128 -1] に非線形にマッピングされ、すべての比較操作が壊れます。これを機能させるには、値の範囲を [0, 255] から [-128 127] にシフトする必要がありました。これは単純な減算で済むはずでしたが、命令セットが再び妨げとなりました。ESP32-S3では、すべてのSIMD算術演算は飽和演算であり、127を超えるすべてのピクセル値は、適切な値にアンダーフローするのではなく、-128にクランプされることになります。この問題を克服するために、減算命令を使用せずに、各数値から並列に128を引く方法を見つける必要がありました。最初は daunting なタスクに思えましたが、最終的に解決策にたどり着きました。

x を被減数と仮定します。各桁の位取りは次のようになります。

-128 64 32 16 8 4 2 1

何か興味深いことに気づきましたか?減算は-128による加算と同じなので、x - 128 を計算するには、x の最上位桁(位取りが-128)を1つ「インクリメント」するだけで、「-128を加算」できます。これは、x の最上位ビットを反転させるだけで計算できます。任意のビットを1とXORすることは、ビットごとのNOTを取ることと同じなので、ビットマスク 0b10000000(0x80に等しい)とXORすることで x の最上位ビットを選択的に反転できます。したがって、x - 128 == x ^ 0x80 です。

これで、符号なし8ビット値がロードされるたびに、0x80 とXORされて、算術演算と比較が意味をなす適切な(線形)範囲に変換されます。

これらの2つのトリックを使用して、ESP32-S3の制約を回避し、SIMDアクセラレーションされたFASTコーナー事前テストを記述することができました。同様の操作セットを使用してSIMDアクセラレーションされたスコアリング関数も記述しましたが、ここではそれについては説明しません。

最終的に、FAST特徴検出器のスループットを約220%向上させ、テストでは5.1MP/sから11.2MP/sに向上させることができました。これは、リアルタイムコンピュータビジョンタスクの許容範囲内にあり、ESP32-S3が30fpsのVGAストリームを簡単に処理できるようになります。2ドルにしては悪くないです!