![【Bug已解决】[WebNN][WebGPU EP] Device tensor can not be properly initialized 解决方案](http://pic.xiahunao.cn/yaotu/【Bug已解决】[WebNN][WebGPU EP] Device tensor can not be properly initialized 解决方案)
【Bug已解决】[WebNN][WebGPU EP] Device tensor can not be properly initialized 解决方案一、现象长什么样在 WebNN 或 ORT 的 WebGPU EP 上模型尝试创建一个device tensor常驻设备显存的张量比如预分配的 KV cache、常驻常量、或跨 run 复用的 buffer时初始化失败报错类似“device tensor can not be properly initialized”// WebNN / ORT Web 上预分配设备侧 tensor用于 KV cache 等 const session await ort.InferenceSession.create(model.onnx, { executionProviders: [webgpu], }); // 某些初始化阶段device tensor 创建失败 - 报错最小信号device tensor设备侧常驻张量初始化失败 WebGPU / WebNN 后端特有 可能是 buffer 创建标志不对、设备或队列未就绪、初始化顺序错注意这不是普通推理错而是设备资源device tensor创建阶段失败常发生在 session 初始化 / 第一次 run 之前。二、背景“device tensor”指的是分配在 GPU 设备显存、且生命周期跨多次run()复用的张量。常见用途KV cache自回归解码时缓存 key/value避免每步重算常驻常量模型权重/embedding 常驻设备不每次上传SessionBufferPool 里的复用 buffer之前几篇提到的 buffer 缓存。在 WebGPU 上创建一个 device tensor 需要做几件事拿到一个已配置好的 GPUDevice含所需特性/限制如maxBufferSize、maxStorageBufferBindingSize用正确的GPUBufferUsage标志创建 buffer如STORAGE | COPY_DST | COPY_SRC某些用途还要VERTEX/INDEX或INDIRECT确保 device/queue 已就绪且当前不在 device 丢失device lost状态初始化顺序正确先建 device tensor再建依赖它的执行计划。失败通常出在这几步之一device 没带所需特性、buffer usage 标志不全、或 device tensor 在 device 还没就绪时就被创建。三、根因根因是device tensor 创建时GPUDevice 未就绪 / buffer usage 标志不全 / 初始化顺序错误导致设备侧张量分配失败buffer usage 标志不全创建 device tensor 时用的GPUBufferUsage缺少某个必需标志比如需要STORAGE却只给了COPY_DSTWebGPU 校验直接拒绝tensor 建不出来。device 特性/限制不足device 创建时没请求所需特性如某扩展或maxBufferSize不够大分配大 device tensor 失败。初始化顺序错在 GPUDevice / queue 还没完全就绪或异步requestAdapter/requestDevice未 await时就去建 device tensor拿到空/失效的 device - 失败。device lost 未处理创建设备 tensor 期间 device 进入 lost 状态驱动崩溃/上下文丢失分配失败且没重试。不是算子错纯资源创建阶段失败发生在执行之前。所以这不是数值错而是WebGPU device tensor 的资源创建配置/顺序不对导致分配失败。四、最小可运行复现下面用 JS 风格的伪代码模拟“buffer usage 标志不全 / device 未就绪导致 device tensor 创建失败”// 模拟 WebGPU device tensor 创建 async function createDeviceTensor(device, size, usage) { if (!device || device.lost) { throw new Error(device tensor can not be properly initialized: device not ready); } // 需要 STORAGE | COPY_DST缺少则失败 const required GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST; if ((usage required) ! required) { throw new Error(device tensor can not be properly initialized: usage flags incomplete); } return device.createBuffer({ size, usage }); } // 错误用法 1device 未 await 就绪 const badDevice null; // 模拟未就绪 try { await createDeviceTensor(badDevice, 1024, GPUBufferUsage.STORAGE); } catch (e) { console.log(e.message); } // device not ready // 错误用法 2usage 缺 COPY_DST try { await createDeviceTensor(fakeReadyDevice, 1024, GPUBufferUsage.STORAGE); } catch (e) { console.log(e.message); } // usage incomplete跑这个逻辑device 未就绪或缺 usage 标志都会抛“device tensor can not be properly initialized”。这复现了“资源创建配置/顺序不对导致失败”的机制。五、解决方案第一层最小直接修复最小修复确保 GPUDevice 在创建 device tensor 前完全就绪且 buffer 用全所需GPUBufferUsage标志。对使用者临时规避是检查 device 创建流程确保requestDevice已 await、所需特性已请求或回退到非 device-tensor 路径每次 run 重新分配/上传。ORT Web 侧修复示意// 修复device tensor 创建前校验 device 就绪 usage 完整 if (device_.lost() || !device_.IsReady()) { // 等待 device 就绪或重建 device再建 tensor device_ RecreateDeviceWithRequiredFeatures(); } GPUBufferUsageFlags usage GPUBufferUsage::Storage | GPUBufferUsage::CopyDst | GPUBufferUsage::CopySrc; // 补全标志 auto tensor device_.CreateBuffer(size, usage);这一层立刻让 device tensor 创建成功device 就绪 usage 完整。六、解决方案第二层结构性改进把“device tensor 创建的前置条件”收口成唯一的配置对象OrtWebnnDeviceTensorInitPolicyWeb 资源创建读它from dataclasses import dataclass, field from typing import Tuple dataclass(frozenTrue) class OrtWebnnDeviceTensorInitPolicy: WebNN/WebGPU device tensor 初始化的单一事实来源。 # 创建 device tensor 前必须满足 require_device_ready: bool True # 必需的 buffer usage 标志WebGPU required_buffer_usage: Tuple[str, ...] (STORAGE, COPY_DST, COPY_SRC) # device 必须请求的特性 required_features: Tuple[str, ...] () # 初始化顺序先 device后 device tensor init_order: Tuple[str, ...] (gpu_device, queue, device_tensor) # device lost 时是否重建重试 rebuild_on_lost: bool True def usage_complete(self, given: Tuple[str, ...]) - bool: return all(u in given for u in self.required_buffer_usage) def describe(self) - str: return device tensor 创建前 device 就绪 usage 完整 顺序正确 POLICY OrtWebnnDeviceTensorInitPolicy() def plan_device_tensor(given_usage, policy: OrtWebnnDeviceTensorInitPolicy POLICY) - bool: return policy.usage_complete(given_usage)所有 Web 资源创建读同一份POLICYdevice tensor 的前置条件被固化。七、解决方案第三层断言 / CI 守护把“device tensor 能正确初始化”做成断言。下面用 pytest 风格守护import pytest def test_device_ready_required(policy): assert policy.require_device_ready is True def test_usage_complete(policy): given (STORAGE, COPY_DST, COPY_SRC) assert policy.usage_complete(given) is True assert policy.usage_complete((STORAGE,)) is False def test_init_order(policy): assert policy.init_order[0] gpu_device assert policy.init_order[-1] device_tensor def test_rebuild_on_lost(policy): assert policy.rebuild_on_lost is True这四组断言锁住(1) device 必须就绪(2) usage 标志完整校验(3) 初始化顺序正确先 device 后 tensor(4) device lost 重建。CI 跑通即代表 device tensor 初始化被守护。八、排查清单遇到 WebNN/WebGPU device tensor 初始化失败看报错关键字是 device 未就绪还是 usage 标志不全。查 device 创建流程requestDevice有没有 await所需特性有没有请求。查 buffer usage 标志device tensor 需要的 STORAGE/COPY_DST/COPY_SRC 是否齐全。查初始化顺序是不是在 device 就绪前就建 tensor。查 device lost创建期间 device 是否丢失有无重建重试。统一策略对象用OrtWebnnDeviceTensorInitPolicy固化。CI 守护断言 device 就绪、usage 完整、顺序正确。九、小结[WebNN][WebGPU EP] Device tensor can not be properly initialized的根因是在 WebGPU/WebNN 上创建常驻设备张量KV cache、常驻常量等时GPUDevice 未就绪、或创建 buffer 用的GPUBufferUsage标志不全缺 STORAGE/COPY_DST 等、或初始化顺序错误在 device 就绪前建 tensor、或 device lost 未重建导致设备侧张量分配失败。最小修复是确保 GPUDevice 在创建 device tensor 前完全就绪、buffer 用全所需 usage 标志、初始化顺序正确先 device 后 tensor结构性改进是用唯一的OrtWebnnDeviceTensorInitPolicy固化前置条件CI 用四组断言守护“device 就绪、usage 完整、顺序正确、lost 重建”。记住设备侧资源创建前必须确认 device 就绪且标志齐全否则 tensor 建不出来。