Skip to content

필사 모드: WebAssembly & エッジコンピューティング: ブラウザAI推論、Cloudflare Workers、IoT Wasmまで

日本語
0%
정확도 0%
💡 왼쪽 원문을 읽으면서 오른쪽에 따라 써보세요. Tab 키로 힌트를 받을 수 있습니다.
원문 렌더가 준비되기 전까지 텍스트 가이드로 표시합니다.

WebAssemblyとは何か

WebAssembly(Wasm)は2019年にW3C公式Web標準として採択されたバイナリ命令フォーマットです。ブラウザ、サーバー、IoTデバイスを問わずネイティブに近い速度で実行でき、JavaScriptがブラウザで動く唯一の言語という地位を事実上終わらせました。

Wasmのコア設計原則は以下の4つです。

- **安全性(Safety)**: サンドボックスメモリモデルがホスト環境を保護します。

- **移植性(Portability)**: CPUアーキテクチャに関係なく同一の動作を保証します。

- **速度(Speed)**: JIT/AOTコンパイルにより、数値演算でJavaScriptの数倍のスループットを実現します。

- **開放性(Open)**: 特定の言語やプラットフォームに依存しません。

1. WATテキストフォーマットとバイトコード構造

WebAssemblyには2つの表現形式があります。`.wasm`バイナリフォーマットと、人間が読める`.wat`(WebAssembly Text Format)です。

WAT例: 2つの整数の和

(module

(func $add (param $a i32) (param $b i32) (result i32)

local.get $a

local.get $b

i32.add)

(export "add" (func $add)))

`.wasm`にコンパイルされるとマジックナンバー`\0asm`(0x00 0x61 0x73 0x6D)で始まるバイナリになります。

バイトコード構造

Wasmモジュールはセクション単位で構成されています。

| セクションID | 名前 | 説明 |

| ------------ | -------- | ---------------------- |

| 1 | Type | 関数シグネチャ定義 |

| 3 | Function | 関数インデックス |

| 7 | Export | 外部に公開するシンボル |

| 10 | Code | 実際の関数ボディ |

線形メモリ(Linear Memory)

Wasmは単一の連続バイト配列である**線形メモリ**を使用します。64KBページ単位で割り当てられ、JavaScriptから`WebAssembly.Memory`オブジェクトを通じて直接アクセスできます。

const memory = new WebAssembly.Memory({ initial: 1, maximum: 10 })

const buffer = new Uint8Array(memory.buffer)

// オフセット0から直接読み書き

buffer[0] = 42

ポインタ演算はWasmインスタンスのサンドボックス内に安全に隔離されており、ホストメモリには一切アクセスできません。

2. WASI: WebAssembly System Interface

WASIはWasmモジュールがファイルシステム、ネットワーク、環境変数などのOS機能にアクセスするための**標準システムインターフェース**です。Dockerの創設者Solomon Hykes氏が「WASM+WASIが2008年に存在していたらDockerは必要なかった」と述べたことで広く知られるようになりました。

(import "wasi_snapshot_preview1" "fd_write"

(func $fd_write (param i32 i32 i32 i32) (result i32)))

WASIが提供する主要な抽象化:

- **ファイルシステム**: `fd_read`、`fd_write`、`path_open`

- **クロック**: `clock_time_get`

- **環境変数**: `environ_get`

- **ネットワーク(WASI 0.2)**: `wasi:sockets`インターフェース

2024年に正式リリースされたWASI 0.2(Component Model)では、高水準インターフェース定義言語WIT(Wasm Interface Types)が導入されました。

3. Wasmエコシステム: Rust、AssemblyScript、Emscripten

Rust to WebAssembly (wasm-pack)

RustはWasmエコシステムで最も成熟した言語です。`wasm-pack`を使えばnpmパッケージとしてすぐ配布できるWasmモジュールを生成できます。

// src/lib.rs

use wasm_bindgen::prelude::*;

#[wasm_bindgen]

pub fn fibonacci(n: u32) -> u32 {

match n {

0 => 0,

1 => 1,

_ => fibonacci(n - 1) + fibonacci(n - 2),

}

}

#[wasm_bindgen]

pub fn matrix_multiply(a: &[f32], b: &[f32], n: usize) -> Vec<f32> {

let mut result = vec![0.0f32; n * n];

for i in 0..n {

for j in 0..n {

for k in 0..n {

result[i * n + j] += a[i * n + k] * b[k * n + j];

}

}

}

result

}

ビルドとデプロイ:

wasm-packのインストール

cargo install wasm-pack

ブラウザ向けビルド

wasm-pack build --target web

Node.js向けビルド

wasm-pack build --target nodejs

生成された`pkg/`ディレクトリには`.wasm`バイナリ、JavaScriptグルーコード、TypeScript型定義が含まれます。

JavaScriptからWasmモジュールを呼び出す

async function main() {

// Wasmモジュールの初期化

await init()

// フィボナッチ計算

console.log(fibonacci(40)) // 102334155

// 行列乗算 (4x4)

const a = new Float32Array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16])

const b = new Float32Array([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1])

const result = matrix_multiply(a, b, 4)

console.log(result)

}

main()

AssemblyScript

TypeScriptに似た構文でWasmを記述できる言語です。

// assembly/index.ts

export function add(a: i32, b: i32): i32 {

return a + b

}

export function sumArray(ptr: usize, len: i32): i64 {

let sum: i64 = 0

for (let i = 0; i < len; i++) {

sum += load<i32>(ptr + i * 4)

}

return sum

}

Emscripten (C/C++)

C/C++コードベースをWasmにポーティングする際のツールチェーンです。FigmaとGoogle EarthはこのアプローチでWasmを使用しています。

CファイルをWasmにコンパイル

emcc compute.c -O3 -o compute.js \

-s WASM=1 \

-s EXPORTED_FUNCTIONS='["_process_image"]' \

-s EXPORTED_RUNTIME_METHODS='["ccall","cwrap"]'

4. ブラウザAI: ONNX Runtime Web、WebNN、WebGPU

ONNX Runtime Webによるブラウザ内推論

ONNX Runtime WebはブラウザでONNXモデルを直接実行します。バックエンドとしてWebAssembly(CPU)、WebGL、WebGPUをサポートします。

async function runInference() {

// WebGPUバックエンド優先、フォールバックはWasm

const session = await ort.InferenceSession.create('/models/bert-base.onnx', {

executionProviders: ['webgpu', 'wasm'],

graphOptimizationLevel: 'all',

})

// 入力テンソルの作成

const inputIds = new BigInt64Array([101n, 2023n, 2003n, 102n])

const attentionMask = new BigInt64Array([1n, 1n, 1n, 1n])

const feeds = {

input_ids: new ort.Tensor('int64', inputIds, [1, 4]),

attention_mask: new ort.Tensor('int64', attentionMask, [1, 4]),

}

const results = await session.run(feeds)

console.log('Logits:', results.logits.data)

}

WebGPUコンピュートシェーダーによる行列演算

WebGPUはGPUの並列演算能力をWebから直接活用できます。ML推論においてWebGLより優れている核心的な理由は**コンピュートシェーダーのファーストクラスサポート**です。

async function webgpuMatmul(matA, matB, M, N, K) {

const adapter = await navigator.gpu.requestAdapter()

const device = await adapter.requestDevice()

const shaderCode = `

@group(0) @binding(0) var<storage, read> matA: array<f32>;

@group(0) @binding(1) var<storage, read> matB: array<f32>;

@group(0) @binding(2) var<storage, read_write> result: array<f32>;

@compute @workgroup_size(8, 8)

fn main(@builtin(global_invocation_id) gid: vec3<u32>) {

let row = gid.x;

let col = gid.y;

var sum = 0.0;

for (var k = 0u; k < ${K}u; k++) {

sum += matA[row * ${K}u + k] * matB[k * ${N}u + col];

}

result[row * ${N}u + col] = sum;

}

`

const shaderModule = device.createShaderModule({ code: shaderCode })

// ... バッファ作成、パイプライン設定、ディスパッチ

}

WebNN API

WebNN(Web Neural Network API)はブラウザがOSレベルのハードウェアアクセラレーション(NPU、GPU、DSP)を直接活用できるW3C標準APIです。

const context = await navigator.ml.createContext({ deviceType: 'gpu' })

const builder = new MLGraphBuilder(context)

const input = builder.input('input', { type: 'float32', dimensions: [1, 3, 224, 224] })

const weights = builder.constant(/* ... */)

const conv = builder.conv2d(input, weights, { padding: [1, 1, 1, 1] })

const relu = builder.relu(conv)

const graph = await builder.build({ output: relu })

const results = await context.compute(graph, inputs, outputs)

5. エッジAIデプロイ: Cloudflare Workers、Fastly、AWS Lambda@Edge

Cloudflare Workers AI

Cloudflare WorkersはV8 isolateベースで世界300以上のPoP(Point of Presence)で実行されます。AIバインディングによりエッジで直接推論を行います。

// Cloudflare Worker with AIバインディング

export default {

async fetch(request, env) {

const body = await request.json()

const userMessage = body.message

// AIバインディングでLLM推論

const response = await env.AI.run('@cf/meta/llama-3.1-8b-instruct', {

messages: [

{

role: 'system',

content: 'You are a helpful assistant.',

},

{

role: 'user',

content: userMessage,

},

],

max_tokens: 512,

})

return new Response(JSON.stringify({ reply: response.response }), {

headers: { 'Content-Type': 'application/json' },

})

},

}

`wrangler.toml`設定:

name = "edge-ai-worker"

main = "src/index.js"

compatibility_date = "2024-09-23"

[ai]

binding = "AI"

Fastly Compute (RustベースのWasm)

use fastly::{Error, Request, Response};

#[fastly::main]

fn main(req: Request) -> Result<Response, Error> {

let body = req.into_body_str();

// Wasm内で直接処理

let processed = process_at_edge(&body);

Ok(Response::from_body(processed))

}

fn process_at_edge(input: &str) -> String {

format!("Processed at edge: {}", input.to_uppercase())

}

Cloudflare Workers vs AWS Lambda@Edge 比較

| 特性 | Cloudflare Workers | AWS Lambda@Edge |

| ---------------- | ------------------ | ------------------------- |

| 実行モデル | V8 Isolate | コンテナベース |

| コールドスタート | 約0ms | 100ms〜数秒 |

| メモリ上限 | 128MB | 128MB〜10GB |

| 最大実行時間 | 30秒(有料プラン) | 30秒 |

| グローバルPoP | 300以上 | CloudFrontエッジ |

| 言語サポート | JS/TS、Wasm | Node.js、Python、Javaなど |

Cloudflare Workersのコールドスタートがほぼゼロな核心的理由は、**新しいOSプロセスを起動するのではなくV8 isolateを再利用する**からです。各WorkerはOSプロセスの初期化を伴わず、同一プロセス内の隔離されたJavaScript実行コンテキストで動作します。

6. IoT & 組み込みWasm

WasmEdge

WasmEdgeはCNCF(Cloud Native Computing Foundation)のサンドボックスプロジェクトで、IoTおよびエッジデバイス向けの軽量Wasmランタイムです。

WasmEdgeのインストール

curl -sSf https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/utils/install.sh | bash

WasmEdgeでPythonスクリプトを実行

wasmedge --dir .:. python_wasm.wasm script.py

WasmEdge上でPythonスクリプトを実行:

script.py - WasmEdge上で動作

def process_sensor_data(data):

temperature = data.get('temperature', 0)

humidity = data.get('humidity', 0)

if temperature > 80 or humidity > 90:

return {'alert': True, 'reason': 'threshold_exceeded'}

return {'alert': False, 'status': 'normal'}

data = json.loads(sys.argv[1])

result = process_sensor_data(data)

print(json.dumps(result))

WAMR (WebAssembly Micro Runtime)

WAMRはBytecode Allianceが開発した超軽量Wasmランタイムで、数KBのRAMで動作します。

最小メモリ要件:

- インタープリターモード: 約85KB ROM + 64KB RAM

- AOTモード: 約60KB ROM + 64KB RAM

Fermyon Spin

SpinはWasmベースのマイクロサービスフレームワークです。

spin.toml

spin_manifest_version = 2

[application]

name = "iot-processor"

version = "0.1.0"

[[trigger.http]]

route = "/sensor"

component = "sensor-handler"

[component.sensor-handler]

source = "target/wasm32-wasi/release/sensor_handler.wasm"

[component.sensor-handler.build]

command = "cargo build --target wasm32-wasi --release"

7. パフォーマンスベンチマーク: Wasm vs ネイティブ

WasmのSIMD

Wasm SIMDは128ビットベクトル演算をサポートし、MLワークロードを大幅に高速化します。

// RustでWasm SIMDを活用

#[cfg(target_arch = "wasm32")]

use std::arch::wasm32::*;

pub fn dot_product_simd(a: &[f32], b: &[f32]) -> f32 {

let mut sum = f32x4_splat(0.0);

let chunks = a.len() / 4;

for i in 0..chunks {

let va = v128_load(a[i*4..].as_ptr() as *const v128);

let vb = v128_load(b[i*4..].as_ptr() as *const v128);

sum = f32x4_add(sum, f32x4_mul(va, vb));

}

// 水平合算

let arr: [f32; 4] = unsafe { std::mem::transmute(sum) };

arr.iter().sum()

}

SharedArrayBufferによるマルチスレッディング

Wasmのスレッド化は`SharedArrayBuffer`と`Atomics` APIを活用します。

// 共有メモリでWasmマルチスレッディング

const sharedMemory = new WebAssembly.Memory({

initial: 16,

maximum: 256,

shared: true, // SharedArrayBufferを有効化

})

// Workerに共有メモリを渡す

const worker = new Worker('wasm-worker.js')

worker.postMessage({ memory: sharedMemory })

ベンチマーク結果(参考値)

| タスク | JavaScript | Wasm(単体) | Wasm + SIMD | ネイティブC |

| ---------------------- | ---------- | ------------ | ----------- | ----------- |

| 行列乗算(1024x1024) | 850ms | 210ms | 55ms | 40ms |

| SHA-256ハッシュ(1MB) | 120ms | 35ms | 22ms | 18ms |

| 画像リサイズ(4K) | 340ms | 95ms | 28ms | 20ms |

Wasm + SIMDはネイティブCと10〜40%以内の差に収束します。

8. 実世界のケーススタディ

Figma

FigmaのレンダリングエンジンはすべてC++で書かれており、Emscriptenを通じてWasmにコンパイルされています。これにより複雑なベクターグラフィック演算がブラウザで60fpsで処理されます。

Google Earth

Google Earth for WebもC++エンジンをWasmにポーティングしています。数GBに及ぶ3D地形レンダリングロジックをブラウザで実行します。

Pyodide: ブラウザでPythonを実行

PyodideはCPythonインタープリター全体をWasmにコンパイルし、ブラウザタブ内でPythonを実行します。

async function runPython() {

const pyodide = await loadPyodide()

// ブラウザでnumpyとpandasをインストールして使用

await pyodide.loadPackage(['numpy', 'pandas'])

const result = pyodide.runPython(`

ブラウザ内でnumpy演算

arr = np.random.randn(1000, 1000)

eigenvalues = np.linalg.eigvals(arr[:10, :10])

float(np.abs(eigenvalues).max())

`)

console.log('最大固有値:', result)

}

runPython()

クイズ

**答え**: 静的型システムと予測可能なAOT/JITコンパイル

**解説**: JavaScriptは動的型付け言語であり、ランタイムに型推論、インラインキャッシング、隠しクラスの変換など多くの最適化を行う必要があります。一方Wasmはコンパイル時にすべての型が確定しているため、JITエンジンが即座に最適化された機械語を生成できます。さらにWasmバイトコードは解析オーバーヘッドが非常に低く、SIMDやマルチスレッド命令を明示的に使用できます。

**答え**: OS依存なしにシステムリソースにアクセスするための標準インターフェース

**解説**: ブラウザ外で実行されるWasmモジュールはファイルシステム、ネットワーク、環境変数などへのアクセスが必要ですが、Wasm自体はサンドボックスで隔離されています。WASIはPOSIX類似のシステムコールをWasmインターフェースとして標準化し、同一の`.wasm`バイナリがLinux、Windows、macOS、組み込みシステムなど、どこでも同様に動作するようにします。Dockerコンテナを使わずWasm単体でどこでも実行できる「コンテナの未来」と呼ばれます。

**答え**: コンピュートシェーダーのファーストクラスサポートと明示的なGPUメモリ管理

**解説**: WebGLはグラフィックレンダリングパイプライン向けに設計されており、汎用並列演算(GPGPU)が制限的でした。ML推論の核心である行列乗算や畳み込みを行うにはフラグメントシェーダーを迂回路として使う必要がありました。WebGPUはコンピュートシェーダーをファーストクラス機能としてサポートし、ストレージバッファを通じた柔軟なメモリアクセスと優れた非同期実行モデルを提供します。実際にONNX Runtime WebのWebGPUバックエンドはWebGLバックエンドと比べて2〜5倍高速な推論速度を実現しています。

**答え**: 既存プロセス内でV8 isolateコンテキストのみを作成し、コンテナやOSの初期化が不要

**解説**: AWS Lambdaはリクエストごとに新しいコンテナ(または実行環境)をプロビジョニングし、OSブート、ランタイム初期化などを経る必要があります。このプロセスには数百ミリ秒から数秒かかります。Cloudflare Workersは既に稼働しているV8プロセス内でメモリ隔離されたisolateをほぼ瞬時(約1ms)に作成します。既存プロセスのJITコンパイル済みコードを再利用できるため、実質的にコールドスタートはゼロに近いです。

**答え**: CPythonインタープリター全体をEmscriptenでWasmにコンパイル

**解説**: PyodideはCPython 3.xのソースコード(Cで記述)をEmscriptenツールチェーンでWebAssemblyバイナリにコンパイルします。ブラウザがこのWasmバイナリをロードすると、完全なPythonインタープリターがブラウザタブ内で実行されます。numpyやscipyなどのC拡張モジュールも同様にWasmにコンパイルされて提供されます。JavaScript-Python間の双方向バインディング(PyProxy、JsProxy)により、PythonオブジェクトをJSから、JSオブジェクトをPythonから直接操作できます。JupyterLiteのような完全なブラウザ内Jupyter環境がこの技術を基盤にしています。

まとめ

WebAssemblyは単なる「高速なJavaScriptの代替」を超え、**汎用ランタイムプラットフォーム**として進化しています。WASI Component Modelの成熟、WebGPUの普及、エッジプラットフォームによるWasm採用の加速により、2026年現在Wasmは以下の領域で標準技術として定着しています。

- ブラウザAI推論(ONNX Runtime Web + WebGPU)

- サーバーレスエッジ関数(Cloudflare Workers、Fastly Compute)

- IoTおよび組み込み(WasmEdge、WAMR)

- プラグインシステム(Extism、waPC)

Rustと`wasm-pack`から始まるWasm開発、Cloudflare Workersへのデプロイ、WebGPUを使ったブラウザ内MLモデル実行まで、このガイドがエッジコンピューティングの旅の羅針盤となることを願っています。

현재 단락 (1/280)

WebAssembly(Wasm)は2019年にW3C公式Web標準として採択されたバイナリ命令フォーマットです。ブラウザ、サーバー、IoTデバイスを問わずネイティブに近い速度で実行でき、JavaSc...

작성 글자: 0원문 글자: 11,375작성 단락: 0/280