コンテンツにスキップ

WebNNの使用

このドキュメントでは、ONNX RuntimeでWebNN実行プロバイダーを使用する方法について説明します。

  • TOC

Web Neural Network (WebNN) APIは、WebアプリとフレームワークがGPU、CPU、または専用AIアクセラレータ(NPU)などのオンデバイスハードウェアでディープニューラルネットワークを加速できるようにする新しいWeb標準です。

WebNNは、Windows、Linux、macOS、Android、ChromeOSの最新バージョンのChromeとEdgeで「Enables WebNN API」フラグの後ろで利用できます。最新の実装状況についてはWebNN statusを確認してください。

WebNN実行プロバイダーでの演算子サポートの最新状況については、WebNN operatorsを参照してください。WebNN実行プロバイダーがモデル内のほとんどの演算子をサポートしており(サポートされていない演算子はWASM EPにフォールバック)、オンデバイスアクセラレータを活用して電力効率的で高速な処理とスムーズなパフォーマンスを実現したい場合は、WebNN実行プロバイダーの使用を検討してください。

ONNX Runtime WebでWebNN EPを使用する方法

Section titled “ONNX Runtime WebでWebNN EPを使用する方法”

このセクションでは、ONNX Runtime WebでWebアプリケーションをすでに設定していることを前提としています。まだの場合は、基本情報についてGet Startedに従ってください。

WebNN EPを使用するには、3つの小さな変更を行うだけです:

  1. インポート文を更新する:

    • HTMLスクリプトタグの場合、ort.min.jsort.all.min.jsに変更:

      <script src="https://example.com/path/ort.all.min.js"></script>
    • JavaScriptインポート文の場合、onnxruntime-webonnxruntime-web/allに変更:

      import * as ort from 'onnxruntime-web/all';

    詳細についてはConditional Importingを参照してください。

  2. セッションオプションで’webnn’ EPを明示的に指定:

    const session = await ort.InferenceSession.create(modelPath, { ..., executionProviders: ['webnn'] });

    WebNN EPは、多様なタイプのWebNN MLContextを作成するためのオプションセットも提供します。

    • deviceType: 'cpu'|'gpu'|'npu'(デフォルト値は'cpu')、MLContextに使用する優先デバイスタイプを指定します。
    • powerPreference: 'default'|'low-power'|'high-performance'(デフォルト値は'default')、MLContextに使用する優先電力消費タイプを指定します。
    • context: MLContextのタイプ、ユーザーが事前作成されたMLContextをWebNN EPに渡すことができ、IOバインディング機能で必要です。このオプションが提供された場合、他のオプションは無視されます。

    WebNN EPオプションの使用例:

    const options = {
    executionProviders: [
    {
    name: 'webnn',
    deviceType: 'gpu',
    powerPreference: "default",
    },
    ],
    }
  3. 動的形状モデルの場合、ONNX Runtime WebはfreeDimensionOverridesセッションオプションを提供してモデルの自由次元をオーバーライドします。詳細についてはfreeDimensionOverrides introductionを参照してください。

WebNN APIとWebNN EPは積極的に開発中です。最新の機能と改善の恩恵を受けるために、ONNX Runtime Webの最新ナイトリービルドバージョン(onnxruntime-web@dev)のインストールを検討してください。

WebNN MLTensor上でテンソルデータを保持する(IOバインディング)

Section titled “WebNN MLTensor上でテンソルデータを保持する(IOバインディング)”

デフォルトでは、モデルの入力と出力はCPUメモリにデータを保持するテンソルです。‘gpu’または’npu’デバイスタイプでWebNN EPを使用してセッションを実行すると、データはGPUまたはNPUメモリにコピーされ、結果はCPUメモリにコピーバックされます。異なるデバイス間および異なるセッション間でのメモリコピーは、推論時間に大きなオーバーヘッドをもたらします。WebNNは、この問題に対処するために新しい不透明なデバイス固有のストレージタイプMLTensorを提供します。

MLTensorから入力データを取得する場合、または出力データをさらなる処理のためにMLTensor上に保持したい場合は、IOバインディングを使用してデータをMLTensor上に保持できます。これは、通常、前の出力を次の入力として単一のモデルを複数回実行するトランスフォーマーベースのモデルを実行する際に特に役立ちます。

モデル入力の場合、入力データがWebNNストレージMLTensorの場合、MLTensorから入力テンソルを作成できます。

モデル出力の場合、IOバインディング機能を使用する方法は2つあります:

以下のトピックも確認してください:

注意: MLTensorはIOバインディングのために共有MLContextを必要とします。これは、MLContextがWebNN EPオプションとして事前作成され、すべてのセッション間で利用されるべきであることを意味します。

入力データがWebNNストレージMLTensorの場合、MLTensorテンソルを作成して入力テンソルとして使用できます:

// WebNN MLContextを作成
const mlContext = await navigator.ml.createContext({deviceType, ...});
// WebNN MLTensorを作成
const inputMLTensor = await mlContext.createTensor({
dataType: 'float32',
shape: [1, 3, 224, 224],
writable: true,
});
// MLTensorにデータを書き込み
const inputArrayBuffer = new Float32Array(1 * 3 * 224 * 224).fill(1.0);
mlContext.writeTensor(inputMLTensor, inputArrayBuffer);
// MLTensorからORTテンソルを作成
const inputTensor = ort.Tensor.fromMLTensor(inputMLTensor, {
dataType: 'float32',
dims: [1, 3, 224, 224],
});

このテンソルをモデル入力(feeds)として使用することで、入力データがMLTensor上に保持されます。

事前割り当てされたMLTensorテンソルを使用

Section titled “事前割り当てされたMLTensorテンソルを使用”

出力形状を事前に知っている場合、MLTensorテンソルを作成して出力テンソルとして使用できます:

// 事前割り当てされたMLTensorと対応するORTテンソルを作成。出力形状が[10, 1000]であると仮定。
const mlContext = await navigator.ml.createContext({deviceType, ...});
const preallocatedMLTensor = await mlContext.createTensor({
dataType: 'float32',
shape: [10, 1000],
readable: true,
});
const preallocatedOutputTensor = ort.Tensor.fromMLTensor(preallocatedMLTensor, {
dataType: 'float32',
dims: [10, 1000],
});
// ...
// fetchesでセッションを実行
const feeds = { 'input_0': inputTensor };
const fetches = { 'output_0': preallocatedOutputTensor };
await session.run(feeds, fetches);
// 必要に応じてpreallocatedMLTensorからoutput_0データを読み取り
const output_0 = await mlContext.readTensor(preallocatedMLTensor);
console.log('output_0 value:', new Float32Array(output_0));

fetchesで出力テンソルを指定することで、ONNX Runtime Webは事前割り当てされたMLTensorを出力テンソルとして使用します。形状の不一致がある場合、run()呼び出しは失敗します。

出力に事前割り当てされたMLTensorテンソルを使用したくない場合は、セッションオプションで出力データの場所を指定することもできます:

const sessionOptions1 = {
...,
// すべての出力データをMLTensor上に保持
preferredOutputLocation: 'ml-tensor'
};
const sessionOptions2 = {
...,
// または、各出力テンソルの出力場所を指定
preferredOutputLocation: {
'output_0': 'cpu', // output_0をCPU上に保持。これがデフォルトの動作。
'output_1': 'ml-tensor' // output_1をMLTensorテンソル上に保持
}
};
// ...
// セッションを実行
const feeds = { 'input_0': inputTensor };
const results = await session.run(feeds);
// output_1データを読み取り
const output_1 = await results['output_1'].getData();
console.log('output_1 value:', new Float32Array(output_1));

preferredOutputLocation設定を指定することで、ONNX Runtime Webは出力データを指定されたデバイス上に保持します。

詳細についてはAPI reference: preferredOutputLocationを参照してください。

MLTensorテンソルライフサイクル管理

Section titled “MLTensorテンソルライフサイクル管理”

メモリリークを回避し、テンソル使用効率を向上させるために、基盤となるMLTensorがどのように管理されるかを理解することが重要です。

MLTensorテンソルは、ユーザーコードまたはモデルの出力としてONNX Runtime Webによって作成されます。

  • ユーザーコードによって作成される場合、常にTensor.fromMLTensor()を使用して既存のMLTensorで作成されます。この場合、テンソルはMLTensorを「所有」しません。

    • 推論中に基盤となるMLTensorが有効であることを確認し、不要になったときにmlTensor.destroy()を呼び出してMLTensorを破棄するのはユーザーの責任です。
    • tensor.getData()tensor.dispose()の呼び出しは避けてください。MLTensorテンソルを直接使用してください。
    • 破棄されたMLTensorでMLTensorテンソルを使用すると、セッション実行が失敗します。
  • モデルの出力としてONNX Runtime Webによって作成される場合(事前割り当てされたMLTensorテンソルではない)、テンソルはMLTensorを「所有」します。

    • テンソルが使用される前にMLTensorが破棄される場合について心配する必要はありません。
    • tensor.getData()を呼び出してMLTensorからCPUにデータをダウンロードし、型付き配列としてデータを取得します。
    • 不要になったときに基盤となるMLTensorを破棄するために、明示的にtensor.dispose()を呼び出します。