Web NN の動向を追う (2021年5月時点)
WebNN support async APIs?
グラフ構築(MLGraphBuilder.build)と実行 (MLGraph.compute)はどちらも sync APIとしてデザインされている。 sync APIだとメインスレッドをブロッキングするので、async API もデザインする必要がある?という議論。
MLGraphBuilder.build
ビルドに含まれる操作
→ 計算グラフのコンパイルと重みのアップロードとGPUでの初期化
グラフ構築は実行と比較して計算コストがかからないので同期APIでも良さそうだが、同期 → 非同期のインターフェイスに変更のは大変 & グラフ構築にコストがかかる場合もある (特に GPU での初期化) ので、非同期APIだけに変更する提案がされていた。しかし、WASM バックエンドの都合によって同期APIも必要になりそうとの議論がされていた。
WASM バックエンドの都合
WASM バックエンドでは、C++ で実装されたMLフレームワークをWASMにコンパイルして実行する。既存の多くの C++ のメソッドは同期APIで実装されているため、compute
自体も同期APIになっていることが要求されることが多い。
C++ の同期API を JS の非同期APIに変換ツールとしてAysncify
があるが、これを使うとパフォーマンスが悪化するらしい。
MLGraph.compute
以下のコメントの表がまとまっている
どこで計算が行われるかで、同期・非同期どちらのAPIを利用すべきかが変わってくる
通常のケース
CPU/GPU デバイスは自動で決定される。CPUで計算が実行される可能性があるので、同期APIは worker スレッドのみに制限すべきとの議論がされている。もちろん非同期APIは、メイン・Worker どちらのスレッドでも呼び出せるようにしている。
WebGPU interop
メインスレッドはGPU スレッドに計算を実行させるようにキューを積むだけなので、同期 API にしても問題ないはず?という議論が起きていた (自分も同じ認識) 。MLGraph.compute
を実行した後の計算結果は、GPUからCPUへのデータの取り出しになり GPUBuffer.mapAsync
で非同期でできる。
同期・非同期 API の議論についてはほとんど落ち着いたみたい (参考) なので、W3C のドキュメントを読むのが良さそう
まずは各インターフェイス / API の紹介
-
MLOperand
- 計算グラフ内のデータ表現 (数値演算を表現したデータ)
-
MLGraph
- コンパイルされた計算グラフ
-
MLGraphBuilder
-
build, buildAsync
: MLOperandを受け取って MLGraph を作成するための builder 関数-
build
: Worker スレッド上で直ちにグラフをコンパイルして,MLGraphを返す- メインスレッド上では呼べないことに注意
-
buildAsync
: MLOperandを受け取って MLGraph を作成するための builder (factory) 関数- 呼び出したスレッドをブロックせずに非同期でグラフをコンパイル
-
-
softmax, batchNormalization, ...
: それぞれの演算に対応したMLOperandを作成する関数- input として MLOperand を受け取り、APIの演算を適応した新しい MLOperand を返す
-
-
MLContext
-
compute, computeAync
: MLGraphと入力・出力値を受け取って計算を行う-
compute
: Worker スレッド上でグラフの実行を直ちに行う- メインスレッドでは呼べない
-
computeAync
: 非同期でグラフの実行を行う- CPU: worker スレッドを利用
- GPU: GPUタイムラインを利用
-
-
-
MLCommandEncoder
- WebGPUを利用するユーザに対して、柔軟にグラフ実行をできるようにしたインターフェイス
-
MLContext.computeAsync
より細かい単位でグラフの実行に関連するAPIが利用できる - グラフ初期化、GPUタイムラインへの演算実行の dispatch、など
-
- WebGPUを利用するユーザに対して、柔軟にグラフ実行をできるようにしたインターフェイス
MLCommandEncoder については、以下の interop の議論を参考にするのが良さそう
interop refers to two or more browsers behaving the same.
Device Selection
MLContext は、グラフ実行に必要なさまざまな状態を保持している。
- context type
- "default": User Agent (ブラウザ)が自動的に最適な MLContext を作成する
- MLPowerPreference と MLDeviceType から 各ハードフェアAPI で実行デバイスを最適化する
- "webgl": WebGLRenderingContext から MLContext を作成する
- "webgpu": GPUDevice から MLContext を作成する
- "default": User Agent (ブラウザ)が自動的に最適な MLContext を作成する
- device type
- 使用するデバイス ("cpu" or "gpu") を指定する
- power preference
- 消費電力に応じた最適化方針を指定する。
- "default": User Agent (ブラウザ)が自動的に最適化方針を決定する
- "high-performance": 消費電力より計算速度を優先する
- "low-power": 計算速度より消費電力を優先する
メモ (自信がない部分)
WebGPU/WebGL は、ブラウザで標準化されたAPIなので個別で context type を指定する。恐らく、WebGPU 内で適切な GPU デバイスが選択される。context type = "default" の場合は、各OSでのNN APIを利用した最適なデバイス選択がされる。WASMはCPUのみで実行される (恐らく) ので、デバイスは常に CPU で選択される。
WebGPU 自体は、DirectX (Win) / Metal (MacOS) / Vulkan (Linux) といった Low Level Graphics API を利用している。一方で、Windows の Direct MLや iOS の ML Compute API のCore NN も、それぞれ内部ではDirectX や Metal を利用する。なので context type の "default" と "webgpu" の違いは、WebNN API → OS specific ML API か WebNN API → WebGPU → OS specific ML API の違いだと理解している。 要は、WebGPU を経由するかどうかが違う。WebGPUを学んでから戻ってくる
Security Considration
Chrome に初めての patch が入ったみたい
onnx のバックエンドとして使われ始めているらしい
Windows なら Chrome ではフラグつきで利用できるらしい