Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
135 commits
Select commit Hold shift + click to select a range
e7bc53a
[WS1][CUDA][MiniMax-H3] adaln_gate_residual: gated residual with in-k…
fusheng-ji Oct 7, 2026
cd688b3
[WS1][MiniMax-H3] adaln_gate_residual: B200 evidence report and figure
fusheng-ji Oct 7, 2026
e7428b1
[WS1][CUDA][MiniMax-H3] final_adaln_out: norm_out projection + final …
fusheng-ji Oct 7, 2026
623bec8
[WS1][MiniMax-H3] final_adaln_out: B200 evidence report, chain replay…
fusheng-ji Oct 7, 2026
debde49
Merge inherited RFC 420 review fixes into PR #488
fusheng-ji Oct 7, 2026
36f8f3f
Merge inherited RFC 420 review fixes into PR #489
fusheng-ji Oct 7, 2026
cc86740
fix(h3): reject mixed-device RMSNorm native inputs
fusheng-ji Oct 7, 2026
40a9b44
fix(h3): retain FP64 final AdaLN golden gradients
fusheng-ji Oct 7, 2026
7090f00
fix(h3): address native validation and evidence review comments
fusheng-ji Oct 7, 2026
cff41e8
docs(h3): regenerate final AdaLN evidence against FP64 gradients
fusheng-ji Oct 7, 2026
507c9ad
[WS2][CUDA][MiniMax-H3] tp_adaln_3mod: column-parallel AdaLN projecti…
fusheng-ji Oct 7, 2026
ef0c9ee
[WS2][MiniMax-H3] tp_adaln_3mod: 8 x B200 NCCL evidence report and fi…
fusheng-ji Oct 7, 2026
e4b8a62
fix(h3): store norm_out.norm and 1 + scale in BF16 in the final AdaLN…
fusheng-ji Oct 8, 2026
dcbd55b
docs(h3): regenerate final AdaLN evidence with the BF16 norm_out golden
fusheng-ji Oct 8, 2026
a05952f
Merge inherited RFC 420 review fixes into PR #488
fusheng-ji Oct 8, 2026
7203797
Merge inherited RFC 420 review fixes into PR #489
fusheng-ji Oct 8, 2026
61c80d7
Merge inherited RFC 420 review fixes into PR #493
fusheng-ji Oct 8, 2026
be7c6a9
Merge the H3 prior-art runner into PR #488
fusheng-ji Oct 8, 2026
c678545
Merge the H3 prior-art runner into PR #489
fusheng-ji Oct 8, 2026
5d0c7d5
Merge the H3 prior-art runner into PR #493
fusheng-ji Oct 8, 2026
b4c9fd5
Merge the H3 prior-art runner fix into PR #488
fusheng-ji Oct 8, 2026
6231a8c
Merge the H3 prior-art runner fix into PR #489
fusheng-ji Oct 8, 2026
09625d2
Merge the H3 prior-art runner fix into PR #493
fusheng-ji Oct 8, 2026
052f5cb
Merge the H3 prior-art figure fix into PR #488
fusheng-ji Oct 8, 2026
875e2a1
Merge the H3 prior-art figure fix into PR #489
fusheng-ji Oct 8, 2026
3a14608
Merge the H3 prior-art figure fix into PR #493
fusheng-ji Oct 8, 2026
5f4253d
Merge the H3 prior-art figure fix into PR #488
fusheng-ji Oct 8, 2026
49287fc
Merge the H3 prior-art figure fix into PR #489
fusheng-ji Oct 8, 2026
b64f915
Merge the H3 prior-art figure fix into PR #493
fusheng-ji Oct 8, 2026
dd35c14
docs(h3): gate_residual vs existing implementations (B200, 4010854)
fusheng-ji Oct 8, 2026
8805329
docs(h3): final_adaln_out vs existing implementations (B200, 03da729)
fusheng-ji Oct 8, 2026
2d1b9d0
Merge the H3 prior-art evidence into PR #488
fusheng-ji Oct 8, 2026
64fb1fa
Merge the H3 prior-art evidence into PR #489
fusheng-ji Oct 8, 2026
f841e5d
Merge the H3 prior-art evidence into PR #493
fusheng-ji Oct 8, 2026
1d1e739
Merge the H3 prior-art figure layout fix into PR #488
fusheng-ji Oct 8, 2026
8136ac3
Merge the H3 prior-art figure layout fix into PR #489
fusheng-ji Oct 8, 2026
6f364d7
Merge the H3 prior-art figure layout fix into PR #493
fusheng-ji Oct 8, 2026
a9ed126
Fix H3 native validation, backward timing, and rank cleanup
fusheng-ji Oct 9, 2026
72ed970
Regenerate gate and final AdaLN backward-only B200 evidence
fusheng-ji Oct 9, 2026
c3fad21
Merge test-h3 refactor and migrate H3 kernels, tools, and tests
fusheng-ji Oct 10, 2026
e004499
Merge test-h3 refactor and migrate H3 kernels, tools, and tests
fusheng-ji Oct 10, 2026
fdc58d4
Merge migrated H3 dependency PR #487
fusheng-ji Oct 10, 2026
2737567
Merge migrated H3 dependency PR #488
fusheng-ji Oct 10, 2026
c41d03b
Merge test-h3 refactor and migrate H3 kernels, tools, and tests
fusheng-ji Oct 10, 2026
916ad44
Merge migrated H3 dependency PR #489
fusheng-ji Oct 10, 2026
6682e76
Merge migrated validation documentation from PR #487
fusheng-ji Oct 10, 2026
5ae2256
Merge migrated validation documentation from PR #488
fusheng-ji Oct 10, 2026
8686d2c
Merge migrated validation documentation from PR #489
fusheng-ji Oct 10, 2026
f75ff23
Merge feat/h3-rmsnorm into feat/h3-adaln-gate-residual
fusheng-ji Oct 13, 2026
2a72708
Merge feat/h3-adaln-gate-residual into feat/h3-final-adaln-out
fusheng-ji Oct 13, 2026
ebd2166
Merge feat/h3-final-adaln-out into feat/h3-tp-adaln-3mod
fusheng-ji Oct 13, 2026
a746bff
Merge feat/h3-rmsnorm into feat/h3-adaln-gate-residual
fusheng-ji Oct 13, 2026
3bbcca4
evidence(h3): gate_residual direct bitwise comparison on B200
fusheng-ji Oct 13, 2026
8cb4abe
Merge feat/h3-adaln-gate-residual into feat/h3-final-adaln-out
fusheng-ji Oct 13, 2026
2809990
evidence(h3): final_adaln_out direct bitwise comparison on B200
fusheng-ji Oct 13, 2026
815e0be
Merge feat/h3-final-adaln-out into feat/h3-tp-adaln-3mod
fusheng-ji Oct 13, 2026
3310212
Merge feat/h3-rmsnorm into feat/h3-adaln-gate-residual
fusheng-ji Oct 13, 2026
3b618cd
Merge feat/h3-adaln-gate-residual into feat/h3-final-adaln-out
fusheng-ji Oct 13, 2026
fb22c4c
Merge feat/h3-final-adaln-out into feat/h3-tp-adaln-3mod
fusheng-ji Oct 13, 2026
2c27639
Merge feat/h3-rmsnorm into feat/h3-adaln-gate-residual
fusheng-ji Oct 13, 2026
a43b952
Merge feat/h3-adaln-gate-residual into feat/h3-final-adaln-out
fusheng-ji Oct 13, 2026
904a70e
Merge feat/h3-final-adaln-out into feat/h3-tp-adaln-3mod
fusheng-ji Oct 13, 2026
9c76b32
Merge feat/h3-rmsnorm into feat/h3-adaln-gate-residual
fusheng-ji Oct 13, 2026
76542aa
Merge feat/h3-adaln-gate-residual into feat/h3-final-adaln-out
fusheng-ji Oct 13, 2026
ac1b95d
Merge feat/h3-final-adaln-out into feat/h3-tp-adaln-3mod
fusheng-ji Oct 13, 2026
81741e9
Merge feat/h3-rmsnorm into feat/h3-adaln-gate-residual
fusheng-ji Oct 13, 2026
e7d1a7f
Merge feat/h3-adaln-gate-residual into feat/h3-final-adaln-out
fusheng-ji Oct 13, 2026
a4bc99f
fix(h3): round the final_adaln_out goldens' activation from the FP32 …
fusheng-ji Oct 13, 2026
357c151
Merge feat/h3-final-adaln-out into feat/h3-tp-adaln-3mod
fusheng-ji Oct 13, 2026
d8a4a69
Merge feat/h3-rmsnorm into feat/h3-adaln-gate-residual
fusheng-ji Oct 13, 2026
a7605c6
Merge feat/h3-adaln-gate-residual into feat/h3-final-adaln-out
fusheng-ji Oct 13, 2026
7d716f2
evidence(h3): regenerate final_adaln_out report and chain replay afte…
fusheng-ji Oct 13, 2026
ddca8f9
Merge feat/h3-final-adaln-out into feat/h3-tp-adaln-3mod
fusheng-ji Oct 13, 2026
76594af
evidence(h3): regenerate this branch's final_adaln_out report after t…
fusheng-ji Oct 13, 2026
9592623
Merge feat/h3-rmsnorm into feat/h3-adaln-gate-residual
fusheng-ji Oct 13, 2026
578f9db
Merge feat/h3-adaln-gate-residual into feat/h3-final-adaln-out
fusheng-ji Oct 13, 2026
c9e350a
Merge feat/h3-final-adaln-out into feat/h3-tp-adaln-3mod
fusheng-ji Oct 13, 2026
9b95c4a
Merge feat/h3-rmsnorm into feat/h3-adaln-gate-residual
fusheng-ji Oct 13, 2026
de6a224
Merge feat/h3-adaln-gate-residual into feat/h3-final-adaln-out
fusheng-ji Oct 13, 2026
a65a02b
Merge feat/h3-final-adaln-out into feat/h3-tp-adaln-3mod
fusheng-ji Oct 13, 2026
a8e5901
docs: move the measurement outputs out of the pull request
fusheng-ji Oct 19, 2026
39fb03d
docs: move the measurement outputs out of the pull request
fusheng-ji Oct 19, 2026
c469b72
docs: move the measurement outputs out of the pull request
fusheng-ji Oct 19, 2026
3801808
docs: point commit hashes at the rewritten history
fusheng-ji Oct 23, 2026
428baa1
docs: point commit hashes at the rewritten history
fusheng-ji Oct 23, 2026
4530173
docs: point commit hashes at the rewritten history
fusheng-ji Oct 23, 2026
1cacd95
Merge test-h3 into feat/h3-adaln-gate-residual
fusheng-ji Oct 25, 2026
8624852
Merge test-h3 into feat/h3-final-adaln-out
fusheng-ji Oct 25, 2026
59377b2
Merge test-h3 into feat/h3-tp-adaln-3mod
fusheng-ji Oct 25, 2026
c08d9ee
Merge feat/h3-rmsnorm into feat/h3-adaln-gate-residual
fusheng-ji Oct 26, 2026
0011a97
Merge feat/h3-adaln-gate-residual into feat/h3-final-adaln-out
fusheng-ji Oct 26, 2026
d004996
Merge feat/h3-final-adaln-out into feat/h3-tp-adaln-3mod
fusheng-ji Oct 26, 2026
9c9ab15
Merge feat/h3-rmsnorm into feat/h3-adaln-gate-residual
fusheng-ji Oct 26, 2026
09c670b
Merge feat/h3-adaln-gate-residual into feat/h3-final-adaln-out
fusheng-ji Oct 26, 2026
9fe0daf
Merge feat/h3-final-adaln-out into feat/h3-tp-adaln-3mod
fusheng-ji Oct 26, 2026
669513d
fix(h3): keep the gate-residual forward out of the timed backward
fusheng-ji Oct 26, 2026
8e5ae90
Merge feat/h3-rmsnorm into feat/h3-adaln-gate-residual
fusheng-ji Oct 26, 2026
e5318ad
fix(h3): do not ask for the checkpoint when the gate-residual evidenc…
fusheng-ji Oct 26, 2026
7ed723a
Merge feat/h3 parent (#487) into #488
fusheng-ji Oct 26, 2026
174a7e1
Merge parent (#488) into #489
fusheng-ji Oct 26, 2026
c0cc462
Merge parent (#489) into #493
fusheng-ji Oct 26, 2026
4cde743
Merge parent (#487) into #488
fusheng-ji Oct 26, 2026
5e0775b
Merge parent (#488) into #489
fusheng-ji Oct 26, 2026
6d0a8d9
Merge parent (#489) into #493
fusheng-ji Oct 26, 2026
37f54db
Merge feat/h3-rmsnorm into feat/h3-adaln-gate-residual
fusheng-ji Oct 26, 2026
3682e65
Merge feat/h3-adaln-gate-residual into feat/h3-final-adaln-out
fusheng-ji Oct 26, 2026
239ef80
fix(h3): assert the gate row in the native kernels and check the back…
fusheng-ji Oct 26, 2026
1d26287
fix(h3): check the position repeat in final_adaln_out backward and ke…
fusheng-ji Oct 26, 2026
47f4f8c
Merge feat/h3-final-adaln-out into feat/h3-tp-adaln-3mod
fusheng-ji Oct 26, 2026
a2d0674
docs(h3): gate-residual latencies from the backward-only rerun
fusheng-ji Oct 26, 2026
70c3d19
Merge feat/h3-adaln-gate-residual into feat/h3-final-adaln-out
fusheng-ji Oct 26, 2026
337ee60
docs(h3): final_adaln_out latencies from the backward-only rerun
fusheng-ji Oct 26, 2026
6aaca7d
Merge parent (#489) into #493
fusheng-ji Oct 26, 2026
d46cbe5
Merge feat/h3-rmsnorm into feat/h3-adaln-gate-residual
fusheng-ji Oct 26, 2026
1857fa6
fix(h3): check the gate backward's tile metadata and lengths, and sca…
fusheng-ji Oct 26, 2026
9cde909
Merge feat/h3-adaln-gate-residual into feat/h3-final-adaln-out
fusheng-ji Oct 26, 2026
fcf0a58
fix(h3): run the final AdaLN backward only for the inputs that need a…
fusheng-ji Oct 26, 2026
95b5fc8
Merge feat/h3-final-adaln-out into feat/h3-tp-adaln-3mod
fusheng-ji Oct 26, 2026
b3747d9
fix(h3): refuse pre-SM80 before the first collective, check the TP ta…
fusheng-ji Oct 26, 2026
53ba838
Merge feat/h3-rmsnorm into feat/h3-adaln-gate-residual
fusheng-ji Oct 26, 2026
1703afc
Merge feat/h3-adaln-gate-residual into feat/h3-final-adaln-out
fusheng-ji Oct 26, 2026
e5d63c1
Merge feat/h3-final-adaln-out into feat/h3-tp-adaln-3mod
fusheng-ji Oct 26, 2026
2084242
Merge feat/h3-rmsnorm into feat/h3-adaln-gate-residual
fusheng-ji Oct 27, 2026
ab407b3
fix(h3): reject gate tables whose rows overlap, and state the residua…
fusheng-ji Oct 27, 2026
0923904
Merge feat/h3-adaln-gate-residual into feat/h3-final-adaln-out
fusheng-ji Oct 27, 2026
af608e6
Merge feat/h3-final-adaln-out into feat/h3-tp-adaln-3mod
fusheng-ji Oct 27, 2026
9aa200d
docs(h3): document the det_linear partial and fold stubs used by the …
fusheng-ji Oct 27, 2026
d20d767
Merge #487 round-5 fixes into #488
fusheng-ji Oct 27, 2026
60e7785
fix(h3): return no residual gradient for a residual that needs none
fusheng-ji Oct 27, 2026
b58b112
Merge #488 round-5 fixes into #489
fusheng-ji Oct 27, 2026
b64c023
Merge #489 round-5 fixes into #493
fusheng-ji Oct 27, 2026
22a3c79
Merge upstream test-h3 into feat/h3-adaln-gate-residual
fusheng-ji Oct 29, 2026
5a46bee
Merge feat/h3 round-6 upstream sync (#488) into #489
fusheng-ji Oct 29, 2026
a4a0dad
Merge feat/h3 round-6 upstream sync (#489) into #493
fusheng-ji Oct 29, 2026
7b85941
fix(h3): skip the weight and bias gradients of a frozen tensor-parall…
fusheng-ji Oct 29, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions build_tools/extensions.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"csrc/cuda/h3/det_linear.cu",
"csrc/cuda/h3/adaln_row_gather.cu",
"csrc/cuda/h3/rmsnorm_modulate.cu",
"csrc/cuda/h3/gate_residual.cu",
)
H3_KERNELS_DEFINE = "-DKERNEL_ALIGN_WITH_H3_KERNELS"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bug · high
H3_BITWISE_SOURCES and H3_KERNELS_DEFINE are only referenced inside the CUDA branch, but H3_BITWISE_SOURCES is added under if not is_rocm: while the define is appended under if not is_rocm and not use_fast_math: in a different spot. Please double-check the guard macro in csrc/bindings/ops.cpp is spelled exactly KERNEL_ALIGN_WITH_H3_KERNELS; if the binding guard name differs from H3_KERNELS_DEFINE, the bindings will never be compiled in even in valid non-fast-math CUDA builds, silently dropping the H3 operators while the .cu sources are still compiled. A build test that asserts the define is emitted does not catch a name mismatch between the flag and the #ifdef in ops.cpp.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in c0b4cd8 (#483, where the build file lives; this PR contains it). build_tools/extensions.py now computes one h3_enabled predicate that gates both the csrc/cuda/h3 sources and -DKERNEL_ALIGN_WITH_H3_KERNELS, so the bindings cannot outlive the kernels. NVCC_PREPEND_FLAGS, NVCC_APPEND_FLAGS and TORCH_NVCC_FLAGS carrying --use_fast_math, --ftz=true or --prec-div/--prec-sqrt=false leave the H3 kernels out with a warning, like KERNEL_ALIGN_USE_FAST_MATH=1, and dispatch falls back to the PyTorch reference. Tests: test_relaxed_math_nvcc_flags_from_the_environment_exclude_bitwise_h3_kernels (three variables) and test_unrelated_nvcc_flags_keep_the_h3_kernels. The #if in csrc/bindings/ops.cpp is spelled KERNEL_ALIGN_WITH_H3_KERNELS, the same string as H3_KERNELS_DEFINE, and the existing build test asserts the define is emitted.

# nvcc options that relax FP32 math. They can also arrive through the environment, where PyTorch's
Expand Down
23 changes: 23 additions & 0 deletions csrc/bindings/ops.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -510,6 +510,8 @@ std::vector<torch::Tensor> h3_det_linear_forward(torch::Tensor x, torch::Tensor
int64_t activation, bool save_pre_activation);
torch::Tensor h3_det_linear_backward_input(torch::Tensor grad, torch::Tensor weight,
c10::ScalarType out_dtype);
torch::Tensor h3_det_linear_backward_input_partials(torch::Tensor grad, torch::Tensor weight);
torch::Tensor h3_det_linear_fold_chunks(torch::Tensor partial, c10::ScalarType out_dtype);
std::vector<torch::Tensor> h3_det_linear_backward_weight(torch::Tensor grad, torch::Tensor x,
c10::ScalarType w_dtype,
bool with_bias);
Expand All @@ -530,6 +532,14 @@ std::vector<torch::Tensor> h3_rmsnorm_backward(
c10::optional<torch::Tensor> index, c10::optional<torch::Tensor> sorted_pos,
c10::optional<torch::Tensor> tile_begin, c10::optional<torch::Tensor> tile_end,
c10::optional<torch::Tensor> seg_first_tile);
torch::Tensor h3_gate_residual_forward(torch::Tensor residual, torch::Tensor y, torch::Tensor gate,
torch::Tensor index);
std::vector<torch::Tensor> h3_gate_residual_backward(torch::Tensor grad, torch::Tensor y,
torch::Tensor gate, torch::Tensor index,
torch::Tensor sorted_pos,
torch::Tensor tile_begin,
torch::Tensor tile_end,
torch::Tensor seg_first_tile);
#endif

// PyBind11 Module Registration
Expand Down Expand Up @@ -803,6 +813,12 @@ PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) {
m.def("h3_det_linear_backward_input", &h3_det_linear_backward_input,
"Deterministic grad @ weight with fixed 64-row N chunks folded in order",
py::arg("grad"), py::arg("weight"), py::arg("out_dtype"));
m.def("h3_det_linear_backward_input_partials", &h3_det_linear_backward_input_partials,
"Per-64-row-chunk FP32 partials of grad @ weight, before the ascending fold",
py::arg("grad"), py::arg("weight"));
m.def("h3_det_linear_fold_chunks", &h3_det_linear_fold_chunks,
"Ascending left fold of h3_det_linear_backward_input_partials, cast once",
py::arg("partial"), py::arg("out_dtype"));
m.def("h3_det_linear_backward_weight", &h3_det_linear_backward_weight,
"Deterministic dW/dbias as ascending-row FP32 folds",
py::arg("grad"), py::arg("x"), py::arg("w_dtype"), py::arg("with_bias") = true);
Expand All @@ -825,5 +841,12 @@ PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) {
py::arg("index") = py::none(), py::arg("sorted_pos") = py::none(),
py::arg("tile_begin") = py::none(), py::arg("tile_end") = py::none(),
py::arg("seg_first_tile") = py::none());
m.def("h3_gate_residual_forward", &h3_gate_residual_forward,
"residual + gate[index] * y with the gate row gathered in-kernel (eager rounding order)",
py::arg("residual"), py::arg("y"), py::arg("gate"), py::arg("index"));
m.def("h3_gate_residual_backward", &h3_gate_residual_backward,
"Gated-residual backward: exact dy, deterministic sorted segment sum for dgate",
py::arg("grad"), py::arg("y"), py::arg("gate"), py::arg("index"), py::arg("sorted_pos"),
py::arg("tile_begin"), py::arg("tile_end"), py::arg("seg_first_tile"));
#endif
}
6 changes: 3 additions & 3 deletions csrc/cuda/h3/adaln_row_gather.cu
Original file line number Diff line number Diff line change
Expand Up @@ -212,9 +212,9 @@ torch::Tensor h3_adaln_row_gather_backward(torch::Tensor grad, torch::Tensor sor
TORCH_CHECK(grad.is_cuda() && grad.dim() == 3 && grad.is_contiguous(),
"grad must be a contiguous (C, S, H) CUDA tensor");
for (const auto* t : {&sorted_pos, &tile_begin, &tile_end, &seg_first_tile}) {
TORCH_CHECK(t->is_cuda() && t->device() == grad.device() && t->dim() == 1 &&
t->is_contiguous() && t->scalar_type() == at::kLong,
"tile metadata must be contiguous 1-D int64 tensors on grad's device");
TORCH_CHECK(t->is_cuda() && t->device() == grad.device() && t->dim() == 1 && t->is_contiguous() &&
t->scalar_type() == at::kLong,
"tile metadata must be contiguous int64 tensors on ", grad.device());
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
TORCH_CHECK(seg_first_tile.numel() >= 1, "seg_first_tile must hold R + 1 entries");
TORCH_CHECK(tile_begin.numel() == tile_end.numel(), "tile_begin/tile_end length mismatch");
Expand Down
51 changes: 42 additions & 9 deletions csrc/cuda/h3/det_linear.cu
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@
// * N is split into fixed chunks of 64 rows; each chunk is an ascending
// fmaf chain into FP32 from 0; the chunk partials are then left-folded in
// ascending chunk order and cast once.
// The partials and the fold are also bound separately: a contiguous N
// slice starting on a chunk boundary yields exactly the full call's
// partials for those chunks, which is what tensor-parallel shards gather.
// d_weight dW[n, k] = sum_t g[t, n] * x[t, k]; d_bias db[n] = sum_t g[t, n]
// * an ascending-t fmaf chain into FP32 from 0, cast once. This is the one
// cross-row reduction; its order is the logical row order. db is the same
Expand Down Expand Up @@ -509,25 +512,22 @@ std::vector<torch::Tensor> h3_det_linear_forward(torch::Tensor x, torch::Tensor
return {out};
}

// grad [T, N] (float32), weight [N, K] -> grad_input [T, K] in out_dtype.
torch::Tensor h3_det_linear_backward_input(torch::Tensor grad, torch::Tensor weight,
c10::ScalarType out_dtype) {
// grad [T, N] (float32), weight [N, K] -> partial [ceil(N / 64), T, K] float32:
// the per-chunk sums of contract h3-det-linear-v1, before the ascending fold.
// A contiguous slice of N that starts on a chunk boundary yields exactly the
// matching rows of the full call (tensor-parallel shards rely on this).
torch::Tensor h3_det_linear_backward_input_partials(torch::Tensor grad, torch::Tensor weight) {
TORCH_CHECK(grad.is_cuda() && grad.dim() == 2 && grad.is_contiguous() &&
grad.scalar_type() == at::kFloat,
"grad must be a contiguous 2-D float32 CUDA tensor");
check_matrix(weight, "weight");
TORCH_CHECK(grad.device() == weight.device(), "grad and weight must be on the same device");
TORCH_CHECK(grad.size(1) == weight.size(0), "grad N != weight N");
TORCH_CHECK(out_dtype == at::kFloat || out_dtype == at::kBFloat16,
"out_dtype must be float32 or bfloat16");
const int64_t rows = grad.size(0);
TORCH_CHECK(rows > 0, "grad must have at least one row");
const int64_t n_out = weight.size(0);
const int64_t k_in = weight.size(1);
const c10::cuda::CUDAGuard device_guard(grad.device());
auto out = torch::empty({rows, k_in}, grad.options().dtype(out_dtype));
if (k_in == 0) return out;
if (n_out == 0) return out.zero_();
const int64_t chunks = (n_out + kDInputChunk - 1) / kDInputChunk;
// chunks is blockIdx.y and rows * k_in / threads is blockIdx.x of the fold: fail with a clear message
// instead of "invalid configuration argument" when a launch dimension would overflow.
Expand All @@ -536,6 +536,7 @@ torch::Tensor h3_det_linear_backward_input(torch::Tensor grad, torch::Tensor wei
TORCH_CHECK((rows * k_in + 255) / 256 <= std::numeric_limits<int32_t>::max(), "rows * K = ",
rows * k_in, " is too large for one input-gradient fold launch");
auto partial = torch::empty({chunks, rows, k_in}, grad.options());
if (partial.numel() == 0) return partial;
auto stream = at::cuda::getCurrentCUDAStream();
const int threads = 256;
dim3 grid(static_cast<unsigned>((k_in + threads - 1) / threads), static_cast<unsigned>(chunks));
Expand All @@ -549,7 +550,27 @@ torch::Tensor h3_det_linear_backward_input(torch::Tensor grad, torch::Tensor wei
n_out, k_in);
}
C10_CUDA_KERNEL_LAUNCH_CHECK();
const int64_t elems = rows * k_in;
return partial;
}

// partial [C, T, K] float32 -> left fold over C in ascending order, cast once.
torch::Tensor h3_det_linear_fold_chunks(torch::Tensor partial, c10::ScalarType out_dtype) {
TORCH_CHECK(partial.is_cuda() && partial.dim() == 3 && partial.is_contiguous() &&
partial.scalar_type() == at::kFloat && partial.size(0) > 0,
"partial must be a non-empty contiguous 3-D float32 CUDA tensor");
TORCH_CHECK(out_dtype == at::kFloat || out_dtype == at::kBFloat16,
"out_dtype must be float32 or bfloat16");
const c10::cuda::CUDAGuard device_guard(partial.device());
const int64_t chunks = partial.size(0);
auto out = torch::empty({partial.size(1), partial.size(2)}, partial.options().dtype(out_dtype));
const int64_t elems = out.numel();
if (elems == 0) return out;
auto stream = at::cuda::getCurrentCUDAStream();
const int threads = 256;
// Same bound as h3_det_linear_backward_input: grid.x holds at most INT32_MAX blocks. (That is 5e11
// elements, beyond any tensor that fits in memory; the check keeps the two entry points alike.)
TORCH_CHECK((elems + threads - 1) / threads <= std::numeric_limits<int32_t>::max(),
"rows * K = ", elems, " needs more blocks than one grid.x launch holds");
const unsigned fold_blocks = static_cast<unsigned>((elems + threads - 1) / threads);
if (out_dtype == at::kFloat) {
det_fold_chunks_kernel<float><<<fold_blocks, threads, 0, stream>>>(
Expand All @@ -562,6 +583,18 @@ torch::Tensor h3_det_linear_backward_input(torch::Tensor grad, torch::Tensor wei
return out;
}

// grad [T, N] (float32), weight [N, K] -> grad_input [T, K] in out_dtype.
torch::Tensor h3_det_linear_backward_input(torch::Tensor grad, torch::Tensor weight,
c10::ScalarType out_dtype) {
TORCH_CHECK(out_dtype == at::kFloat || out_dtype == at::kBFloat16,
"out_dtype must be float32 or bfloat16");
auto partial = h3_det_linear_backward_input_partials(grad, weight);
if (partial.size(0) == 0) { // N == 0: no output column contributes
return torch::zeros({partial.size(1), partial.size(2)}, grad.options().dtype(out_dtype));
}
return h3_det_linear_fold_chunks(partial, out_dtype);
}

// grad [T, N] float32, x [T, K] (float32 or bfloat16) -> (dW [N, K], dbias [N]) in w_dtype.
std::vector<torch::Tensor> h3_det_linear_backward_weight(torch::Tensor grad, torch::Tensor x,
c10::ScalarType w_dtype,
Expand Down
Loading
Loading