WebNNとは?WebGPU・WebAssemblyとの違いと対応環境を2026年版で確認する

WebNN・WebGPU・WASM、何が違う? 黄色と黒の文字で示すブラウザAIの技術比較 ブラウザAI
カテゴリー
ブラウザAI
公開日
2026.09.22

はじめに

ブラウザ内AIについて調べると、WebNN、WebGPU、WebAssemblyという似た文脈の名前が登場します。

どれもブラウザで計算処理を行うために利用できますが、同じ技術ではありません。

この記事では3つの役割を整理し、利用中のブラウザで次を確認する診断ページを作ります。

  • WebAssemblyの基本機能を利用できるか
  • WebGPUのGPUAdapterを取得できるか
  • WebNNのMLContextを作成できるか
  • APIが存在しても初期化に失敗した場合、その理由を表示できるか

WebNNで大きなAIモデルを直接組み立てるのではなく、「何がどの層を担当するのか」と「採用前に何を確認するのか」に焦点を当てます。

3つの技術の違い

技術主な抽象度主な用途開発者が記述するもの
WebAssemblyCPUで実行する低水準バイナリ形式他言語製ライブラリ、汎用計算Wasmモジュールまたはそれを使うライブラリ
WebGPUGPUへアクセスする低水準API描画、汎用GPU計算、機械学習バッファ、パイプライン、WGSLシェーダーなど
WebNNニューラルネットワークの演算を扱うAPI学習済みモデルの推論演算グラフ、テンソル、実行指示

WebAssembly

WebAssemblyは、C、C++、Rustなどで作られた処理をブラウザで効率よく実行するためにも使われるバイナリ形式です。機械学習専用ではありません。

ONNX Runtime Webなどは、GPU向けAPIを利用できない環境でWASMをCPU実行基盤として利用できます。

WebGPU

WebGPUはGPUへバッファや命令を送り、描画や汎用計算を実行するためのAPIです。機械学習でも利用できますが、ニューラルネットワーク専用ではありません。

低水準APIなので、直接利用する場合はデータ型、バッファ、パイプライン、シェーダー、エラー処理などを管理します。Transformers.jsやONNX Runtime Webを使うと、通常はこれらの大部分をライブラリが担当します。

WebNN

WebNNは、ニューラルネットワークの推論をWebアプリから実行するためのAPIです。WebGPUのシェーダーよりも演算の単位で記述できますが、モデルを読み込むだけで使えるアプリ向けライブラリではありません。仕様上は低水準APIと位置付けられ、演算グラフやテンソルを扱います。ブラウザやOSが利用可能なCPU、GPU、NPUなどを使って処理するための抽象層を提供します。

WebNNの目的は「JavaScriptからNPUを直接自由に操作すること」ではありません。現在の仕様では、実行デバイスの選択を実装側へ委ねながら、powerPreferenceacceleratedなどで意図を伝える設計が進められています。

2026年仕様で注意したいdeviceType

古いWebNN記事や一部のライブラリAPIでは、次のようなコードを見かけます。

// 古いWebNN API例として見かける形式
await navigator.ml.createContext({ deviceType: "npu" });

しかし、参照したWebNN Editor’s Draftでは、deviceTypeMLContextOptionsの直接のオプションではありません。この辞書にはpowerPreferenceacceleratedが定義されています。

const context = await navigator.ml.createContext({
  powerPreference: "high-performance",
  accelerated: true,
});

ここでの値は希望を伝えるものであり、特定デバイスで実行されることを無条件に保証するものではありません。

なお、ライブラリ独自のオプションとWeb標準APIのオプションは別です。例えばONNX Runtime WebのWebNN Execution ProviderがdeviceTypeを受け付けるバージョンがあっても、それだけでnavigator.ml.createContext()の最新仕様にも同じプロパティがあるとは判断できません。

仕様、ブラウザ実装、利用ライブラリの3つを分けて確認してください。

対応確認はプロパティの存在だけでは不十分

次のコードはWebGPU APIの入口があるかを調べています。

if ("gpu" in navigator) {
  console.log("WebGPU APIがあります");
}

しかし、navigator.gpuがあっても、requestAdapter()nullを返す可能性があります。WebNNもnavigator.mlが存在した後、createContext()が失敗する可能性があります。

採用判断では、APIの存在確認と初期化確認の両方を行います。

診断ページを作る

次のindex.htmlを作成します。外部ライブラリは必要ありません。

<!doctype html>
<html lang="ja">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>ブラウザAI実行環境診断</title>
    <style>
      body { width: min(760px, calc(100% - 32px)); margin: 40px auto; font-family: system-ui; }
      table { width: 100%; border-collapse: collapse; }
      th, td { border: 1px solid #cbd5e1; padding: 10px; text-align: left; }
      .ok { color: #166534; }
      .warn { color: #9a3412; }
      code { overflow-wrap: anywhere; }
    </style>
  </head>
  <body>
    <main>
      <h1>ブラウザAI実行環境診断</h1>
      <button id="run" type="button">診断する</button>
      <p id="status" role="status" aria-live="polite"></p>
      <table>
        <thead><tr><th>機能</th><th>結果</th><th>詳細</th></tr></thead>
        <tbody id="results"></tbody>
      </table>
    </main>
    <script type="module">
      const runButton = document.querySelector("#run");
      const status = document.querySelector("#status");
      const results = document.querySelector("#results");

      function addResult(name, supported, detail) {
        const row = document.createElement("tr");
        const nameCell = document.createElement("th");
        const resultCell = document.createElement("td");
        const detailCell = document.createElement("td");

        nameCell.scope = "row";
        nameCell.textContent = name;
        resultCell.textContent = supported ? "利用可能" : "利用不可";
        resultCell.className = supported ? "ok" : "warn";
        detailCell.textContent = detail;
        row.append(nameCell, resultCell, detailCell);
        results.append(row);
      }

      function checkWebAssembly() {
        if (typeof WebAssembly !== "object") return false;
        // 空の有効なWasmモジュールを検証する
        return WebAssembly.validate(
          new Uint8Array([0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00]),
        );
      }

      async function checkWebGPU() {
        if (!("gpu" in navigator)) {
          return { supported: false, detail: "navigator.gpuがありません。" };
        }

        try {
          const adapter = await navigator.gpu.requestAdapter();
          if (!adapter) {
            return { supported: false, detail: "GPUAdapterを取得できませんでした。" };
          }
          return { supported: true, detail: "GPUAdapterを取得できました。" };
        } catch (error) {
          return { supported: false, detail: String(error) };
        }
      }

      async function checkWebNN() {
        if (!("ml" in navigator)) {
          return { supported: false, detail: "navigator.mlがありません。" };
        }

        try {
          const context = await navigator.ml.createContext({
            powerPreference: "high-performance",
            accelerated: true,
          });
          const accelerated =
            "accelerated" in context ? String(context.accelerated) : "取得不可";
          context.destroy?.();
          return {
            supported: true,
            detail: `MLContextを作成できました。accelerated: ${accelerated}`,
          };
        } catch (error) {
          return { supported: false, detail: String(error) };
        }
      }

      runButton.addEventListener("click", async () => {
        runButton.disabled = true;
        results.replaceChildren();
        status.textContent = "診断しています。";

        try {
          const wasm = checkWebAssembly();
          addResult("WebAssembly", wasm, wasm ? "基本モジュールを検証できました。" : "基本機能を確認できません。" );

          const webgpu = await checkWebGPU();
          addResult("WebGPU", webgpu.supported, webgpu.detail);

          const webnn = await checkWebNN();
          addResult("WebNN", webnn.supported, webnn.detail);
          status.textContent = "診断が完了しました。";
        } finally {
          runButton.disabled = false;
        }
      });
    </script>
  </body>
</html>

ローカルサーバーで開く

WebNNとWebGPUは安全なコンテキストで提供されるAPIです。localhostは開発用の信頼できるオリジンとして扱われますが、ファイルをダブルクリックしたfile://ではなくHTTPサーバーから開いてください。

Python 3を用意し、index.htmlを保存したフォルダーでターミナルを開きます。python --versionでバージョンが表示されることを確認してから、次を実行します。

python -m http.server 8000 --bind 127.0.0.1

ブラウザでhttp://localhost:8000を開き、「診断する」を押します。Windowsでpythonが見つからずPythonランチャーがある場合は、py -3 -m http.server 8000 --bind 127.0.0.1を使えます。Pythonが未導入ならPython公式サイトから導入してください。サーバーはターミナルを開いたまま使い、終了するときはCtrl+Cを押します。

接続できない場合はサーバーが起動中か、ファイル一覧が出る場合はindex.htmlの保存先と実行フォルダーが同じかを確認します。

結果の読み方

WASMだけ利用可能

ブラウザ内AIをCPUで動かせる可能性があります。Transformers.jsやONNX Runtime WebのWASM実行を検討します。

WebGPUも利用可能

GPU向け実行基盤を選べる可能性があります。ただし、対象モデルを実際に初期化し、推論が成功することを別途確認します。

WebNNが利用不可

珍しくありません。WebNNを必須条件にせず、WebGPUまたはWASMへ切り替える設計が必要です。

WebNNが利用可能

MLContextを作れたことは確認できましたが、すべての演算子やモデルが動くことを意味しません。利用予定のモデルをONNX Runtime Webなどで実行し、対応演算子とフォールバックの動きを確認します。

WebNNを直接使うか、ライブラリ経由で使うか

WebNNでは演算グラフを直接組み立てられます。しかし実際のONNXモデルを扱う場合、モデルファイルの解析、演算子の割り当て、テンソル管理などが必要です。

WebNN公式サンプルでも、通常のアプリではONNX Runtime WebなどWebNNを統合したJavaScriptライブラリを使う方法が推奨されています。学習目的や独自グラフを作る目的でなければ、まずライブラリ経由を検討するとよいでしょう。

フォールバック設計

実行基盤の選択例は次のようになります。

  1. WebNNで対象モデルの初期化を試す
  2. 初期化または演算子対応で失敗したらWebGPUを試す
  3. WebGPUが失敗したらWASMへ切り替える
  4. どの基盤でも動かない場合は、サーバー推論または非AI機能を案内する

APIの有無だけで選ばず、モデルの初期化を含めて判定してください。

仕様変更への備え

WebNNはEditor’s Draftであり、MLContextOptionsも活発に検討されています。再現性のため、記事本文とは別の検証メモに次を記録します。

  • 確認した仕様日
  • ブラウザ名とバージョン
  • OSと主なハードウェア
  • 利用ライブラリのバージョン
  • 実験的フラグを変更したか

古いコードをコピーするときは、deviceType、テンソルAPI、演算子名などを最新仕様と照合してください。

関連記事

まとめ

WebAssemblyは汎用のCPU実行基盤、WebGPUはGPU向けの低水準API、WebNNはニューラルネットワークの演算グラフを扱う推論APIです。

WebNNは有望ですが、策定と実装が進行中です。WebNNだけを前提にせず、実際の初期化結果を確認し、WebGPUやWASMへ切り替えられる設計にします。

次の記事ではONNX Runtime Webを使い、これらの実行基盤をExecution Providerとして切り替える方法を扱います。

参考リンク

コメント

タイトルとURLをコピーしました