Fix SM8650 VAE decoder with validated FP16 context
Browse filesReplace the collapsed W8A16 QNN VAE decoder with the directly compiled FP16 context. Device validation against the raw ONNX decoder reached 59.77 dB PSNR.
README.md
CHANGED
|
@@ -39,7 +39,7 @@ splitting the network into smaller graphs suitable for mobile integration.
|
|
| 39 |
| Batch size | 1 |
|
| 40 |
| Activations | FP16 (A16) |
|
| 41 |
| DiT block weights | INT4 (W4A16) |
|
| 42 |
-
| Auxiliary/final graph weights | INT8 (W8A16) |
|
| 43 |
| Total DLC size | 1,736,469,708 bytes / 1.617 GiB |
|
| 44 |
|
| 45 |
## Files
|
|
@@ -56,11 +56,33 @@ The graphs must be executed in the order shown below.
|
|
| 56 |
| 6 | `vosr_dit_blocks_18_24.dlc` | W4A16 | 222.62 MiB |
|
| 57 |
| 7 | `vosr_dit_blocks_24_36.dlc` | W4A16 | 444.86 MiB |
|
| 58 |
| 8 | `vosr_dit_final.dlc` | W8A16 | 4.90 MiB |
|
| 59 |
-
| 9 | `vosr_qwen_vae_decoder.dlc` | W8A16 | 24.97 MiB |
|
| 60 |
|
| 61 |
`manifest.json` contains the same graph order, precision assignment, and exact
|
| 62 |
byte size for programmatic use.
|
| 63 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 64 |
## Tensor interface
|
| 65 |
|
| 66 |
All image and latent tensors use NCHW layout.
|
|
@@ -89,8 +111,9 @@ noise generation, the one-step latent update, tiling, and image postprocessing.
|
|
| 89 |
`lq_latent` and `z` along the channel axis, and use the result as `latent_pair`.
|
| 90 |
4. For the one-step schedule, run DiT prepare with `timestep = [1.0]` and
|
| 91 |
`next_timestep = [0.0]`.
|
| 92 |
-
5. Pass `hidden` sequentially through all four DiT block-stage DLCs
|
| 93 |
-
|
|
|
|
| 94 |
6. Run DiT final and apply the one-step update `z = z - velocity`.
|
| 95 |
7. Decode the updated latent with the Qwen VAE decoder, clamp the output to
|
| 96 |
`[-1, 1]`, convert it back to RGB, and blend overlapping tiles when tiling.
|
|
@@ -101,13 +124,23 @@ resolution.
|
|
| 101 |
|
| 102 |
## Validation status
|
| 103 |
|
| 104 |
-
-
|
| 105 |
-
|
|
|
|
| 106 |
- The Qwen VAE encoder and DiT prepare graphs were profiled on the Snapdragon 8
|
| 107 |
Gen 3 NPU.
|
| 108 |
-
-
|
| 109 |
-
|
| 110 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 111 |
|
| 112 |
Performance, memory use, and image quality depend on the QNN SDK version, device
|
| 113 |
firmware, thermal state, tiling implementation, and host-side orchestration. Test on
|
|
|
|
| 39 |
| Batch size | 1 |
|
| 40 |
| Activations | FP16 (A16) |
|
| 41 |
| DiT block weights | INT4 (W4A16) |
|
| 42 |
+
| Auxiliary/final graph weights | INT8 (W8A16), except the FP16 VAE decoder |
|
| 43 |
| Total DLC size | 1,736,469,708 bytes / 1.617 GiB |
|
| 44 |
|
| 45 |
## Files
|
|
|
|
| 56 |
| 6 | `vosr_dit_blocks_18_24.dlc` | W4A16 | 222.62 MiB |
|
| 57 |
| 7 | `vosr_dit_blocks_24_36.dlc` | W4A16 | 444.86 MiB |
|
| 58 |
| 8 | `vosr_dit_final.dlc` | W8A16 | 4.90 MiB |
|
| 59 |
+
| 9 | `vosr_qwen_vae_decoder.dlc` | Legacy W8A16 DLC; EPContext uses FP16 | 24.97 MiB |
|
| 60 |
|
| 61 |
`manifest.json` contains the same graph order, precision assignment, and exact
|
| 62 |
byte size for programmatic use.
|
| 63 |
|
| 64 |
+
### Ready-to-run SM8650 EPContext package
|
| 65 |
+
|
| 66 |
+
`sd8g3/qnn-context/` contains eleven pre-linked QNN context binaries for the
|
| 67 |
+
Snapdragon 8 Gen 3 HTP. They were linked with QAIRT `2.45.0.260326154327`,
|
| 68 |
+
target DSP v75 / SoC model 57, and use O1 graph finalization to stay inside the
|
| 69 |
+
device's 8 MiB VTCM budget.
|
| 70 |
+
|
| 71 |
+
The DiT is split into six contiguous stages: `00_06`, `06_12`, `12_18`,
|
| 72 |
+
`18_24`, `24_30`, and `30_36`. RMSNorm pointwise multiplications are divided
|
| 73 |
+
along the token axis before linking; a CPU reference comparison against the
|
| 74 |
+
unmodified QDQ block measured 72.9 dB PSNR.
|
| 75 |
+
|
| 76 |
+
The complete context package is 1,140,031,488 bytes (1.062 GiB). The small
|
| 77 |
+
EPContext ONNX wrappers and their exact SHA-256, byte-size, tensor, graph-order,
|
| 78 |
+
and immutable Hub-revision contracts are stored in
|
| 79 |
+
`sd8g3/vosr_runtime_manifest.json`.
|
| 80 |
+
|
| 81 |
+
The Qwen VAE decoder is compiled directly from the original FP16 ONNX graph.
|
| 82 |
+
The earlier W8A16 QDQ decoder removed nearly all spatial detail. The FP16
|
| 83 |
+
SM8650 context matches the CPU ONNX decoder at 59.77 dB PSNR with a maximum
|
| 84 |
+
per-channel error of one RGB level.
|
| 85 |
+
|
| 86 |
## Tensor interface
|
| 87 |
|
| 88 |
All image and latent tensors use NCHW layout.
|
|
|
|
| 111 |
`lq_latent` and `z` along the channel axis, and use the result as `latent_pair`.
|
| 112 |
4. For the one-step schedule, run DiT prepare with `timestep = [1.0]` and
|
| 113 |
`next_timestep = [0.0]`.
|
| 114 |
+
5. Pass `hidden` sequentially through all four DiT block-stage DLCs, or through
|
| 115 |
+
all six `sd8g3/qnn-context` DiT stages when using the EPContext package.
|
| 116 |
+
Reuse `block_conditioning` and `projected_dino` for every stage.
|
| 117 |
6. Run DiT final and apply the one-step update `z = z - velocity`.
|
| 118 |
7. Decode the updated latent with the Qwen VAE decoder, clamp the output to
|
| 119 |
`[-1, 1]`, convert it back to RGB, and blend overlapping tiles when tiling.
|
|
|
|
| 124 |
|
| 125 |
## Validation status
|
| 126 |
|
| 127 |
+
- The DINO, VAE encoder, DiT prepare/final, and DiT blocks use their documented
|
| 128 |
+
mobile quantization. The VAE decoder deliberately remains FP16.
|
| 129 |
+
- All runtime graphs were successfully compiled and linked for SM8650.
|
| 130 |
- The Qwen VAE encoder and DiT prepare graphs were profiled on the Snapdragon 8
|
| 131 |
Gen 3 NPU.
|
| 132 |
+
- All eleven split EPContext graphs were linked and inspected as DSP v75 / SoC
|
| 133 |
+
model 57 contexts. The runtime disables CPU execution-provider fallback.
|
| 134 |
+
- The complete on-device chain preserves generated detail: on the S24 Ultra
|
| 135 |
+
regression patch, edge energy rose from 1.54 for the bicubic input to 15.19
|
| 136 |
+
after VOSR.
|
| 137 |
+
- The `00_06` six-block context was profiled successfully on the Galaxy S24
|
| 138 |
+
target: 382.9 ms estimated warm inference, 230.9 ms warm load, and 119.5 MB
|
| 139 |
+
estimated peak memory. Every reported operator, including the VTCM chunks,
|
| 140 |
+
executed on the NPU.
|
| 141 |
+
- A monolithic context is intentionally not included. Splitting the DiT into six
|
| 142 |
+
VTCM-safe contexts avoids the cloud linker's memory explosion and allows the
|
| 143 |
+
application to release each session before opening the next one.
|
| 144 |
|
| 145 |
Performance, memory use, and image quality depend on the QNN SDK version, device
|
| 146 |
firmware, thermal state, tiling implementation, and host-side orchestration. Test on
|
sd8g3/qnn-context/vosr_qwen_vae_decoder.bin
CHANGED
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
-
size
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:a3e0b355634a2f41fc6f830141671c5da158f36c7e68070790431419fa71b002
|
| 3 |
+
size 53456896
|
sd8g3/qnn-context/vosr_qwen_vae_decoder.json
CHANGED
|
@@ -20,7 +20,7 @@
|
|
| 20 |
"backendApiVersion": "5.45.0",
|
| 21 |
"socVersion": "",
|
| 22 |
"contextBlobVersion": "3.3.4",
|
| 23 |
-
"contextBlobSize":
|
| 24 |
"numContextTensors": 0,
|
| 25 |
"contextTensors": [],
|
| 26 |
"numGraphs": 1,
|
|
@@ -59,7 +59,7 @@
|
|
| 59 |
{
|
| 60 |
"version": "QNN_TENSOR_VERSION_2",
|
| 61 |
"info": {
|
| 62 |
-
"id":
|
| 63 |
"name": "output_0",
|
| 64 |
"type": "QNN_TENSOR_TYPE_APP_READ",
|
| 65 |
"dataFormat": "QNN_TENSOR_DATA_FORMAT_FLAT_BUFFER",
|
|
@@ -85,8 +85,8 @@
|
|
| 85 |
"graphBlobInfo": {
|
| 86 |
"version": "QNN_SYSTEM_CONTEXT_HTP_GRAPH_INFO_BLOB_VERSION_V1",
|
| 87 |
"info": {
|
| 88 |
-
"spillFillBufferSize":
|
| 89 |
-
"optimizationLevel":
|
| 90 |
"vtcmSize": 8,
|
| 91 |
"htpDlbc": 0,
|
| 92 |
"numHvxThreads": 0
|
|
@@ -98,13 +98,13 @@
|
|
| 98 |
"nativeVChannelSize": 64,
|
| 99 |
"isSafeShareIO": 0,
|
| 100 |
"ioTensorSize": 1703936,
|
| 101 |
-
"opDataSize":
|
| 102 |
-
"constSize":
|
| 103 |
-
"ddrTensorSize":
|
| 104 |
"sharedWeightsSize": 0
|
| 105 |
},
|
| 106 |
-
"startOpIndex":
|
| 107 |
-
"endOpIndex":
|
| 108 |
}
|
| 109 |
}
|
| 110 |
],
|
|
|
|
| 20 |
"backendApiVersion": "5.45.0",
|
| 21 |
"socVersion": "",
|
| 22 |
"contextBlobVersion": "3.3.4",
|
| 23 |
+
"contextBlobSize": 53452800,
|
| 24 |
"numContextTensors": 0,
|
| 25 |
"contextTensors": [],
|
| 26 |
"numGraphs": 1,
|
|
|
|
| 59 |
{
|
| 60 |
"version": "QNN_TENSOR_VERSION_2",
|
| 61 |
"info": {
|
| 62 |
+
"id": 452,
|
| 63 |
"name": "output_0",
|
| 64 |
"type": "QNN_TENSOR_TYPE_APP_READ",
|
| 65 |
"dataFormat": "QNN_TENSOR_DATA_FORMAT_FLAT_BUFFER",
|
|
|
|
| 85 |
"graphBlobInfo": {
|
| 86 |
"version": "QNN_SYSTEM_CONTEXT_HTP_GRAPH_INFO_BLOB_VERSION_V1",
|
| 87 |
"info": {
|
| 88 |
+
"spillFillBufferSize": 133758976,
|
| 89 |
+
"optimizationLevel": 1,
|
| 90 |
"vtcmSize": 8,
|
| 91 |
"htpDlbc": 0,
|
| 92 |
"numHvxThreads": 0
|
|
|
|
| 98 |
"nativeVChannelSize": 64,
|
| 99 |
"isSafeShareIO": 0,
|
| 100 |
"ioTensorSize": 1703936,
|
| 101 |
+
"opDataSize": 9052416,
|
| 102 |
+
"constSize": 51228672,
|
| 103 |
+
"ddrTensorSize": 23593472,
|
| 104 |
"sharedWeightsSize": 0
|
| 105 |
},
|
| 106 |
+
"startOpIndex": 0,
|
| 107 |
+
"endOpIndex": 0
|
| 108 |
}
|
| 109 |
}
|
| 110 |
],
|