hip-quant 2.2.0__tar.gz → 2.2.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (182) hide show
  1. {hip_quant-2.2.0/hip_quant.egg-info → hip_quant-2.2.1}/PKG-INFO +151 -26
  2. {hip_quant-2.2.0 → hip_quant-2.2.1}/README.md +148 -25
  3. {hip_quant-2.2.0 → hip_quant-2.2.1}/_C.cp312-win_amd64.pyd +0 -0
  4. {hip_quant-2.2.0 → hip_quant-2.2.1}/__init__.py +19 -2
  5. {hip_quant-2.2.0 → hip_quant-2.2.1}/build.ps1 +40 -29
  6. {hip_quant-2.2.0 → hip_quant-2.2.1}/device_info.py +6 -0
  7. {hip_quant-2.2.0 → hip_quant-2.2.1}/gguf.py +14 -2
  8. {hip_quant-2.2.0 → hip_quant-2.2.1}/gguf_loader.py +10 -2
  9. {hip_quant-2.2.0 → hip_quant-2.2.1/hip_quant.egg-info}/PKG-INFO +151 -26
  10. {hip_quant-2.2.0 → hip_quant-2.2.1}/hip_quant.egg-info/SOURCES.txt +4 -0
  11. hip_quant-2.2.1/hip_quant.egg-info/requires.txt +7 -0
  12. {hip_quant-2.2.0 → hip_quant-2.2.1}/hip_quantize.cpp +1 -1
  13. {hip_quant-2.2.0 → hip_quant-2.2.1}/hip_quantize.dll +0 -0
  14. {hip_quant-2.2.0 → hip_quant-2.2.1}/hip_quantize_rocm721.dll +0 -0
  15. {hip_quant-2.2.0 → hip_quant-2.2.1}/hq2/archive.py +2 -0
  16. {hip_quant-2.2.0 → hip_quant-2.2.1}/hq2/format.py +4 -1
  17. {hip_quant-2.2.0 → hip_quant-2.2.1}/hq2/hq3.py +2 -1
  18. {hip_quant-2.2.0 → hip_quant-2.2.1}/hq2/hq8.py +2 -1
  19. {hip_quant-2.2.0 → hip_quant-2.2.1}/hq2/safetensors_numpy.py +4 -3
  20. {hip_quant-2.2.0 → hip_quant-2.2.1}/pyproject.toml +9 -1
  21. {hip_quant-2.2.0 → hip_quant-2.2.1}/setup.py +25 -0
  22. {hip_quant-2.2.0 → hip_quant-2.2.1}/smi.py +32 -24
  23. hip_quant-2.2.1/tools/.gpu-smi-version +1 -0
  24. hip_quant-2.2.1/tools/fetch_gpu_smi.py +156 -0
  25. hip_quant-2.2.1/tools/gpu-smi.exe +0 -0
  26. {hip_quant-2.2.0 → hip_quant-2.2.1}/torch_api.py +27 -7
  27. {hip_quant-2.2.0 → hip_quant-2.2.1}/torch_ext/fp8_linear_kernels.hip +33 -33
  28. {hip_quant-2.2.0 → hip_quant-2.2.1}/torch_ext/gemv_q_kernels.hip +12 -6
  29. {hip_quant-2.2.0 → hip_quant-2.2.1}/torch_ext/mxfp4_to_fp8_kernels.hip +14 -11
  30. {hip_quant-2.2.0 → hip_quant-2.2.1}/torch_ext/pytorch_bindings.cpp +22 -4
  31. {hip_quant-2.2.0 → hip_quant-2.2.1}/torch_ext/wave_attn.hip +10 -1
  32. {hip_quant-2.2.0 → hip_quant-2.2.1}/torch_ext/wave_attn_long.hip +6 -1
  33. hip_quant-2.2.0/hip_quant.egg-info/requires.txt +0 -4
  34. hip_quant-2.2.0/tools/gpu-smi.exe +0 -0
  35. {hip_quant-2.2.0 → hip_quant-2.2.1}/DOCUMENTATION.md +0 -0
  36. {hip_quant-2.2.0 → hip_quant-2.2.1}/LICENSE +0 -0
  37. {hip_quant-2.2.0 → hip_quant-2.2.1}/MANIFEST.in +0 -0
  38. {hip_quant-2.2.0 → hip_quant-2.2.1}/__main__.py +0 -0
  39. {hip_quant-2.2.0 → hip_quant-2.2.1}/bench_mxfp8.py +0 -0
  40. {hip_quant-2.2.0 → hip_quant-2.2.1}/bench_wave_attn_inference.py +0 -0
  41. {hip_quant-2.2.0 → hip_quant-2.2.1}/build.sh +0 -0
  42. {hip_quant-2.2.0 → hip_quant-2.2.1}/cdna_compat.py +0 -0
  43. {hip_quant-2.2.0 → hip_quant-2.2.1}/codebooks/iq1_s.bin +0 -0
  44. {hip_quant-2.2.0 → hip_quant-2.2.1}/codebooks/iq2_xs.bin +0 -0
  45. {hip_quant-2.2.0 → hip_quant-2.2.1}/codebooks/iq2_xxs.bin +0 -0
  46. {hip_quant-2.2.0 → hip_quant-2.2.1}/codebooks/iq3_s.bin +0 -0
  47. {hip_quant-2.2.0 → hip_quant-2.2.1}/codebooks/iq3_xxs.bin +0 -0
  48. {hip_quant-2.2.0 → hip_quant-2.2.1}/demo.py +0 -0
  49. {hip_quant-2.2.0 → hip_quant-2.2.1}/diagnose_fp8_crash.py +0 -0
  50. {hip_quant-2.2.0 → hip_quant-2.2.1}/e2e_iq2s_iq1m.py +0 -0
  51. {hip_quant-2.2.0 → hip_quant-2.2.1}/get_hf_tensors.py +0 -0
  52. {hip_quant-2.2.0 → hip_quant-2.2.1}/hip_iquant_util.h +0 -0
  53. {hip_quant-2.2.0 → hip_quant-2.2.1}/hip_quant.egg-info/dependency_links.txt +0 -0
  54. {hip_quant-2.2.0 → hip_quant-2.2.1}/hip_quant.egg-info/entry_points.txt +0 -0
  55. {hip_quant-2.2.0 → hip_quant-2.2.1}/hip_quant.egg-info/not-zip-safe +0 -0
  56. {hip_quant-2.2.0 → hip_quant-2.2.1}/hip_quant.egg-info/top_level.txt +0 -0
  57. {hip_quant-2.2.0 → hip_quant-2.2.1}/hip_quant_types.h +0 -0
  58. {hip_quant-2.2.0 → hip_quant-2.2.1}/hip_quant_util.h +0 -0
  59. {hip_quant-2.2.0 → hip_quant-2.2.1}/hq2/__init__.py +0 -0
  60. {hip_quant-2.2.0 → hip_quant-2.2.1}/hq2/__main__.py +0 -0
  61. {hip_quant-2.2.0 → hip_quant-2.2.1}/hq2/analyzer.py +0 -0
  62. {hip_quant-2.2.0 → hip_quant-2.2.1}/hq2/api.py +0 -0
  63. {hip_quant-2.2.0 → hip_quant-2.2.1}/hq2/backends.py +0 -0
  64. {hip_quant-2.2.0 → hip_quant-2.2.1}/hq2/mixed_policy.py +0 -0
  65. {hip_quant-2.2.0 → hip_quant-2.2.1}/hq2/raw.py +0 -0
  66. {hip_quant-2.2.0 → hip_quant-2.2.1}/hq2/sensitivity.py +0 -0
  67. {hip_quant-2.2.0 → hip_quant-2.2.1}/hq2/torch_inference.py +0 -0
  68. {hip_quant-2.2.0 → hip_quant-2.2.1}/hq2/transformers_loader.py +0 -0
  69. {hip_quant-2.2.0 → hip_quant-2.2.1}/kernels/dequant_to_fp8.cu +0 -0
  70. {hip_quant-2.2.0 → hip_quant-2.2.1}/kernels/direct_fp8_quant.cu +0 -0
  71. {hip_quant-2.2.0 → hip_quant-2.2.1}/kernels/fp8_expand.cu +0 -0
  72. {hip_quant-2.2.0 → hip_quant-2.2.1}/kernels/fp8_gemm_test.cu +0 -0
  73. {hip_quant-2.2.0 → hip_quant-2.2.1}/kernels/quant_aq2.cu +0 -0
  74. {hip_quant-2.2.0 → hip_quant-2.2.1}/kernels/quant_bf16.cu +0 -0
  75. {hip_quant-2.2.0 → hip_quant-2.2.1}/kernels/quant_f8_e4m3.cu +0 -0
  76. {hip_quant-2.2.0 → hip_quant-2.2.1}/kernels/quant_f8_e5m2.cu +0 -0
  77. {hip_quant-2.2.0 → hip_quant-2.2.1}/kernels/quant_hq2.cu +0 -0
  78. {hip_quant-2.2.0 → hip_quant-2.2.1}/kernels/quant_iq1_m.cu +0 -0
  79. {hip_quant-2.2.0 → hip_quant-2.2.1}/kernels/quant_iq1_s.cu +0 -0
  80. {hip_quant-2.2.0 → hip_quant-2.2.1}/kernels/quant_iq2_s.cu +0 -0
  81. {hip_quant-2.2.0 → hip_quant-2.2.1}/kernels/quant_iq2_xs.cu +0 -0
  82. {hip_quant-2.2.0 → hip_quant-2.2.1}/kernels/quant_iq2_xxs.cu +0 -0
  83. {hip_quant-2.2.0 → hip_quant-2.2.1}/kernels/quant_iq3_s.cu +0 -0
  84. {hip_quant-2.2.0 → hip_quant-2.2.1}/kernels/quant_iq3_xxs.cu +0 -0
  85. {hip_quant-2.2.0 → hip_quant-2.2.1}/kernels/quant_iq4_nl.cu +0 -0
  86. {hip_quant-2.2.0 → hip_quant-2.2.1}/kernels/quant_iq4_xs.cu +0 -0
  87. {hip_quant-2.2.0 → hip_quant-2.2.1}/kernels/quant_q1_0.cu +0 -0
  88. {hip_quant-2.2.0 → hip_quant-2.2.1}/kernels/quant_q2_0.cu +0 -0
  89. {hip_quant-2.2.0 → hip_quant-2.2.1}/kernels/quant_q2_K.cu +0 -0
  90. {hip_quant-2.2.0 → hip_quant-2.2.1}/kernels/quant_q3_K.cu +0 -0
  91. {hip_quant-2.2.0 → hip_quant-2.2.1}/kernels/quant_q4_0.cu +0 -0
  92. {hip_quant-2.2.0 → hip_quant-2.2.1}/kernels/quant_q4_1.cu +0 -0
  93. {hip_quant-2.2.0 → hip_quant-2.2.1}/kernels/quant_q4_K.cu +0 -0
  94. {hip_quant-2.2.0 → hip_quant-2.2.1}/kernels/quant_q5_0.cu +0 -0
  95. {hip_quant-2.2.0 → hip_quant-2.2.1}/kernels/quant_q5_1.cu +0 -0
  96. {hip_quant-2.2.0 → hip_quant-2.2.1}/kernels/quant_q5_K.cu +0 -0
  97. {hip_quant-2.2.0 → hip_quant-2.2.1}/kernels/quant_q6_K.cu +0 -0
  98. {hip_quant-2.2.0 → hip_quant-2.2.1}/kernels/quant_q8_0.cu +0 -0
  99. {hip_quant-2.2.0 → hip_quant-2.2.1}/kernels/quant_q8_1.cu +0 -0
  100. {hip_quant-2.2.0 → hip_quant-2.2.1}/kernels/quant_q8_K.cu +0 -0
  101. {hip_quant-2.2.0 → hip_quant-2.2.1}/kernels/quant_tq1_0.cu +0 -0
  102. {hip_quant-2.2.0 → hip_quant-2.2.1}/kernels/quant_tq2_0.cu +0 -0
  103. {hip_quant-2.2.0 → hip_quant-2.2.1}/kernels/wmma_diag.cu +0 -0
  104. {hip_quant-2.2.0 → hip_quant-2.2.1}/setup.cfg +0 -0
  105. {hip_quant-2.2.0 → hip_quant-2.2.1}/setup_torch.py +0 -0
  106. {hip_quant-2.2.0 → hip_quant-2.2.1}/tests/__init__.py +0 -0
  107. {hip_quant-2.2.0 → hip_quant-2.2.1}/tests/bench_attn_compare.py +0 -0
  108. {hip_quant-2.2.0 → hip_quant-2.2.1}/tests/bench_iq2s_variants.py +0 -0
  109. {hip_quant-2.2.0 → hip_quant-2.2.1}/tests/bench_wave_prefill.py +0 -0
  110. {hip_quant-2.2.0 → hip_quant-2.2.1}/tests/debug_conv1d.py +0 -0
  111. {hip_quant-2.2.0 → hip_quant-2.2.1}/tests/test_aq2.py +0 -0
  112. {hip_quant-2.2.0 → hip_quant-2.2.1}/tests/test_bf16_numpy.py +0 -0
  113. {hip_quant-2.2.0 → hip_quant-2.2.1}/tests/test_compat.py +0 -0
  114. {hip_quant-2.2.0 → hip_quant-2.2.1}/tests/test_dequant_fp8.py +0 -0
  115. {hip_quant-2.2.0 → hip_quant-2.2.1}/tests/test_direct_fp8_quant.py +0 -0
  116. {hip_quant-2.2.0 → hip_quant-2.2.1}/tests/test_ffn_layer.py +0 -0
  117. {hip_quant-2.2.0 → hip_quant-2.2.1}/tests/test_fused_ssm_prefill.py +0 -0
  118. {hip_quant-2.2.0 → hip_quant-2.2.1}/tests/test_gemv_kquants.py +0 -0
  119. {hip_quant-2.2.0 → hip_quant-2.2.1}/tests/test_hq2.py +0 -0
  120. {hip_quant-2.2.0 → hip_quant-2.2.1}/tests/test_hq2_portable.py +0 -0
  121. {hip_quant-2.2.0 → hip_quant-2.2.1}/tests/test_hq8_g128.py +0 -0
  122. {hip_quant-2.2.0 → hip_quant-2.2.1}/tests/test_iq2s_iq1m_byte_exact.py +0 -0
  123. {hip_quant-2.2.0 → hip_quant-2.2.1}/tests/test_iquant_parallel.py +0 -0
  124. {hip_quant-2.2.0 → hip_quant-2.2.1}/tests/test_lazy_torch_import.py +0 -0
  125. {hip_quant-2.2.0 → hip_quant-2.2.1}/tests/test_mixed_policy.py +0 -0
  126. {hip_quant-2.2.0 → hip_quant-2.2.1}/tests/test_mixed_sensitivity.py +0 -0
  127. {hip_quant-2.2.0 → hip_quant-2.2.1}/tests/test_mxfp4_compat.py +0 -0
  128. {hip_quant-2.2.0 → hip_quant-2.2.1}/tests/test_mxfp4_native_contract.py +0 -0
  129. {hip_quant-2.2.0 → hip_quant-2.2.1}/tests/test_mxfp8_numerical.py +0 -0
  130. {hip_quant-2.2.0 → hip_quant-2.2.1}/tests/test_patch_hq_mixed_archive.py +0 -0
  131. {hip_quant-2.2.0 → hip_quant-2.2.1}/tests/test_pipeline.py +0 -0
  132. {hip_quant-2.2.0 → hip_quant-2.2.1}/tests/test_prefill_with_lse.py +0 -0
  133. {hip_quant-2.2.0 → hip_quant-2.2.1}/tests/test_q_to_fp8_gpu.py +0 -0
  134. {hip_quant-2.2.0 → hip_quant-2.2.1}/tests/test_qol.py +0 -0
  135. {hip_quant-2.2.0 → hip_quant-2.2.1}/tests/test_safetensors_numpy.py +0 -0
  136. {hip_quant-2.2.0 → hip_quant-2.2.1}/tests/test_v8.py +0 -0
  137. {hip_quant-2.2.0 → hip_quant-2.2.1}/tests/test_wave_attn_decode_hybrid.py +0 -0
  138. {hip_quant-2.2.0 → hip_quant-2.2.1}/tests/test_wave_prefill_gqa.py +0 -0
  139. {hip_quant-2.2.0 → hip_quant-2.2.1}/tests/test_wmma_diag.py +0 -0
  140. {hip_quant-2.2.0 → hip_quant-2.2.1}/tests/test_wmma_layout.py +0 -0
  141. {hip_quant-2.2.0 → hip_quant-2.2.1}/tests/torch/bench_compare.py +0 -0
  142. {hip_quant-2.2.0 → hip_quant-2.2.1}/tests/torch/bench_fp8.py +0 -0
  143. {hip_quant-2.2.0 → hip_quant-2.2.1}/tests/torch/conftest.py +0 -0
  144. {hip_quant-2.2.0 → hip_quant-2.2.1}/tests/torch/test_fp8.py +0 -0
  145. {hip_quant-2.2.0 → hip_quant-2.2.1}/tests/torch/test_fp8_v2.py +0 -0
  146. {hip_quant-2.2.0 → hip_quant-2.2.1}/tests/torch/test_hip_graph.py +0 -0
  147. {hip_quant-2.2.0 → hip_quant-2.2.1}/tests/torch/test_mxfp4_native_contract_torch.py +0 -0
  148. {hip_quant-2.2.0 → hip_quant-2.2.1}/tests/torch/test_mxfp4_to_fp8_torch.py +0 -0
  149. {hip_quant-2.2.0 → hip_quant-2.2.1}/tests/torch/test_mxfp8_torch.py +0 -0
  150. {hip_quant-2.2.0 → hip_quant-2.2.1}/tests/torch/test_q_to_fp8_torch.py +0 -0
  151. {hip_quant-2.2.0 → hip_quant-2.2.1}/tests/torch/test_quant_transpose.py +0 -0
  152. {hip_quant-2.2.0 → hip_quant-2.2.1}/tests/torch/test_wave_attn_backward_math.py +0 -0
  153. {hip_quant-2.2.0 → hip_quant-2.2.1}/tests/verify_fused_fp8_linear.py +0 -0
  154. {hip_quant-2.2.0 → hip_quant-2.2.1}/tools/mlp_codec/analyze.py +0 -0
  155. {hip_quant-2.2.0 → hip_quant-2.2.1}/tools/mlp_codec/clean_wikitext.py +0 -0
  156. {hip_quant-2.2.0 → hip_quant-2.2.1}/tools/mlp_codec/collect_hessians.py +0 -0
  157. {hip_quant-2.2.0 → hip_quant-2.2.1}/tools/mlp_codec/hq2_bridge.py +0 -0
  158. {hip_quant-2.2.0 → hip_quant-2.2.1}/tools/mlp_codec/hq2v.py +0 -0
  159. {hip_quant-2.2.0 → hip_quant-2.2.1}/tools/mlp_codec/ldlq.py +0 -0
  160. {hip_quant-2.2.0 → hip_quant-2.2.1}/tools/mlp_codec/ledger.py +0 -0
  161. {hip_quant-2.2.0 → hip_quant-2.2.1}/tools/mlp_codec/run_ladder.py +0 -0
  162. {hip_quant-2.2.0 → hip_quant-2.2.1}/tools/mlp_codec/safe_run.py +0 -0
  163. {hip_quant-2.2.0 → hip_quant-2.2.1}/tools/mlp_codec/validate_hessians.py +0 -0
  164. {hip_quant-2.2.0 → hip_quant-2.2.1}/torch_ext/current_stream.hip +0 -0
  165. {hip_quant-2.2.0 → hip_quant-2.2.1}/torch_ext/dequant_q_to_fp16.hip +0 -0
  166. {hip_quant-2.2.0 → hip_quant-2.2.1}/torch_ext/fp8_linear_kernels_v2.hip +0 -0
  167. {hip_quant-2.2.0 → hip_quant-2.2.1}/torch_ext/fp8_quant_kernels.hip +0 -0
  168. {hip_quant-2.2.0 → hip_quant-2.2.1}/torch_ext/hq2_linear_kernels.hip +0 -0
  169. {hip_quant-2.2.0 → hip_quant-2.2.1}/torch_ext/hq3_linear_kernels.hip +0 -0
  170. {hip_quant-2.2.0 → hip_quant-2.2.1}/torch_ext/hq8_g128_linear_kernels.hip +0 -0
  171. {hip_quant-2.2.0 → hip_quant-2.2.1}/torch_ext/iq_grid_tables.h +0 -0
  172. {hip_quant-2.2.0 → hip_quant-2.2.1}/torch_ext/kv_iu4_kernels.hip +0 -0
  173. {hip_quant-2.2.0 → hip_quant-2.2.1}/torch_ext/mxfp8_kernels.hip +0 -0
  174. {hip_quant-2.2.0 → hip_quant-2.2.1}/torch_ext/pytorch_bindings_hip.cpp +0 -0
  175. {hip_quant-2.2.0 → hip_quant-2.2.1}/torch_ext/q_to_fp8_kernels.hip +0 -0
  176. {hip_quant-2.2.0 → hip_quant-2.2.1}/torch_ext/ssm_kernels.hip +0 -0
  177. {hip_quant-2.2.0 → hip_quant-2.2.1}/torch_ext/wave_attn_backward.hip +0 -0
  178. {hip_quant-2.2.0 → hip_quant-2.2.1}/torch_ext/wave_attn_common.h +0 -0
  179. {hip_quant-2.2.0 → hip_quant-2.2.1}/torch_ext/wave_attn_decode.hip +0 -0
  180. {hip_quant-2.2.0 → hip_quant-2.2.1}/torch_ext/wave_attn_diag.hip +0 -0
  181. {hip_quant-2.2.0 → hip_quant-2.2.1}/torch_ext/wave_attn_prefill.hip +0 -0
  182. {hip_quant-2.2.0 → hip_quant-2.2.1}/wave_helpers.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hip-quant
3
- Version: 2.2.0
3
+ Version: 2.2.1
4
4
  Summary: High-performance GPU tensor quantization and inference engine for AMD ROCm. Native AOT GEMV (K-Quants & I-Quants), State Space Model (SSM/DeltaNet) kernels, FP8 WMMA WaveAttention, and portable HIP C++ kernels for RDNA4, RDNA3, and CDNA.
5
5
  Author-email: Thenukegun10x <conormorris84@gmail.com>
6
6
  License: Apache License
@@ -219,6 +219,8 @@ License-File: LICENSE
219
219
  Requires-Dist: numpy
220
220
  Provides-Extra: torch
221
221
  Requires-Dist: torch>=2.0; extra == "torch"
222
+ Provides-Extra: torch215
223
+ Requires-Dist: torch==2.15.0a0+gitf07882e; extra == "torch215"
222
224
  Dynamic: license-file
223
225
 
224
226
  <div align="center">
@@ -237,6 +239,18 @@ Dynamic: license-file
237
239
 
238
240
  `hip-quant` is a standalone Python library and highly optimized HIP C++ backend for tensor quantization and accelerated LLM inference on AMD GPUs with zero CPU round-trips.
239
241
 
242
+ ## 🌟 What's New in 2.2.1
243
+
244
+ > **2.2.1.post215** is the same release rebuilt against PyTorch 2.15 (TheRock / ROCm 7.14). See *Custom PyTorch 2.15* below for a self-hosted install index.
245
+
246
+ Security, correctness and robustness fixes from an internal audit:
247
+
248
+ - **Kernels**: fixed a missing CTA barrier in `wave_attn`/`wave_attn_long` (V overwrote the K tile while waves were still reading it), corrected the causal K-tile clamp (dropped the diagonal tile at exact boundaries), added `Dim <= 128` guards to the wave forward entry points, made the `gemv_tune` dispatch selector thread-local and exception-safe, and 64-bit-corrected FP8 GEMM index arithmetic.
249
+ - **Parsers (untrusted input)**: bounded GGUF string/array reads and the legacy HQ2 manifest (small crafted files could force multi-GiB allocations), rejected `general.alignment <= 0`, and replaced `assert`-based shape validation with explicit raises.
250
+ - **Offline API**: `quantize_from_fp8` now validates the `imatrix` element count (was a host + device out-of-bounds read), `ggml_blck_size_for` restype corrected, `math.prod` for element counts.
251
+ - **Hardening**: `_C` is loaded by absolute path (no `sys.path` mutation), `HIP_QUANT_DLL`/`_PATH` must be absolute, and the mxfp4 LUT init is `std::call_once`.
252
+ - **gpu-smi** is now fetched from its GitHub Releases at build time (checksum-verified) and bundled in the wheel; `smi.py` discovers it dynamically (env → bundled → console script → PATH) instead of hardcoding a path.
253
+
240
254
  ## 🌟 What's New in 2.2.0
241
255
 
242
256
  > **2.2.0.post215** is the same release rebuilt against PyTorch 2.15 (TheRock / ROCm 7.14). Use it if `2.2.0` reports a torch ABI mismatch on import.
@@ -545,19 +559,55 @@ the next replay.
545
559
  ## 📦 Installation
546
560
 
547
561
  ```powershell
548
- # Binary wheel with packaged ROCm 7.2.1 ctypes DLL and PyTorch extension
549
- pip install dist/hip_quant-1.3.0-cp312-cp312-win_amd64.whl
562
+ # From PyPI: binary wheel with the packaged ROCm 7.2.1 ctypes DLL and PyTorch extension
563
+ pip install hip-quant
550
564
 
551
- # With PyTorch optional dependency declared
565
+ # With the PyTorch optional dependency declared
552
566
  pip install "hip-quant[torch]"
567
+
568
+ # Or a local wheel
569
+ pip install dist/hip_quant-2.2.0-cp312-cp312-win_amd64.whl
570
+ ```
571
+
572
+ Two wheels are published per release, one per PyTorch ABI. Install the one that
573
+ matches your PyTorch, so the extension loads without an ABI mismatch:
574
+
575
+ | Wheel | PyTorch | ROCm |
576
+ |---|---|---|
577
+ | `hip-quant==2.2.1` | 2.9.x | ROCm 7.2.1 |
578
+ | `hip-quant==2.2.1.post215` | 2.15 / TheRock | ROCm 7.14 |
579
+
580
+ ```powershell
581
+ pip install "hip-quant==2.2.1.post215" # PyTorch 2.15 / TheRock
553
582
  ```
554
583
 
584
+ #### Custom PyTorch 2.15 (self-hosted wheels)
585
+
586
+ The `post215` wheel targets a custom PyTorch 2.15 build that is not on PyPI.
587
+ Its wheels live in a public Backblaze B2 bucket; point pip at the index page
588
+ with `--find-links`:
589
+
590
+ ```powershell
591
+ pip install "hip-quant==2.2.1.post215" `
592
+ --find-links https://dl.hipquant.download/file/Torchs/torch_index.html
593
+ ```
594
+
595
+ This resolves `torch==2.15.0a0+gitf07882e` (plus matching `torchvision` /
596
+ `torchaudio`). `gpu-smi` is bundled in the wheel, so monitoring needs no extra
597
+ step.
598
+
599
+ The wheels can also be fetched directly, e.g.
600
+ `https://dl.hipquant.download/file/Torchs/torch-2.15.0a0%2Bgitf07882e-cp312-cp312-win_amd64.whl`
601
+ — the `+` **must** be percent-encoded as `%2B` (a literal `+` 404s on B2).
602
+ Because wheel filenames must match their metadata version, the objects are
603
+ named `torch-2.15.0a0+gitf07882e-…`, not `torch-2.15.0-…`.
604
+
555
605
  On Windows, DLL resolution order is:
556
606
  - `HIP_QUANT_DLL` or `HIP_QUANT_DLL_PATH`, if set
557
607
  - `hip_quantize_rocm721.dll`
558
608
  - `hip_quantize.dll`
559
609
 
560
- Runtime DLL directories include `HIP_QUANT_ROCM_BIN`, `HIP_QUANT_ROCM_HOME`, `ROCM_HOME`, `ROCM_PATH`, `HIP_PATH`, the active venv's `_rocm_sdk_core\bin`, `torch\lib`, `Scripts`, then the system ROCm 7.1 path.
610
+ Runtime DLL directories include `HIP_QUANT_ROCM_BIN`, `HIP_QUANT_ROCM_HOME`, `ROCM_HOME`, `ROCM_PATH`, `HIP_PATH`, the active venv's `_rocm_sdk_core\bin`, `torch\lib`, `Scripts`, then the system ROCm 7.2 path.
561
611
 
562
612
  ---
563
613
 
@@ -820,6 +870,20 @@ Block-wise scaling is useful when a tensor has uneven dynamic range across its
820
870
  last dimension. It usually reduces FP8 quantization error compared with one
821
871
  global scale for the entire tensor. Existing per-tensor FP8 APIs remain unchanged.
822
872
 
873
+ #### Dynamic Per-Token FP8 Quantization
874
+
875
+ `quantize_e4m3_per_token` computes a single FP32 dequant scale for an entire row
876
+ (`amax / 448`). This is the `activation_scheme: "dynamic"` used by
877
+ DeepSeek/vLLM FP8 checkpoints. For an input `[..., K]` the scale tensor has
878
+ shape `[...]` — one value per row:
879
+
880
+ ```python
881
+ from hip_quant.torch_api import quantize_e4m3_per_token
882
+
883
+ x_fp8, x_scale = quantize_e4m3_per_token(x) # x_scale: [M], real ~= fp8 * scale[m]
884
+ ```
885
+
886
+
823
887
  #### Block-scaled Linear and Adafactor Kernel Helpers
824
888
 
825
889
  Two lower-level training helpers are available for experiments and future fused
@@ -848,12 +912,51 @@ out = fp8_linear_forward_blockwise_quantized(
848
912
  )
849
913
  ```
850
914
 
851
- The current block-scaled linear kernel is correctness-first and intentionally
852
- does not use gfx12 WMMA yet. It validates the `FP8 bytes + per-block scales`
853
- layout and math before replacing the inner loop with a tiled/WMMA or rocBLASLt
854
- implementation. `Adafactor` is a full Python optimizer step with factored
855
- second-moment state; GPU-side row/column mean-square helpers exist, while a
856
- fully fused Adafactor update kernel remains a future optimization.
915
+ #### 2-D Block-Scaled FP8 Linear (vLLM / DeepSeek)
916
+
917
+ `fp8_linear_forward_blockwise_2d` consumes a safetensors `weight_scale_inv`
918
+ directly: a `[N, K]` E4M3 weight plus one dequant scale per `block x block`
919
+ tile (typically `128 x 128`), i.e. a `[N/block, K/block]` FP32 tensor, paired
920
+ with a single per-token activation scale `[M]`:
921
+
922
+ ```text
923
+ C[m,n] = input_scale[m] * sum_kb W_scale[n/block, kb] * <A[m,:], B[n,:]>_kb
924
+ ```
925
+
926
+ ```python
927
+ from hip_quant import fp8_linear_forward_blockwise_2d, fp8_linear_deepseek
928
+
929
+ # From raw FP8 + 2-D scale tensors (already on device)
930
+ out = fp8_linear_forward_blockwise_2d(
931
+ input_fp8, input_scale, # quantize_e4m3_per_token(x)
932
+ weight_fp8, weight_scale_inv, # [N, K] uint8, [N/128, K/128] float32
933
+ output_dtype_source=x,
934
+ block_size=128, backend="auto", bias=bias,
935
+ )
936
+
937
+ # One-shot: dynamically quantizes x per token, then runs the fused GEMM
938
+ out = fp8_linear_deepseek(x, weight_fp8, weight_scale_inv, bias=bias)
939
+ ```
940
+
941
+ `backend` selects the kernel at runtime:
942
+
943
+ | backend | kernel | notes |
944
+ |---|---|---|
945
+ | `"auto"` (default) | gfx12 WMMA when the shape allows, else portable | recommended |
946
+ | `"wmma"` | gfx12 `v_wmma_f32_16x16x16_fp8_fp8`, one weight-tile scale folded per 128-K stage | gfx12 only |
947
+ | `"portable"` | LDS-tiled `64x64x32` microkernel, exact fp8->fp16 shared-memory decode | any AMD GPU, no matrix intrinsics |
948
+ | `"reference"` | naive per-element kernel | slow; testing only |
949
+
950
+ The per-token activation scale is constant across K, so it is factored out of
951
+ the accumulation; only the weight tile scale is applied per 128-K block. Scales
952
+ are dequant scales (`real ~= fp8 * scale`), matching `weight_scale_inv`, so a
953
+ checkpoint can be fed verbatim with no re-quantization of the weights.
954
+
955
+ The 1-D `fp8_linear_forward_blockwise_quantized` kernel above is correctness-first
956
+ and does **not** use gfx12 WMMA; the 2-D path does (see the backend table).
957
+ `Adafactor` is a full Python optimizer step with factored second-moment state;
958
+ GPU-side row/column mean-square helpers exist, while a fully fused Adafactor
959
+ update kernel remains a future optimization.
857
960
 
858
961
  #### Fake-FP8 Linear (autograd-safe, Phase 3)
859
962
 
@@ -964,6 +1067,9 @@ from hip_quant import (
964
1067
  fp8_linear_forward_scaled,
965
1068
  fp8_linear_forward_fp8_weight,
966
1069
  fp8_linear_forward_blockwise,
1070
+ fp8_linear_forward_blockwise_quantized,
1071
+ fp8_linear_forward_blockwise_2d,
1072
+ fp8_linear_deepseek,
967
1073
  fp8_linear_backward_input,
968
1074
  fp8_linear_backward_input_scaled,
969
1075
  fp8_linear_backward_weight,
@@ -983,6 +1089,9 @@ grad_wt_s = fp8_linear_backward_weight_scaled(grad_output, input, input_scale)
983
1089
 
984
1090
  # Correctness-first block-scaled FP8 path, no WMMA requirement
985
1091
  out_block = fp8_linear_forward_blockwise(input, weight, bias, block_size=32)
1092
+
1093
+ # 2-D (128x128 tile) block-scaled FP8 path from a safetensors weight_scale_inv
1094
+ out_2d = fp8_linear_deepseek(input, weight_fp8, weight_scale_inv, bias=bias)
986
1095
  ```
987
1096
 
988
1097
  These functions are also used by `Fp8Linear`, `Fp8ScaledLinear`, and
@@ -1061,10 +1170,9 @@ All PyTorch extension functions are guarded against:
1061
1170
 
1062
1171
  ## 🧪 Running Tests
1063
1172
 
1064
- #### Math tests (no GPU required)
1173
+ #### Extension FP8 tests (GPU required)
1065
1174
  ```powershell
1066
- python tests/torch/test_math_fp8.py
1067
- # 90/90 pass — validated against ml_dtypes reference
1175
+ & "C:\venvs\medusa_rocm\Scripts\python.exe" -m pytest tests/torch/test_fp8.py -v
1068
1176
  ```
1069
1177
 
1070
1178
  #### Full pipeline tests (CPU mock, no GPU required)
@@ -1128,20 +1236,27 @@ $env:HIP_QUANT_BUILD_TORCH_EXT = "1"
1128
1236
  Check the artifacts:
1129
1237
  ```powershell
1130
1238
  & "C:\venvs\medusa_rocm\Scripts\python.exe" -m twine check `
1131
- "dist\hip_quant-1.3.0-cp312-cp312-win_amd64.whl" `
1132
- "dist\hip_quant-1.3.0.tar.gz"
1239
+ "dist\hip_quant-2.2.0-cp312-cp312-win_amd64.whl" `
1240
+ "dist\hip_quant-2.2.0.tar.gz"
1133
1241
  ```
1134
1242
 
1135
1243
  Upload to PyPI:
1136
1244
  ```powershell
1137
1245
  & "C:\venvs\medusa_rocm\Scripts\python.exe" -m twine upload `
1138
- "dist\hip_quant-1.3.0-cp312-cp312-win_amd64.whl" `
1139
- "dist\hip_quant-1.3.0.tar.gz"
1246
+ "dist\hip_quant-2.2.0-cp312-cp312-win_amd64.whl" `
1247
+ "dist\hip_quant-2.2.0.tar.gz"
1140
1248
  ```
1141
1249
 
1142
- Do not upload stale universal wheels such as `hip_quant-1.3.0-py3-none-any.whl`.
1250
+ Do not upload stale universal wheels such as `hip_quant-2.2.0-py3-none-any.whl`.
1143
1251
  The Windows wheel is intentionally platform-tagged because it contains DLLs.
1144
1252
 
1253
+ Each release publishes two versions from the same sources — `X.Y.Z` (PyTorch
1254
+ 2.9.x / ROCm 7.2) and `X.Y.Z.post215` (PyTorch 2.15 / TheRock ROCm 7.14). Build
1255
+ each in its own venv: `setup_torch.py` picks the ROCm 7.14/TheRock toolchain for
1256
+ a `torch.version.hip` of `7.14.*` and `C:\Program Files\AMD\ROCm\<major.minor>`
1257
+ otherwise (see the toolchain matrix in `AGENTS.md`). Never build the 2.9.x
1258
+ artifact against TheRock, or vice versa.
1259
+
1145
1260
  Suggested release order:
1146
1261
  - Build and run `twine check`
1147
1262
  - Upload to TestPyPI or PyPI
@@ -1154,9 +1269,13 @@ Suggested release order:
1154
1269
 
1155
1270
  ```
1156
1271
  hip_quant/
1157
- ├── __init__.py # NumPy / ctypes offline API
1272
+ ├── __init__.py # NumPy / ctypes offline API + lazy export table
1158
1273
  ├── __main__.py # CLI entry point
1159
- ├── torch_api.py # PyTorch FP8 training API (Phases 1–4)
1274
+ ├── torch_api.py # PyTorch FP8 / GEMM / attention API (Phases 1-4)
1275
+ ├── gguf.py # Pure-Python GGUF parser
1276
+ ├── gguf_loader.py # Streaming GGUF -> VRAM tensor loader
1277
+ ├── wave_helpers.py # Drop-in wave attention helpers
1278
+ ├── smi.py # gpu-smi wrapper
1160
1279
  ├── device_info.py # GPU/DLL compatibility probe helpers
1161
1280
  ├── cdna_compat.py # CDNA feature table, build configs, CPU refs
1162
1281
  ├── setup_torch.py # PyTorch C++ extension build script
@@ -1167,17 +1286,23 @@ hip_quant/
1167
1286
  ├── kernels/ # Per-format offline HIP kernels (.cu)
1168
1287
  ├── torch_ext/ # PyTorch extension source
1169
1288
  │ ├── pytorch_bindings.cpp # C++ bindings (TORCH_CHECK, pybind11)
1170
- │ ├── fp8_quant_kernels.hip# Element-wise quant/dequant kernels
1171
- │ ├── mxfp8_kernels.hip # MXFP8 UE8M0 quant/dequant (OCP, 32-thread warp)
1172
- │ └── fp8_linear_kernels.hip# Tiled FP8 GEMM kernels
1173
- └── tests/torch/ # GPU test suite (pytest)
1289
+ │ ├── fp8_quant_kernels.hip # Element-wise + per-token + block-wise quant
1290
+ │ ├── fp8_linear_kernels.hip # FP8 GEMM: naive + tiled portable + 2-D block scales
1291
+ │ ├── fp8_linear_kernels_v2.hip # gfx12 LDS-staged FP8 WMMA GEMM (incl. 2-D block scales)
1292
+ │ ├── mxfp8_kernels.hip # MXFP8 UE8M0 quant/dequant (OCP, 32-thread warp)
1293
+ │ ├── gemv_q_kernels.hip # GGUF AOT GEMV (K-/I-quants)
1294
+ │ ├── hq2_linear_kernels.hip # HQ2 learned-codebook formats
1295
+ │ ├── hq3_linear_kernels.hip # HQ3 learned-codebook formats
1296
+ │ ├── ssm_kernels.hip # SSM / DeltaNet / fused norms
1297
+ │ └── wave_attn*.hip # WaveAttention FP8 WMMA prefill/decode/backward
1298
+ └── tests/ # pytest suite (CPU pipeline in tests/test_pipeline.py)
1174
1299
  ```
1175
1300
 
1176
1301
  ---
1177
1302
 
1178
1303
  ## 📋 Architecture Notes
1179
1304
 
1180
- - **RDNA4 PyTorch target** — FP8 WMMA extension kernels are compiled with `--offload-arch=gfx1200` and `--offload-arch=gfx1201`
1305
+ - **RDNA4 PyTorch target** — release `_C` builds are a multi-arch fatbin for `gfx90a`, `gfx942`, RDNA3 `gfx1100`-`gfx1103`, and RDNA4 `gfx1200`/`gfx1201` (`HIP_QUANT_ARCH` overrides this; a `gfx1201`-only build is the fast local-dev option). The gfx12 FP8 WMMA kernels require a `gfx1200`/`gfx1201` device at runtime.
1181
1306
  - **Default offline DLL target** — `build.ps1` compiles the portable DLL quantization kernels for `gfx90a`, `gfx942`, RDNA3 `gfx1100`-`gfx1103`, and RDNA4 `gfx1200`/`gfx1201`
1182
1307
  - **Current validation scope** — runtime-tested locally on `gfx1201` RX 9070 XT; `gfx1200` and CDNA code objects are build-validated and need separate hardware runtime validation
1183
1308
  - **BF16/FP16 PyTorch support** — FP8 quantization and linear kernels accept FP32, FP16, and BF16 tensors, accumulating in FP32 registers and storing results in the input/master dtype
@@ -14,6 +14,18 @@
14
14
 
15
15
  `hip-quant` is a standalone Python library and highly optimized HIP C++ backend for tensor quantization and accelerated LLM inference on AMD GPUs with zero CPU round-trips.
16
16
 
17
+ ## 🌟 What's New in 2.2.1
18
+
19
+ > **2.2.1.post215** is the same release rebuilt against PyTorch 2.15 (TheRock / ROCm 7.14). See *Custom PyTorch 2.15* below for a self-hosted install index.
20
+
21
+ Security, correctness and robustness fixes from an internal audit:
22
+
23
+ - **Kernels**: fixed a missing CTA barrier in `wave_attn`/`wave_attn_long` (V overwrote the K tile while waves were still reading it), corrected the causal K-tile clamp (dropped the diagonal tile at exact boundaries), added `Dim <= 128` guards to the wave forward entry points, made the `gemv_tune` dispatch selector thread-local and exception-safe, and 64-bit-corrected FP8 GEMM index arithmetic.
24
+ - **Parsers (untrusted input)**: bounded GGUF string/array reads and the legacy HQ2 manifest (small crafted files could force multi-GiB allocations), rejected `general.alignment <= 0`, and replaced `assert`-based shape validation with explicit raises.
25
+ - **Offline API**: `quantize_from_fp8` now validates the `imatrix` element count (was a host + device out-of-bounds read), `ggml_blck_size_for` restype corrected, `math.prod` for element counts.
26
+ - **Hardening**: `_C` is loaded by absolute path (no `sys.path` mutation), `HIP_QUANT_DLL`/`_PATH` must be absolute, and the mxfp4 LUT init is `std::call_once`.
27
+ - **gpu-smi** is now fetched from its GitHub Releases at build time (checksum-verified) and bundled in the wheel; `smi.py` discovers it dynamically (env → bundled → console script → PATH) instead of hardcoding a path.
28
+
17
29
  ## 🌟 What's New in 2.2.0
18
30
 
19
31
  > **2.2.0.post215** is the same release rebuilt against PyTorch 2.15 (TheRock / ROCm 7.14). Use it if `2.2.0` reports a torch ABI mismatch on import.
@@ -322,19 +334,55 @@ the next replay.
322
334
  ## 📦 Installation
323
335
 
324
336
  ```powershell
325
- # Binary wheel with packaged ROCm 7.2.1 ctypes DLL and PyTorch extension
326
- pip install dist/hip_quant-1.3.0-cp312-cp312-win_amd64.whl
337
+ # From PyPI: binary wheel with the packaged ROCm 7.2.1 ctypes DLL and PyTorch extension
338
+ pip install hip-quant
327
339
 
328
- # With PyTorch optional dependency declared
340
+ # With the PyTorch optional dependency declared
329
341
  pip install "hip-quant[torch]"
342
+
343
+ # Or a local wheel
344
+ pip install dist/hip_quant-2.2.0-cp312-cp312-win_amd64.whl
345
+ ```
346
+
347
+ Two wheels are published per release, one per PyTorch ABI. Install the one that
348
+ matches your PyTorch, so the extension loads without an ABI mismatch:
349
+
350
+ | Wheel | PyTorch | ROCm |
351
+ |---|---|---|
352
+ | `hip-quant==2.2.1` | 2.9.x | ROCm 7.2.1 |
353
+ | `hip-quant==2.2.1.post215` | 2.15 / TheRock | ROCm 7.14 |
354
+
355
+ ```powershell
356
+ pip install "hip-quant==2.2.1.post215" # PyTorch 2.15 / TheRock
330
357
  ```
331
358
 
359
+ #### Custom PyTorch 2.15 (self-hosted wheels)
360
+
361
+ The `post215` wheel targets a custom PyTorch 2.15 build that is not on PyPI.
362
+ Its wheels live in a public Backblaze B2 bucket; point pip at the index page
363
+ with `--find-links`:
364
+
365
+ ```powershell
366
+ pip install "hip-quant==2.2.1.post215" `
367
+ --find-links https://dl.hipquant.download/file/Torchs/torch_index.html
368
+ ```
369
+
370
+ This resolves `torch==2.15.0a0+gitf07882e` (plus matching `torchvision` /
371
+ `torchaudio`). `gpu-smi` is bundled in the wheel, so monitoring needs no extra
372
+ step.
373
+
374
+ The wheels can also be fetched directly, e.g.
375
+ `https://dl.hipquant.download/file/Torchs/torch-2.15.0a0%2Bgitf07882e-cp312-cp312-win_amd64.whl`
376
+ — the `+` **must** be percent-encoded as `%2B` (a literal `+` 404s on B2).
377
+ Because wheel filenames must match their metadata version, the objects are
378
+ named `torch-2.15.0a0+gitf07882e-…`, not `torch-2.15.0-…`.
379
+
332
380
  On Windows, DLL resolution order is:
333
381
  - `HIP_QUANT_DLL` or `HIP_QUANT_DLL_PATH`, if set
334
382
  - `hip_quantize_rocm721.dll`
335
383
  - `hip_quantize.dll`
336
384
 
337
- Runtime DLL directories include `HIP_QUANT_ROCM_BIN`, `HIP_QUANT_ROCM_HOME`, `ROCM_HOME`, `ROCM_PATH`, `HIP_PATH`, the active venv's `_rocm_sdk_core\bin`, `torch\lib`, `Scripts`, then the system ROCm 7.1 path.
385
+ Runtime DLL directories include `HIP_QUANT_ROCM_BIN`, `HIP_QUANT_ROCM_HOME`, `ROCM_HOME`, `ROCM_PATH`, `HIP_PATH`, the active venv's `_rocm_sdk_core\bin`, `torch\lib`, `Scripts`, then the system ROCm 7.2 path.
338
386
 
339
387
  ---
340
388
 
@@ -597,6 +645,20 @@ Block-wise scaling is useful when a tensor has uneven dynamic range across its
597
645
  last dimension. It usually reduces FP8 quantization error compared with one
598
646
  global scale for the entire tensor. Existing per-tensor FP8 APIs remain unchanged.
599
647
 
648
+ #### Dynamic Per-Token FP8 Quantization
649
+
650
+ `quantize_e4m3_per_token` computes a single FP32 dequant scale for an entire row
651
+ (`amax / 448`). This is the `activation_scheme: "dynamic"` used by
652
+ DeepSeek/vLLM FP8 checkpoints. For an input `[..., K]` the scale tensor has
653
+ shape `[...]` — one value per row:
654
+
655
+ ```python
656
+ from hip_quant.torch_api import quantize_e4m3_per_token
657
+
658
+ x_fp8, x_scale = quantize_e4m3_per_token(x) # x_scale: [M], real ~= fp8 * scale[m]
659
+ ```
660
+
661
+
600
662
  #### Block-scaled Linear and Adafactor Kernel Helpers
601
663
 
602
664
  Two lower-level training helpers are available for experiments and future fused
@@ -625,12 +687,51 @@ out = fp8_linear_forward_blockwise_quantized(
625
687
  )
626
688
  ```
627
689
 
628
- The current block-scaled linear kernel is correctness-first and intentionally
629
- does not use gfx12 WMMA yet. It validates the `FP8 bytes + per-block scales`
630
- layout and math before replacing the inner loop with a tiled/WMMA or rocBLASLt
631
- implementation. `Adafactor` is a full Python optimizer step with factored
632
- second-moment state; GPU-side row/column mean-square helpers exist, while a
633
- fully fused Adafactor update kernel remains a future optimization.
690
+ #### 2-D Block-Scaled FP8 Linear (vLLM / DeepSeek)
691
+
692
+ `fp8_linear_forward_blockwise_2d` consumes a safetensors `weight_scale_inv`
693
+ directly: a `[N, K]` E4M3 weight plus one dequant scale per `block x block`
694
+ tile (typically `128 x 128`), i.e. a `[N/block, K/block]` FP32 tensor, paired
695
+ with a single per-token activation scale `[M]`:
696
+
697
+ ```text
698
+ C[m,n] = input_scale[m] * sum_kb W_scale[n/block, kb] * <A[m,:], B[n,:]>_kb
699
+ ```
700
+
701
+ ```python
702
+ from hip_quant import fp8_linear_forward_blockwise_2d, fp8_linear_deepseek
703
+
704
+ # From raw FP8 + 2-D scale tensors (already on device)
705
+ out = fp8_linear_forward_blockwise_2d(
706
+ input_fp8, input_scale, # quantize_e4m3_per_token(x)
707
+ weight_fp8, weight_scale_inv, # [N, K] uint8, [N/128, K/128] float32
708
+ output_dtype_source=x,
709
+ block_size=128, backend="auto", bias=bias,
710
+ )
711
+
712
+ # One-shot: dynamically quantizes x per token, then runs the fused GEMM
713
+ out = fp8_linear_deepseek(x, weight_fp8, weight_scale_inv, bias=bias)
714
+ ```
715
+
716
+ `backend` selects the kernel at runtime:
717
+
718
+ | backend | kernel | notes |
719
+ |---|---|---|
720
+ | `"auto"` (default) | gfx12 WMMA when the shape allows, else portable | recommended |
721
+ | `"wmma"` | gfx12 `v_wmma_f32_16x16x16_fp8_fp8`, one weight-tile scale folded per 128-K stage | gfx12 only |
722
+ | `"portable"` | LDS-tiled `64x64x32` microkernel, exact fp8->fp16 shared-memory decode | any AMD GPU, no matrix intrinsics |
723
+ | `"reference"` | naive per-element kernel | slow; testing only |
724
+
725
+ The per-token activation scale is constant across K, so it is factored out of
726
+ the accumulation; only the weight tile scale is applied per 128-K block. Scales
727
+ are dequant scales (`real ~= fp8 * scale`), matching `weight_scale_inv`, so a
728
+ checkpoint can be fed verbatim with no re-quantization of the weights.
729
+
730
+ The 1-D `fp8_linear_forward_blockwise_quantized` kernel above is correctness-first
731
+ and does **not** use gfx12 WMMA; the 2-D path does (see the backend table).
732
+ `Adafactor` is a full Python optimizer step with factored second-moment state;
733
+ GPU-side row/column mean-square helpers exist, while a fully fused Adafactor
734
+ update kernel remains a future optimization.
634
735
 
635
736
  #### Fake-FP8 Linear (autograd-safe, Phase 3)
636
737
 
@@ -741,6 +842,9 @@ from hip_quant import (
741
842
  fp8_linear_forward_scaled,
742
843
  fp8_linear_forward_fp8_weight,
743
844
  fp8_linear_forward_blockwise,
845
+ fp8_linear_forward_blockwise_quantized,
846
+ fp8_linear_forward_blockwise_2d,
847
+ fp8_linear_deepseek,
744
848
  fp8_linear_backward_input,
745
849
  fp8_linear_backward_input_scaled,
746
850
  fp8_linear_backward_weight,
@@ -760,6 +864,9 @@ grad_wt_s = fp8_linear_backward_weight_scaled(grad_output, input, input_scale)
760
864
 
761
865
  # Correctness-first block-scaled FP8 path, no WMMA requirement
762
866
  out_block = fp8_linear_forward_blockwise(input, weight, bias, block_size=32)
867
+
868
+ # 2-D (128x128 tile) block-scaled FP8 path from a safetensors weight_scale_inv
869
+ out_2d = fp8_linear_deepseek(input, weight_fp8, weight_scale_inv, bias=bias)
763
870
  ```
764
871
 
765
872
  These functions are also used by `Fp8Linear`, `Fp8ScaledLinear`, and
@@ -838,10 +945,9 @@ All PyTorch extension functions are guarded against:
838
945
 
839
946
  ## 🧪 Running Tests
840
947
 
841
- #### Math tests (no GPU required)
948
+ #### Extension FP8 tests (GPU required)
842
949
  ```powershell
843
- python tests/torch/test_math_fp8.py
844
- # 90/90 pass — validated against ml_dtypes reference
950
+ & "C:\venvs\medusa_rocm\Scripts\python.exe" -m pytest tests/torch/test_fp8.py -v
845
951
  ```
846
952
 
847
953
  #### Full pipeline tests (CPU mock, no GPU required)
@@ -905,20 +1011,27 @@ $env:HIP_QUANT_BUILD_TORCH_EXT = "1"
905
1011
  Check the artifacts:
906
1012
  ```powershell
907
1013
  & "C:\venvs\medusa_rocm\Scripts\python.exe" -m twine check `
908
- "dist\hip_quant-1.3.0-cp312-cp312-win_amd64.whl" `
909
- "dist\hip_quant-1.3.0.tar.gz"
1014
+ "dist\hip_quant-2.2.0-cp312-cp312-win_amd64.whl" `
1015
+ "dist\hip_quant-2.2.0.tar.gz"
910
1016
  ```
911
1017
 
912
1018
  Upload to PyPI:
913
1019
  ```powershell
914
1020
  & "C:\venvs\medusa_rocm\Scripts\python.exe" -m twine upload `
915
- "dist\hip_quant-1.3.0-cp312-cp312-win_amd64.whl" `
916
- "dist\hip_quant-1.3.0.tar.gz"
1021
+ "dist\hip_quant-2.2.0-cp312-cp312-win_amd64.whl" `
1022
+ "dist\hip_quant-2.2.0.tar.gz"
917
1023
  ```
918
1024
 
919
- Do not upload stale universal wheels such as `hip_quant-1.3.0-py3-none-any.whl`.
1025
+ Do not upload stale universal wheels such as `hip_quant-2.2.0-py3-none-any.whl`.
920
1026
  The Windows wheel is intentionally platform-tagged because it contains DLLs.
921
1027
 
1028
+ Each release publishes two versions from the same sources — `X.Y.Z` (PyTorch
1029
+ 2.9.x / ROCm 7.2) and `X.Y.Z.post215` (PyTorch 2.15 / TheRock ROCm 7.14). Build
1030
+ each in its own venv: `setup_torch.py` picks the ROCm 7.14/TheRock toolchain for
1031
+ a `torch.version.hip` of `7.14.*` and `C:\Program Files\AMD\ROCm\<major.minor>`
1032
+ otherwise (see the toolchain matrix in `AGENTS.md`). Never build the 2.9.x
1033
+ artifact against TheRock, or vice versa.
1034
+
922
1035
  Suggested release order:
923
1036
  - Build and run `twine check`
924
1037
  - Upload to TestPyPI or PyPI
@@ -931,9 +1044,13 @@ Suggested release order:
931
1044
 
932
1045
  ```
933
1046
  hip_quant/
934
- ├── __init__.py # NumPy / ctypes offline API
1047
+ ├── __init__.py # NumPy / ctypes offline API + lazy export table
935
1048
  ├── __main__.py # CLI entry point
936
- ├── torch_api.py # PyTorch FP8 training API (Phases 1–4)
1049
+ ├── torch_api.py # PyTorch FP8 / GEMM / attention API (Phases 1-4)
1050
+ ├── gguf.py # Pure-Python GGUF parser
1051
+ ├── gguf_loader.py # Streaming GGUF -> VRAM tensor loader
1052
+ ├── wave_helpers.py # Drop-in wave attention helpers
1053
+ ├── smi.py # gpu-smi wrapper
937
1054
  ├── device_info.py # GPU/DLL compatibility probe helpers
938
1055
  ├── cdna_compat.py # CDNA feature table, build configs, CPU refs
939
1056
  ├── setup_torch.py # PyTorch C++ extension build script
@@ -944,17 +1061,23 @@ hip_quant/
944
1061
  ├── kernels/ # Per-format offline HIP kernels (.cu)
945
1062
  ├── torch_ext/ # PyTorch extension source
946
1063
  │ ├── pytorch_bindings.cpp # C++ bindings (TORCH_CHECK, pybind11)
947
- │ ├── fp8_quant_kernels.hip# Element-wise quant/dequant kernels
948
- │ ├── mxfp8_kernels.hip # MXFP8 UE8M0 quant/dequant (OCP, 32-thread warp)
949
- │ └── fp8_linear_kernels.hip# Tiled FP8 GEMM kernels
950
- └── tests/torch/ # GPU test suite (pytest)
1064
+ │ ├── fp8_quant_kernels.hip # Element-wise + per-token + block-wise quant
1065
+ │ ├── fp8_linear_kernels.hip # FP8 GEMM: naive + tiled portable + 2-D block scales
1066
+ │ ├── fp8_linear_kernels_v2.hip # gfx12 LDS-staged FP8 WMMA GEMM (incl. 2-D block scales)
1067
+ │ ├── mxfp8_kernels.hip # MXFP8 UE8M0 quant/dequant (OCP, 32-thread warp)
1068
+ │ ├── gemv_q_kernels.hip # GGUF AOT GEMV (K-/I-quants)
1069
+ │ ├── hq2_linear_kernels.hip # HQ2 learned-codebook formats
1070
+ │ ├── hq3_linear_kernels.hip # HQ3 learned-codebook formats
1071
+ │ ├── ssm_kernels.hip # SSM / DeltaNet / fused norms
1072
+ │ └── wave_attn*.hip # WaveAttention FP8 WMMA prefill/decode/backward
1073
+ └── tests/ # pytest suite (CPU pipeline in tests/test_pipeline.py)
951
1074
  ```
952
1075
 
953
1076
  ---
954
1077
 
955
1078
  ## 📋 Architecture Notes
956
1079
 
957
- - **RDNA4 PyTorch target** — FP8 WMMA extension kernels are compiled with `--offload-arch=gfx1200` and `--offload-arch=gfx1201`
1080
+ - **RDNA4 PyTorch target** — release `_C` builds are a multi-arch fatbin for `gfx90a`, `gfx942`, RDNA3 `gfx1100`-`gfx1103`, and RDNA4 `gfx1200`/`gfx1201` (`HIP_QUANT_ARCH` overrides this; a `gfx1201`-only build is the fast local-dev option). The gfx12 FP8 WMMA kernels require a `gfx1200`/`gfx1201` device at runtime.
958
1081
  - **Default offline DLL target** — `build.ps1` compiles the portable DLL quantization kernels for `gfx90a`, `gfx942`, RDNA3 `gfx1100`-`gfx1103`, and RDNA4 `gfx1200`/`gfx1201`
959
1082
  - **Current validation scope** — runtime-tested locally on `gfx1201` RX 9070 XT; `gfx1200` and CDNA code objects are build-validated and need separate hardware runtime validation
960
1083
  - **BF16/FP16 PyTorch support** — FP8 quantization and linear kernels accept FP32, FP16, and BF16 tensors, accumulating in FP32 registers and storing results in the input/master dtype
@@ -3,7 +3,7 @@ import numpy as np
3
3
  import os
4
4
  import sys
5
5
 
6
- __version__ = "2.2.0"
6
+ __version__ = "2.2.1"
7
7
 
8
8
 
9
9
  _TORCH_EXPORTS = {
@@ -284,6 +284,13 @@ def _add_runtime_dll_dirs():
284
284
  def _shared_library_candidates():
285
285
  env_dll = os.environ.get("HIP_QUANT_DLL") or os.environ.get("HIP_QUANT_DLL_PATH")
286
286
  if env_dll:
287
+ # Only an absolute override is safe: a bare/relative name is resolved
288
+ # against the process CWD and can be shadowed by an attacker (DLL hijack).
289
+ if not os.path.isabs(env_dll):
290
+ raise ValueError(
291
+ "HIP_QUANT_DLL / HIP_QUANT_DLL_PATH must be an absolute path, got "
292
+ f"{env_dll!r}"
293
+ )
287
294
  yield env_dll
288
295
 
289
296
  win_names = ["hip_quantize_rocm721.dll", "hip_quantize.dll"]
@@ -389,7 +396,7 @@ class HipQuant:
389
396
  self._dequantize_tensor_to_fp8 = None
390
397
  self._dll.ggml_type_size_for.restype = ctypes.c_size_t
391
398
  self._dll.ggml_type_size_for.argtypes = [ctypes.c_int]
392
- self._dll.ggml_blck_size_for.restype = ctypes.c_size_t
399
+ self._dll.ggml_blck_size_for.restype = ctypes.c_int
393
400
  self._dll.ggml_blck_size_for.argtypes = [ctypes.c_int]
394
401
  self._dll.ggml_row_size_for.restype = ctypes.c_size_t
395
402
  self._dll.ggml_row_size_for.argtypes = [ctypes.c_int, ctypes.c_int64]
@@ -855,6 +862,16 @@ class HipQuant:
855
862
  im_ptr = None
856
863
  if imatrix is not None:
857
864
  imatrix = np.ascontiguousarray(imatrix, dtype=np.float32)
865
+ # The native kernel indexes imatrix + row*n_per_row for every row,
866
+ # i.e. it reads exactly arr_fp8.size floats. Require at least that
867
+ # many (a short buffer is a host hipMemcpy + device OOB read), then
868
+ # reshape so the row indexing is well defined.
869
+ if imatrix.size != arr_fp8.size:
870
+ raise ValueError(
871
+ f"imatrix has {imatrix.size} elements but FP8 input has "
872
+ f"{arr_fp8.size} ({arr_fp8.shape})"
873
+ )
874
+ imatrix = imatrix.reshape(arr_fp8.shape)
858
875
  im_ptr = imatrix.ctypes.data_as(ctypes.POINTER(ctypes.c_float))
859
876
  if isinstance(source_format, str):
860
877
  source_format = source_format.upper()