From 6527765d07cd0b01dac517aed1172ee456f18c5a Mon Sep 17 00:00:00 2001 From: eric8810 Date: Mon, 20 Jul 2026 00:28:00 +0800 Subject: [PATCH] =?UTF-8?q?fix(release):=20=E9=93=B6=E8=88=9F=E9=81=BF?= =?UTF-8?q?=E6=B5=AA=EF=BC=8C=E7=A8=B3=E5=AE=88=E6=9C=AC=E8=88=AA=20=C2=B7?= =?UTF-8?q?=20keep=20macOS=20x64=20release=20on=20CPU?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 6 +++--- README.md | 12 ++++++------ README.zh-CN.md | 12 ++++++------ bindings/node/CMakeLists.txt | 8 ++++++-- bindings/node/README.md | 2 +- bindings/node/js/load-native.cjs | 4 ++-- bindings/node/test/adapter.test.cjs | 5 +++-- docs/apple-device-acceleration.md | 14 +++++++------- docs/implementation-status.md | 2 +- docs/npm-packaging.md | 2 +- tests/python/test_npm_release.py | 10 ++++++++-- tools/npm/smoke.cjs | 14 ++++++++++++-- tools/npm_release.py | 12 ++++++++---- 13 files changed, 64 insertions(+), 39 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 720eb2c..a0f63a6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ This file records user-visible changes to `light-ocr`. Published artifact detail ### Added - Added an opt-in Direct Core ML provider for the `0.3.0` source candidate. Apple Silicon routes FP16 detection and shorter recognition shapes through the Neural Engine envelope, with wider recognition shapes on the GPU. -- Added experimental macOS 15+ compatibility for both `arm64` and `x86_64`. Intel Macs use Core ML CPU+GPU because they do not have an Apple Neural Engine; the strict GPU-only profile remains Apple-Silicon-only. +- Added experimental macOS 15+ Core ML compatibility on `arm64`. The macOS x64 package remains CPU-only after its release smoke test did not reproduce the locked OCR result through Core ML. - Added per-provider and per-session execution diagnostics, including configured provider chain, device family, operating system, precision, model/cache identity, qualification identity, a structured Auto creation trace, and `deviceValidated` evidence status. - Added a self-contained Apple model bundle, deterministic Core ML derivation, offline compiled-model cache, cross-process cache locking, bounded recognition-function caching, and descriptor-driven platform Auto selection. - Added self-contained Native WebGPU execution on Linux x64 glibc/Vulkan and Windows x64/D3D12 with ONNX Runtime 1.24.4, the official WebGPU Plugin EP 0.1.0, hash-verified runtime descriptors, offline staging, and CPU as the final Auto candidate. @@ -44,10 +44,10 @@ This file records user-visible changes to `light-ocr`. Published artifact detail ### Compatibility and evidence - The current source candidate defaults to descriptor-driven Auto selection. Explicit providers are strict single-backend requests, and the legacy `sessionFallback: "cpu"` value returns `invalid_argument`. -- Production bundles use `devicePolicy: "open-macos"`: M1–M3, later Apple Silicon, and Intel Macs are not blocked by the current evidence list. +- Production bundles use `devicePolicy: "open-macos"` for Apple Silicon: M1–M3 and later Apple Silicon are not blocked by the current evidence list. The npm runtime descriptor does not expose Apple on macOS x64. - Real-device performance data currently comes from one Apple M4 Max runner. The evidence contract classifies it under the `Apple M4` device family for `deviceValidated`; this is not a claim that every M4 SKU was measured separately. Other Macs report `deviceValidated: false`; experimental compatibility is available, but no performance number is promised until that hardware family is reviewed. - Heavy model conversion, Compute Plan placement, performance, cache, and lifecycle qualification remain local real-device work. Ordinary CI stays limited to cross-platform builds, contracts, and lightweight tests and does not require paid runners. -- The Core ML provider is merged on `main` but is not included in the published `0.2.0` npm packages. The planned `0.3.0` distribution keeps the existing six-package installation shape. +- The macOS arm64 Core ML provider is merged on `main` but is not included in the published `0.2.0` npm packages. The planned `0.3.0` distribution keeps the existing six-package installation shape. - Native WebGPU compatibility and performance are evidenced on the named NVIDIA/Linux and AMD/Windows systems. Other devices may use the open compatibility path but do not inherit these performance numbers. - The Linux and Windows qualification reports both passed 164/164 mechanical Gates. Their reviewed report and artifact-set hashes are bound into the production runtime lock, so ordinary `0.3.0` release staging now accepts the exact qualified payloads. diff --git a/README.md b/README.md index 90186e7..d088501 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ It is made for products where OCR should feel like a local capability: quick to > **Available on npm:** `@arcships/light-ocr@0.2.0` includes the default PP-OCRv6 Small model, prebuilt native runtimes for all Tier 1 platforms, opt-in tiled detection, and direct in-memory JPEG/PNG input for Node.js. See [Package support](#package-support). -> **`0.3.0` acceleration candidate:** macOS adds Direct Core ML; Linux x64/Vulkan and Windows x64/D3D12 add the official Native WebGPU Plugin EP. The recorded real-device results are **2.30×–2.85×** on Apple M4 Max, **5.70× aggregate P50** on NVIDIA RTX 5060 Ti, and **2.44× aggregate P50** on AMD Radeon 780M. WebGPU ships an FP32 execution profile; Apple uses its separately qualified FP16 route. These providers are not included in the published `0.2.0` packages yet. +> **`0.3.0` acceleration candidate:** macOS arm64 adds Direct Core ML; Linux x64/Vulkan and Windows x64/D3D12 add the official Native WebGPU Plugin EP. The recorded real-device results are **2.30×–2.85×** on Apple M4 Max, **5.70× aggregate P50** on NVIDIA RTX 5060 Ti, and **2.44× aggregate P50** on AMD Radeon 780M. WebGPU ships an FP32 execution profile; Apple uses its separately qualified FP16 route. macOS x64 remains on the CPU provider. ## Where light-ocr fits @@ -43,7 +43,7 @@ Cloud OCR is convenient, but it introduces uploads, network availability, recurr - **Local by default.** Recognition performs no runtime network access and does not start a child process. - **Ready for real application pipelines.** It accepts `GRAY8`, `RGB8`, `BGR8`, and `RGBA8` pixel buffers; the Node.js adapter can also decode JPEG and PNG bytes already held in memory. - **Two deliberate large-image modes.** Bounded/960 remains the fast, memory-conscious default. Opt-in tiled detection preserves more detail for small text and dense 2048-pixel documents while processing one detection tile at a time. -- **Native Apple acceleration when requested.** The `0.3.0` source candidate can route FP16 detection and recognition through Core ML without changing the public OCR result contract. +- **Native Apple acceleration when requested.** On macOS arm64, the `0.3.0` source candidate can route FP16 detection and recognition through Core ML without changing the public OCR result contract. - **Qualified Native WebGPU acceleration.** The `0.3.0` candidate packages the official WebGPU Plugin EP and its exact Linux/Vulkan or Windows/D3D12 runtime closure, with hash-verified offline staging and 164/164 real-device Gates on both recorded systems. - **A pinned, reproducible model.** The approximately 31 MB PP-OCRv6 Small bundle is integrity-checked and designed to ship with the application instead of downloading on first use. - **Consistent across supported platforms.** The same model and result contract are used on macOS, Linux, and Windows. @@ -120,7 +120,7 @@ The accelerated output also passed all 14 locked quality fixtures: 99.6484% char The formal warm performance runs peaked at 692.14 MiB RSS and the self-contained Apple model payload added 25.42 MiB. The separate same-engine 100-dense-page lifecycle run peaked at 888.11 MiB and finished 27.47 MiB below its post-warm-up baseline, showing no sustained growth in that run. First use performs offline compilation and loads recognition functions on demand: the fixed `HELLO 123` startup canary took 7.219 s on a compiled-cache miss and 1.275/1.278 s on hits; the 113-line form took 53.846 s on its first full-page miss and 12.677/12.677 s on hits. No provider, compiler, or model is downloaded at runtime. -Only that single M4 Max runner has real-device performance data. The evidence contract classifies it under the `Apple M4` device family for `deviceValidated`; this does not represent separate measurements of every M4 SKU. The candidate's compatibility policy is intentionally open and experimental on other macOS 15+ hardware: M1–M3 and later Apple Silicon can try the same ANE/GPU route, while Intel Macs use Core ML CPU+GPU. Hardware without reviewed evidence reports `deviceValidated: false`; no speedup is claimed until that family has its own data. See the [Apple acceleration design and evidence](docs/apple-device-acceleration.md) for methodology, model placement, quality thresholds, cache behavior, and lifecycle results. +Only that single M4 Max runner has real-device performance data. The evidence contract classifies it under the `Apple M4` device family for `deviceValidated`; this does not represent separate measurements of every M4 SKU. M1–M3 and later Apple Silicon can try the same ANE/GPU route and report `deviceValidated: false` without inheriting a speed claim. The `0.3.0` macOS x64 package remains CPU-only after its release smoke test failed Core ML OCR parity. See the [Apple acceleration design and evidence](docs/apple-device-acceleration.md) for methodology, model placement, quality thresholds, cache behavior, and lifecycle results. ### Native WebGPU acceleration @@ -195,7 +195,7 @@ const engine = await createEngine({ }); ``` -`cpuPartition: "allow"` works on both Apple Silicon and Intel Macs. The strict GPU-only profile is Apple-Silicon-only. Explicit providers never fall through to CPU; only Auto may advance through its descriptor-locked creation candidates. Published `0.2.0` packages remain CPU-default until the source candidate is released. +`cpuPartition: "allow"` and the strict GPU-only profile apply to the Apple provider on Apple Silicon. The `0.3.0` macOS x64 package exposes CPU only. Explicit providers never fall through to CPU; only Auto may advance through its descriptor-locked creation candidates. Published `0.2.0` packages remain CPU-default until the source candidate is released. See the [Node.js guide](bindings/node/README.md) for the full API, cancellation, queue limits, and lifecycle behavior. @@ -227,13 +227,13 @@ See [Build and release](docs/build-and-release.md) for platform prerequisites an The npm distribution installs one facade, one required model package, and the native package matching the host platform. Package contents, versioning, and release gates are documented in [npm packaging](docs/npm-packaging.md); immutable `0.2.0` hashes and validation evidence are recorded in the [release record](docs/releases/npm-0.2.0.md). -Direct Core ML acceleration is merged on `main` for the `0.3.0` candidate but is not part of the published `0.2.0` package set. Its release keeps the same six-package installation shape; no extra provider package or runtime download is planned. +Direct Core ML acceleration on macOS arm64 is merged on `main` for the `0.3.0` candidate but is not part of the published `0.2.0` package set. Its release keeps the same six-package installation shape; no extra provider package or runtime download is planned. PR #11 also carries the Linux x64 and Windows x64 Native WebGPU source candidate. Explicit WebGPU accepts `auto`/`fp32`; Auto also selects FP32. The three required CPU-partition operators are reported and bounded. Both real-device reports passed 164/164 Gates, and their immutable report/artifact hashes are now bound into the production lock for the `0.3.0` release workflow. Published `0.2.0` packages remain unchanged and CPU-only on those platforms. ## Project status -`light-ocr` is under active development. Version `0.2.0` publishes the deterministic `tiled-v1` high-resolution mode and bounded in-memory JPEG/PNG decoding in the Node.js adapter without changing the raw-pixel C++ Core boundary. The `0.3.0` source candidate adds descriptor-driven Auto selection, Direct Core ML execution on macOS, and FP32 Native WebGPU execution on Linux x64/Windows x64. +`light-ocr` is under active development. Version `0.2.0` publishes the deterministic `tiled-v1` high-resolution mode and bounded in-memory JPEG/PNG decoding in the Node.js adapter without changing the raw-pixel C++ Core boundary. The `0.3.0` source candidate adds descriptor-driven Auto selection, Direct Core ML execution on macOS arm64, and FP32 Native WebGPU execution on Linux x64/Windows x64. As a pre-1.0 project, public APIs and package layout may still evolve; the project does not currently promise a stable cross-release C++ ABI. diff --git a/README.zh-CN.md b/README.zh-CN.md index af3c145..2f78e86 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -18,7 +18,7 @@ > **npm 已可用:**`@arcships/light-ocr@0.2.0` 自带默认 PP-OCRv6 Small 模型和全部 Tier 1 平台的预编译原生运行时,并支持可选 tiled 检测与 Node.js 内存 JPEG/PNG 直接输入。详见[包支持](#包支持)。 -> **`0.3.0` 加速候选:**macOS 加入 Direct Core ML;Linux x64/Vulkan 与 Windows x64/D3D12 加入官方 Native WebGPU Plugin EP。已记录的真机结果分别为 Apple M4 Max **2.30×–2.85×**、NVIDIA RTX 5060 Ti **聚合 P50 5.70×**、AMD Radeon 780M **聚合 P50 2.44×**。WebGPU 发布 FP32 执行 profile,Apple 使用独立资格验证的 FP16 路径。这些 provider 尚未进入已发布的 `0.2.0` packages。 +> **`0.3.0` 加速候选:**macOS arm64 加入 Direct Core ML;Linux x64/Vulkan 与 Windows x64/D3D12 加入官方 Native WebGPU Plugin EP。已记录的真机结果分别为 Apple M4 Max **2.30×–2.85×**、NVIDIA RTX 5060 Ti **聚合 P50 5.70×**、AMD Radeon 780M **聚合 P50 2.44×**。WebGPU 发布 FP32 执行 profile,Apple 使用独立资格验证的 FP16 路径;macOS x64 保持 CPU provider。 ## 适合哪些场景 @@ -43,7 +43,7 @@ - **默认本地运行。**识别过程不会访问网络,也不会启动子进程。 - **适合真实应用流程。**直接接收 `GRAY8`、`RGB8`、`BGR8` 和 `RGBA8` 像素;Node.js 适配器也能解码已经在内存中的 JPEG 和 PNG。 - **两种明确的大图策略。**bounded/960 仍是速度和内存优先的默认模式;可选 tiled 检测为小字和密集的 2048 像素文档保留更多细节,并始终逐个处理 detection tile。 -- **按需启用原生 Apple 加速。**`0.3.0` 源码候选可以用 Core ML 执行 FP16 detection/recognition,同时保持公共 OCR 结果契约不变。 +- **按需启用原生 Apple 加速。**在 macOS arm64 上,`0.3.0` 源码候选可以用 Core ML 执行 FP16 detection/recognition,同时保持公共 OCR 结果契约不变。 - **已完成真机资格验证的 Native WebGPU 加速。**`0.3.0` 候选会打包官方 WebGPU Plugin EP 及其精确的 Linux/Vulkan 或 Windows/D3D12 运行时闭包,支持哈希校验的离线 staging;两台记录设备均通过 164/164 Gate。 - **模型固定且可复现。**约 31 MB 的 PP-OCRv6 Small bundle 会经过完整性验证,目标是随应用一起安装,而不是首次运行时再下载。 - **跨平台结果一致。**macOS、Linux 和 Windows 使用同一套模型与结果契约。 @@ -120,7 +120,7 @@ WebGPU 聚合值按锁定的 14-fixture corpus 计算:`CPU fixture P50 之和 正式 warm 性能测量的 peak RSS 为 692.14 MiB,自包含 Apple 模型 payload 增加 25.42 MiB。独立的同 engine 100 个密集页生命周期测试 peak RSS 为 888.11 MiB,结束时比预热后基线低 27.47 MiB,该次测试未出现持续增长。首次使用会离线编译,并按需加载 recognition functions:固定 `HELLO 123` 启动 canary 的 compiled-cache miss 为 7.219 s,hit 为 1.275/1.278 s;113 行表单的首次整页 miss 为 53.846 s,hit 为 12.677/12.677 s。运行时不会下载 provider、编译器或模型。 -真实设备性能数据只来自这一台 M4 Max。证据契约把它归入 `Apple M4` device family 并据此设置 `deviceValidated`,不代表每一种 M4 SKU 都做过独立测量。该候选对其他 macOS 15+ 硬件采取开放但实验性的兼容策略:M1–M3 和后续 Apple Silicon 可以尝试同一 ANE/GPU 路径,Intel Mac 使用 Core ML CPU+GPU。没有已审阅证据的硬件会报告 `deviceValidated: false`;取得对应设备数据前不宣称加速倍数。完整方法、模型放置、质量阈值、缓存与生命周期结果见 [Apple 加速技术方案](docs/apple-device-acceleration.md)。 +真实设备性能数据只来自这一台 M4 Max。证据契约把它归入 `Apple M4` device family 并据此设置 `deviceValidated`,不代表每一种 M4 SKU 都做过独立测量。M1–M3 和后续 Apple Silicon 可以尝试同一 ANE/GPU 路径并报告 `deviceValidated: false`,但不继承性能承诺。`0.3.0` macOS x64 package 的 Core ML OCR 未通过发布 smoke parity,因此保持 CPU-only。完整方法、模型放置、质量阈值、缓存与生命周期结果见 [Apple 加速技术方案](docs/apple-device-acceleration.md)。 ### Native WebGPU 加速 @@ -195,7 +195,7 @@ const engine = await createEngine({ }); ``` -`cpuPartition: "allow"` 同时适用于 Apple Silicon 和 Intel Mac;strict GPU-only profile 只支持 Apple Silicon。显式 provider 失败不会转入 CPU,只有 Auto 可以沿 descriptor 锁定的创建候选继续。源码候选发布前,公开的 `0.2.0` package 仍保持 CPU 默认。 +`cpuPartition: "allow"` 与 strict GPU-only profile 适用于 Apple Silicon 上的 Apple provider;`0.3.0` macOS x64 package 只暴露 CPU。显式 provider 失败不会转入 CPU,只有 Auto 可以沿 descriptor 锁定的创建候选继续。源码候选发布前,公开的 `0.2.0` package 仍保持 CPU 默认。 完整 API、取消、队列限制和生命周期行为见 [Node.js 指南](bindings/node/README.md)。 @@ -227,13 +227,13 @@ ctest --preset release npm 分发会安装一个统一入口、一个必需的模型包,以及与当前系统匹配的 native 包。包内容、版本策略和发布门槛见 [npm package 设计](docs/npm-packaging.md);`0.2.0` 的不可变哈希和验证证据见[发布记录](docs/releases/npm-0.2.0.md)。 -Direct Core ML 加速已经合并到 `main`,目标版本为 `0.3.0`,但尚未进入已发布的 `0.2.0` package set。它会继续复用现有六包安装结构,不计划新增 provider package 或运行时下载。 +macOS arm64 Direct Core ML 加速已经合并到 `main`,目标版本为 `0.3.0`,但尚未进入已发布的 `0.2.0` package set。它会继续复用现有六包安装结构,不计划新增 provider package 或运行时下载。 PR #11 同时包含 Linux x64 与 Windows x64 Native WebGPU 源码候选。显式 WebGPU 接受 `auto/fp32`,Auto 同样选择 FP32;三个必要 CPU partition 算子会被显式报告并限制范围。两份真机报告均已通过 164/164 Gate,其报告与产物的不可变哈希现已绑定进 production lock,供 `0.3.0` 发布流程使用。已发布的 `0.2.0` packages 保持不变,并在这两个平台继续仅使用 CPU。 ## 项目状态 -`light-ocr` 仍在积极开发。`0.2.0` 已发布确定性的 `tiled-v1` 大图模式,以及 Node.js 适配器中受资源限制的内存 JPEG/PNG 解码;C++ Core 的 raw-pixel 边界保持不变。`0.3.0` 源码候选加入 descriptor-driven Auto、macOS Direct Core ML,以及 Linux x64/Windows x64 FP32 Native WebGPU 执行。 +`light-ocr` 仍在积极开发。`0.2.0` 已发布确定性的 `tiled-v1` 大图模式,以及 Node.js 适配器中受资源限制的内存 JPEG/PNG 解码;C++ Core 的 raw-pixel 边界保持不变。`0.3.0` 源码候选加入 descriptor-driven Auto、macOS arm64 Direct Core ML,以及 Linux x64/Windows x64 FP32 Native WebGPU 执行。 作为 pre-1.0 项目,公共 API 和 package 布局仍可能调整;项目目前不承诺跨版本稳定的 C++ ABI。 diff --git a/bindings/node/CMakeLists.txt b/bindings/node/CMakeLists.txt index 55559ef..0ad8c40 100644 --- a/bindings/node/CMakeLists.txt +++ b/bindings/node/CMakeLists.txt @@ -99,6 +99,10 @@ else() set(_light_ocr_node_platform_arch "x86_64") set(_light_ocr_node_platform_libc "glibc") endif() +set(_light_ocr_node_has_apple_provider 0) +if(APPLE AND _light_ocr_node_platform_arch STREQUAL "arm64") + set(_light_ocr_node_has_apple_provider 1) +endif() if(LIGHT_OCR_HAS_WEBGPU) set(_light_ocr_node_runtime_flavor "webgpu") set(_light_ocr_node_runtime_version "1.24.4") @@ -127,7 +131,7 @@ target_compile_definitions(light_ocr_node PRIVATE LIGHT_OCR_NODE_WEBGPU_QUALIFICATION_ID="${LIGHT_OCR_WEBGPU_QUALIFICATION_ID}" LIGHT_OCR_NODE_QUALIFICATION_ONLY=${_light_ocr_node_qualification_only} LIGHT_OCR_NODE_RELEASED=${_light_ocr_node_released} - LIGHT_OCR_NODE_HAS_APPLE=$ + LIGHT_OCR_NODE_HAS_APPLE=${_light_ocr_node_has_apple_provider} LIGHT_OCR_NODE_HAS_WEBGPU=$) add_custom_command(TARGET light_ocr_node POST_BUILD COMMAND "${CMAKE_COMMAND}" @@ -141,7 +145,7 @@ add_custom_command(TARGET light_ocr_node POST_BUILD "-DRUNTIME_FLAVOR=${_light_ocr_node_runtime_flavor}" "-DQUALIFICATION_ONLY=${_light_ocr_node_qualification_only}" "-DWEBGPU_QUALIFICATION_ID=${LIGHT_OCR_WEBGPU_QUALIFICATION_ID}" - "-DHAS_COREML=$" + "-DHAS_COREML=${_light_ocr_node_has_apple_provider}" -P "${PROJECT_SOURCE_DIR}/cmake/StageNodeRuntime.cmake" VERBATIM) diff --git a/bindings/node/README.md b/bindings/node/README.md index d52d59a..dccb2c5 100644 --- a/bindings/node/README.md +++ b/bindings/node/README.md @@ -21,7 +21,7 @@ npm install @arcships/light-ocr - 支持 `AbortSignal` 协作式取消:queued 请求会从队列移除;running 请求立即拒绝 public Promise,但 Core 会安全运行到返回并丢弃结果。 - native addon 只接收现有绝对 bundle 目录。当前源码开发调用显式传 `bundlePath`;发布后的 facade 默认使用随 npm 安装的 model package 路径。 - 产品 engine 默认报告 `detectionStrategy: 'bounded'`、`detectionMaxSide: 960` 和 `defaultRecognitionBatchSize: 1`。0.2.0 可通过 `detection: {strategy: 'tiled'}` 显式选择 `tiled-v1`;`upstreamExact` 只用于上游对照,单次 `recognize({detectionMaxSide})` 只能继续降低 bounded engine 的 side。 -- `createEngine({execution})` 接受 `auto`、`cpu`、`apple` 与已交付平台支持的 `webgpu`。macOS 15+ 默认开放:Apple Silicon interactive 使用 FP16 ANE + 宽文本 FP16 GPU,strict 使用全 GPU;Intel Mac 使用 Core ML CPU+GPU 且只接受 `cpuPartition: 'allow'`。WebGPU 使用 ORT Core 1.24.4 + official plugin 0.1.0,Linux 为 Vulkan、Windows 为 D3D12;`0.3.0` 公共 WebGPU profile 只接受 `precision: 'auto' | 'fp32'`,FP16 仅用于 Apple provider。当前 WebGPU 模型需要 `Concat/Gather/Slice` 三类有界 CPU partition,因而 `cpuPartition: 'forbid'` 会稳定 fail-closed。只有 Auto 可在创建期按 descriptor 锁定的 typed failure 继续候选;显式 provider 不回退,旧 `sessionFallback: 'cpu'` 返回 `invalid_argument`。`engine.info.execution.sessions` 报告每个模型的实际 provider chain、precision、adapter、runtime/provider/qualification identity,selection trace 则报告 Auto 的每次创建尝试。 +- `createEngine({execution})` 接受 `auto`、`cpu`、`apple` 与已交付平台支持的 `webgpu`。macOS 15+ arm64 默认开放:Apple Silicon interactive 使用 FP16 ANE + 宽文本 FP16 GPU,strict 使用全 GPU;macOS x64 package 保持 CPU-only。WebGPU 使用 ORT Core 1.24.4 + official plugin 0.1.0,Linux 为 Vulkan、Windows 为 D3D12;`0.3.0` 公共 WebGPU profile 只接受 `precision: 'auto' | 'fp32'`,FP16 仅用于 Apple provider。当前 WebGPU 模型需要 `Concat/Gather/Slice` 三类有界 CPU partition,因而 `cpuPartition: 'forbid'` 会稳定 fail-closed。只有 Auto 可在创建期按 descriptor 锁定的 typed failure 继续候选;显式 provider 不回退,旧 `sessionFallback: 'cpu'` 返回 `invalid_argument`。`engine.info.execution.sessions` 报告每个模型的实际 provider chain、precision、adapter、runtime/provider/qualification identity,selection trace 则报告 Auto 的每次创建尝试。 ## `0.3.0` 加速证据 diff --git a/bindings/node/js/load-native.cjs b/bindings/node/js/load-native.cjs index 2aacbc6..4432101 100644 --- a/bindings/node/js/load-native.cjs +++ b/bindings/node/js/load-native.cjs @@ -340,12 +340,12 @@ function validateRuntimeDescriptor(descriptorPath) { const expectedPolicy = runtime.flavor === 'webgpu' ? ['webgpu', 'cpu'] - : actual.os === 'darwin' + : actual.id === 'macos-arm64' ? ['apple', 'cpu'] : ['cpu']; const expectedAvailable = runtime.flavor === 'webgpu' ? ['cpu', 'webgpu'] - : actual.os === 'darwin' + : actual.id === 'macos-arm64' ? ['apple', 'cpu'] : ['cpu']; const sortedAvailable = [...availableProviders].sort(); diff --git a/bindings/node/test/adapter.test.cjs b/bindings/node/test/adapter.test.cjs index 2202728..2858a14 100644 --- a/bindings/node/test/adapter.test.cjs +++ b/bindings/node/test/adapter.test.cjs @@ -125,6 +125,7 @@ test('validates runtime descriptor artifacts before native loading', () => { : process.platform === 'win32' ? 'windows-x64' : 'linux-x64'; + const appleSupported = process.platform === 'darwin' && process.arch === 'arm64'; const descriptor = { schemaVersion: '2.0', platform: { @@ -145,7 +146,7 @@ test('validates runtime descriptor artifacts before native loading', () => { autoPolicy: { id: `${platformId}-v1`, version: 1, - providers: process.platform === 'darwin' ? ['apple', 'cpu'] : ['cpu'], + providers: appleSupported ? ['apple', 'cpu'] : ['cpu'], }, providers: { cpu: { @@ -153,7 +154,7 @@ test('validates runtime descriptor artifacts before native loading', () => { qualificationId: 'cpu-baseline-v1', artifacts: [record(runtime)], }, - ...(process.platform === 'darwin' + ...(appleSupported ? { apple: { runtimeProvider: 'CoreML', diff --git a/docs/apple-device-acceleration.md b/docs/apple-device-acceleration.md index 710ffb9..a168401 100644 --- a/docs/apple-device-acceleration.md +++ b/docs/apple-device-acceleration.md @@ -1,12 +1,12 @@ # Apple Device 加速技术方案 -状态:Implemented with open macOS compatibility;M4 Max 的实现、放置、质量、性能、缓存和 100 页生命周期 Gate 已通过;其他 Mac 以实验兼容模式开放;不代表已经发布 +状态:Implemented with open Apple Silicon compatibility;M4 Max 的实现、放置、质量、性能、缓存和 100 页生命周期 Gate 已通过;其他 Apple Silicon 以实验兼容模式开放;macOS x64 npm runtime 保持 CPU-only;不代表已经发布 更新时间:2026-07-16 -范围:以 macOS 15+ 为当前交付目标;Apple Silicon 使用 ANE/GPU 混合路由,Intel Mac 使用 CPU+GPU 路由;iPhone/iPad 不在当前 Tier 1 平台承诺内 +范围:以 macOS 15+ Apple Silicon 为当前 Core ML 交付目标;macOS x64 继续作为 CPU Tier 1 平台;iPhone/iPad 不在当前 Tier 1 平台承诺内 -实施状态:Direct Objective-C++ Core ML bridge、schema 1.1 capability manifest、哈希锁 FP16 模型派生、自包含 npm 模型包、ANE/GPU 与 Intel CPU+GPU 路由、严格 GPU 模式、离线编译缓存、跨进程锁、20 个加权宽度桶的有界函数缓存、C++/Node API、资格工具和 D112 macOS Auto 外层顺序 `apple → cpu` 均已在源码实现,平台发布证据仍待完成。生产 bundle 使用 `devicePolicy: open-macos`,macOS 15+ 的 arm64/x86_64 Mac 均可尝试 Core ML;`validatedDeviceFamilies: ["Apple M4"]` 只标记已有性能证据,不再充当运行白名单。`deviceValidated` 让调用方区分 M4 实证与其他设备的实验兼容。 +实施状态:Direct Objective-C++ Core ML bridge、schema 1.1 capability manifest、哈希锁 FP16 模型派生、自包含 npm 模型包、ANE/GPU 路由、严格 GPU 模式、离线编译缓存、跨进程锁、20 个加权宽度桶的有界函数缓存、C++/Node API、资格工具和 D112 macOS arm64 Auto 外层顺序 `apple → cpu` 均已在源码实现。生产 bundle 使用 `devicePolicy: open-macos`;`validatedDeviceFamilies: ["Apple M4"]` 只标记已有性能证据,不再充当 Apple Silicon 运行白名单。macOS x64 release smoke 的 Core ML OCR 未通过 parity,因此 0.3.0 x64 runtime descriptor 使用 `cpu` 单候选。 关联 Roadmap:[Perf-0–Perf-4](roadmap.md#7-perf-0perf-4--性能与宿主加速线) @@ -166,7 +166,7 @@ W8A8 的已有 quality smoke 只使用 3 页 detector 校准图和 10 个 recogn | --- | --- | --- | --- | --- | | M4 系列 | 有;M4 具备 Apple 明确说明的 INT8×INT8 加速 | 已验证的 FP16 ANE + FP16 GPU | 质量与收益通过后,可对 ANE 子模型启用 | `deviceValidated=true`;D112 Auto 可在可跳过创建原因后尝试 CPU | | M1–M3 与后续 Apple Silicon Mac | 有 | 开放 FP16 ANE/GPU 实验兼容 | 不承诺 W8A8 加速;社区设备反馈后逐步补证据 | `deviceValidated=false`;同一 D112 Auto 规则 | -| Intel Mac | 无 | 开放 Core ML FP16 CPU+GPU 实验兼容;仅 `cpuPartition=allow` | 不适用 ANE W8A8 | `deviceValidated=false`;同一 D112 Auto 规则 | +| Intel Mac | 无 | 0.3.0 npm package 使用 CPU;Core ML CPU+GPU 保留为未交付实验路径 | 不适用 ANE W8A8 | x64 runtime descriptor 的 Auto 为 `cpu` | | A17 Pro/M4 系列及项目独立验证过的后续 iPhone/iPad | 有;A17 Pro/M4 具备 Apple 明确说明的 INT8×INT8 加速 | 架构上与 Mac 相同 | 未来平台工作,当前不发布 | 平台自有 CPU/GPU 策略 | | 更老 iPhone/iPad | 有或无,能力不同 | 当前不在项目支持矩阵 | 不承诺 | 当前不发布 | @@ -380,7 +380,7 @@ Apple provider 继承 Roadmap Provider Gate,并增加交互式 CPU 目标: ### Phase B — FP16 Apple interactive preview -状态:实现完成,M4 Max 本机全套 Gate 已通过;macOS 15+ 的其他 Apple Silicon 以同一 ANE/GPU 路径开放,Intel Mac 以 CPU+GPU 路径开放,二者均明确报告 `deviceValidated=false`。 +状态:实现完成,M4 Max 本机全套 Gate 已通过;macOS 15+ 的其他 Apple Silicon 以同一 ANE/GPU 路径开放并明确报告 `deviceValidated=false`。Intel Core ML CPU+GPU 未通过 release smoke OCR parity,0.3.0 npm x64 package 因此保持 CPU-only。 - Detector、常规 recognition 优先 FP16 ANE。 - ANE-unqualified recognition shape 使用 FP16 GPU。 @@ -413,8 +413,8 @@ Apple provider 继承 Roadmap Provider Gate,并增加交互式 CPU 目标: ## 13. 已落地决策与剩余外部证据 1. 正式 backend 候选为 Direct Core ML;ORT 1.22 CoreML EP 在禁止 CPU fallback 时不能完整放置当前 graph,保留为未来对照而非产品路径。 -2. FP16 生产 manifest 使用 `devicePolicy: open-macos` 和 `architectures: [arm64, x86_64]`。`validatedDeviceFamilies` 当前只列 M4,但仅表示性能证据;M1–M3、后续 Apple Silicon 和 Intel Mac 无需白名单即可尝试。CI 虚拟 M1 不暴露 GPU/Neural Engine,仍不能作为性能证据。W8A8 仍不发布。 -3. Detector 使用 32–960 的受限 range MLProgram;Apple Silicon interactive 使用 ANE/MLCPU envelope,strict 使用全 GPU;Intel 因无 ANE 使用 Core ML CPU+GPU,且不接受 strict `cpuPartition=forbid`。 +2. FP16 生产 manifest 保留 `devicePolicy: open-macos` 和可复现的模型架构声明;npm runtime descriptor 只在 macOS arm64 暴露 Apple provider。`validatedDeviceFamilies` 当前只列 M4,但仅表示性能证据;M1–M3 与后续 Apple Silicon 无需白名单即可尝试。CI 虚拟 M1 不暴露 GPU/Neural Engine,仍不能作为性能证据。W8A8 仍不发布。 +3. Detector 使用 32–960 的受限 range MLProgram;Apple Silicon interactive 使用 ANE/MLCPU envelope,strict 使用全 GPU。Intel CPU+GPU 路径保留在源码中,但不进入 0.3.0 npm provider policy。 4. Recognition 使用 320–3200、步长 32 的 91-function MLProgram 做全量资格审查;运行时向上取整到锁定的 20 个加权 bucket,≤1600 走 ANE envelope,>1600 走 GPU,LRU≤20。 5. 随包携带源 `.mlpackage`,首次运行离线编译并以 package/OS/device identity 缓存;不分发跨 OS 的预编译 `.mlmodelc`。 6. 质量、两 workload speedup、CPU-time 降幅、canary 的 3 次 cold start、30 次 warm、RSS、同 engine 100 页生命周期和 32 MiB 包增量阈值由 `tools/apple/acceptance.json` 锁定。 diff --git a/docs/implementation-status.md b/docs/implementation-status.md index 7172565..326e094 100644 --- a/docs/implementation-status.md +++ b/docs/implementation-status.md @@ -25,7 +25,7 @@ | 无 network/shell/cwd/locale 运行依赖 | Done | sterile cwd/minimal env 与 Linux network namespace disabled 测试通过;npm release 另完成已安装 package 的禁网运行。 | | manifest、hash、licenses、SBOM、parity、benchmark | Done | Release commit 已重新生成并保存四平台 metadata、六个 npm tarballs 的 hashes/integrity、parity、quality 与 benchmark 证据。 | | N-API/npm 非本 Core milestone | Done / `0.2.0` published | raw Node-API v8、CJS/ESM、`.d.ts`、内置模型解析、四平台 prebuild、双重背压、AbortSignal 与生命周期均已完成;[npm release run 29340467784](https://github.com/arcships/light-ocr/actions/runs/29340467784) 与 [promotion run 29342178842](https://github.com/arcships/light-ocr/actions/runs/29342178842) 保存六包发布、registry 和禁网证据。 | -| Perf-1A / Apple execution | Done locally / open macOS | provider-neutral `InferenceSession` 已加入 Objective-C++ Direct Core ML;公开 union 与 D112 Auto 创建状态机已接线。detector 使用 FP16 range model,recognizer 使用 91-function FP16 MLProgram 和 20 个加权宽度桶;Apple Silicon interactive 为 ANE + 宽文本 GPU,strict 为 GPU,Intel 为 CPU+GPU。schema 1.1 provider contract 使用 `open-macos`、arm64/x86_64、`validatedDeviceFamilies` 和 `deviceValidated`;显式 provider 严格失败,只有 Auto 可按 typed reason 在创建期继续。哈希锁模型、离线编译缓存、跨进程锁、LRU≤20 与 Node 映射均已完成。M4 有正式证据,其他 Mac 直接开放实验兼容。 | +| Perf-1A / Apple execution | Done locally / Apple Silicon open compatibility | provider-neutral `InferenceSession` 已加入 Objective-C++ Direct Core ML;公开 union 与 D112 Auto 创建状态机已接线。detector 使用 FP16 range model,recognizer 使用 91-function FP16 MLProgram 和 20 个加权宽度桶;Apple Silicon interactive 为 ANE + 宽文本 GPU,strict 为 GPU。schema 1.1 provider contract、`validatedDeviceFamilies` 与 `deviceValidated` 已实现;显式 provider 严格失败,只有 Auto 可按 typed reason 在创建期继续。哈希锁模型、离线编译缓存、跨进程锁、LRU≤20 与 Node 映射均已完成。M4 有正式证据,其他 Apple Silicon 开放实验兼容;macOS x64 release smoke 未通过 Core ML OCR parity,因此 0.3.0 x64 runtime descriptor 只暴露 CPU。 | | Perf-2 / Native WebGPU | Production-qualified / two device Gates passed | Linux x64 glibc/Vulkan 与 Windows x64/D3D12 使用 official ORT Core 1.24.4 + WebGPU Plugin EP 0.1.0。NuGet bytes/SHA-512、headers、runtime/plugin/companions、license 和 session options 已锁定;assembler 支持在线取得、离线复装和 exact SDK 校验。C++/Node plugin registration、D112 `webgpu → cpu`、typed/fatal failure、FP32 allow/strict、真实 provider chain、profiling、schema 2 descriptor、sterile loader、self-contained npm staging、license/SBOM 和双平台 CI 已实现。Linux RTX 5060 Ti/Vulkan 与 Windows Radeon 780M/D3D12 报告均为 164/164 Gate 通过、14/14 FP32 字节级质量对齐;聚合 P50 分别加速 5.698× 与 2.436×。已审阅 report/artifact hashes 已绑定 production lock,release configure 仅接受精确匹配的 SDK。 | | Node.js JPEG/PNG 内存输入 | Done / `0.2.0` published | `recognizeEncoded(Uint8Array)` 在 engine worker 上使用固定 stb revision 解码,保持 Core raw-pixel 边界;格式、尺寸、pixels、临时内存、queue/snapshot budget、AbortSignal 与 `timingUs.decode` 均有四平台 Node 22/24 package 测试。 | | 高分辨率峰值内存 | Done | Release 原生独立进程本机参考:2048² 空白 `318.8 MiB ≤ 384 MiB`;xfund 密集表单 116 框 `400.5 MiB ≤ 640 MiB`。四平台 release jobs 的真实模型与 RSS gates 均通过。 | diff --git a/docs/npm-packaging.md b/docs/npm-packaging.md index 14221a3..e5511cc 100644 --- a/docs/npm-packaging.md +++ b/docs/npm-packaging.md @@ -12,7 +12,7 @@ Decision:[decisions.md](decisions.md) D105 0.3.0 候选不增加第七个包或第二个安装入口。model package 改为 `ppocrv6-small-native-20260719.1` 自包含 superset:所有平台继续使用其中的 ONNX FP32 CPU/WebGPU payload;锁定的 WebGPU FP16 variants 仅作为内部可复现工件保留; -macOS 15+ arm64/x86_64 使用 `open-macos` 策略,均可显式请求 Core ML。`validatedDeviceFamilies` 只标记已有真机证据,不阻塞其他 Mac 的实验兼容。 +macOS 15+ arm64 使用 `open-macos` 策略并可显式请求 Core ML;`validatedDeviceFamilies` 只标记已有真机证据,不阻塞其他 Apple Silicon 的实验兼容。macOS x64 package 保持 CPU-only,因为发布 smoke 未能通过 Intel Core ML OCR parity。 release workflow 在 Linux 复现内部 WebGPU FP16 ONNX 工件、在 macOS 以哈希锁 Python 3.12 工具链派生固定 Core ML 工件,Linux assemble job 只消费这些已验证 artifacts;公共 WebGPU 只使用 FP32,运行时和 postinstall 都不转换或下载模型。 ## 1. 用户契约 diff --git a/tests/python/test_npm_release.py b/tests/python/test_npm_release.py index b5000ec..808596d 100644 --- a/tests/python/test_npm_release.py +++ b/tests/python/test_npm_release.py @@ -138,10 +138,16 @@ def test_stages_and_deterministically_packs_six_packages(self) -> None: native_root / platform_id / "native" / "runtime-descriptor.json" ).read_text("utf-8") ) + expected = ( + ["apple", "cpu"] + if platform_id == "macos-arm64" + else ["cpu"] + ) + self.assertEqual(descriptor["autoPolicy"]["providers"], expected) self.assertEqual( - descriptor["autoPolicy"]["providers"], ["apple", "cpu"] + set(descriptor["providers"]), + {"apple", "cpu"} if platform_id == "macos-arm64" else {"cpu"}, ) - self.assertIn("apple", descriptor["providers"]) bundle = root / "bundle" bundle.mkdir() diff --git a/tools/npm/smoke.cjs b/tools/npm/smoke.cjs index 02fe289..44ca70f 100644 --- a/tools/npm/smoke.cjs +++ b/tools/npm/smoke.cjs @@ -14,6 +14,7 @@ async function main() { const cjs = require('@arcships/light-ocr'); const esm = await import('@arcships/light-ocr'); + const appleSupported = process.platform === 'darwin' && process.arch === 'arm64'; assert.strictEqual(esm.createEngine, cjs.createEngine); assert.strictEqual(esm.OcrError, cjs.OcrError); @@ -23,7 +24,7 @@ async function main() { assert.equal(engine.info.detectionStrategy, 'bounded'); assert.equal(engine.info.detectionMaxSide, 960); assert.equal(engine.info.defaultRecognitionBatchSize, 1); - if (process.platform === 'darwin') { + if (appleSupported) { assert.deepEqual( engine.info.execution.selectionTrace.orderedCandidates, ['apple', 'cpu'], @@ -32,6 +33,15 @@ async function main() { (capability) => capability.provider === 'apple' && capability.packageIncluded, )); + } else if (process.platform === 'darwin') { + assert.deepEqual( + engine.info.execution.selectionTrace.orderedCandidates, + ['cpu'], + ); + assert.equal( + engine.info.execution.selectionTrace.selectedProvider, + 'cpu', + ); } else { assert.deepEqual( engine.info.execution.selectionTrace.orderedCandidates, @@ -57,7 +67,7 @@ async function main() { await engine.close(); } - if (process.platform === 'darwin') { + if (appleSupported) { const apple = await cjs.createEngine({ execution: { provider: 'apple', diff --git a/tools/npm_release.py b/tools/npm_release.py index 2ba6960..088225e 100644 --- a/tools/npm_release.py +++ b/tools/npm_release.py @@ -380,14 +380,14 @@ def validate_runtime_descriptor( ["webgpu", "cpu"] if runtime["flavor"] == "webgpu" else ["apple", "cpu"] - if str(platform.get("id", "")).startswith("macos-") + if platform.get("id") == "macos-arm64" else ["cpu"] ) expected_available = ( {"cpu", "webgpu"} if runtime["flavor"] == "webgpu" else {"apple", "cpu"} - if str(platform.get("id", "")).startswith("macos-") + if platform.get("id") == "macos-arm64" else {"cpu"} ) if providers != expected_policy or set(provider_records) != expected_available: @@ -522,7 +522,7 @@ def stage_native(arguments: argparse.Namespace) -> None: "artifacts": [runtime_record], } } - if platform["os"] == ["darwin"]: + if arguments.platform_id == "macos-arm64": provider_entries["apple"] = { "runtimeProvider": "CoreML", "qualificationId": "apple-open-macos-v1", @@ -613,7 +613,11 @@ def stage_native(arguments: argparse.Namespace) -> None: "providers": ( ["webgpu", "cpu"] if runtime_flavor == "webgpu" - else (["apple", "cpu"] if platform["os"] == ["darwin"] else ["cpu"]) + else ( + ["apple", "cpu"] + if arguments.platform_id == "macos-arm64" + else ["cpu"] + ) ), }, "providers": provider_entries,