Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
418998c
[WS1][CUDA][MiniMax-H3] timestep_mlp_fp32: deterministic FP32 timeste…
fusheng-ji Oct 7, 2026
e32bb4a
[WS1][MiniMax-H3] timestep_mlp_fp32: B200 evidence report and figure
fusheng-ji Oct 7, 2026
74a7772
fix(h3): reject mixed CUDA devices in deterministic linear helpers
fusheng-ji Oct 7, 2026
0fd6210
Merge timestep sinusoid review fixes into H3 timestep MLP
fusheng-ji Oct 7, 2026
2a984f6
Merge the H3 prior-art runner into PR #484
fusheng-ji Oct 8, 2026
39f0f80
Merge the H3 prior-art runner fix into PR #484
fusheng-ji Oct 8, 2026
6acdd42
Merge the H3 prior-art figure fix into PR #484
fusheng-ji Oct 8, 2026
d7dba15
Merge the H3 prior-art figure fix into PR #484
fusheng-ji Oct 8, 2026
4c040db
docs(h3): timestep_mlp vs existing implementations (B200, ffd958a)
fusheng-ji Oct 8, 2026
f9c5a8c
Merge the H3 prior-art evidence into PR #484
fusheng-ji Oct 8, 2026
0ea4545
Merge the H3 prior-art figure layout fix into PR #484
fusheng-ji Oct 8, 2026
ce16ef9
Merge test-h3 refactor and migrate H3 timestep MLP validation
fusheng-ji Oct 10, 2026
d22c1f8
Merge migrated H3 dependency PR #483
fusheng-ji Oct 10, 2026
e04594b
Merge feat/h3-timestep-sinusoid into feat/h3-timestep-mlp-fp32
fusheng-ji Oct 13, 2026
73939f2
Merge feat/h3-timestep-sinusoid into feat/h3-timestep-mlp-fp32
fusheng-ji Oct 13, 2026
1a21cd6
evidence(h3): timestep_mlp direct bitwise comparison on B200
fusheng-ji Oct 13, 2026
fb1bd8a
fix(h3): seed the timestep_mlp timing inputs in the evidence report
fusheng-ji Oct 13, 2026
8132d06
docs: move the measurement outputs out of the pull request
fusheng-ji Oct 19, 2026
3b74ce3
docs: point commit hashes at the rewritten history
fusheng-ji Oct 23, 2026
897601c
Merge test-h3 into feat/h3-timestep-mlp-fp32
fusheng-ji Oct 25, 2026
cb9828f
fix(h3): time competing callables in a shuffled order and fix the sin…
fusheng-ji Oct 25, 2026
a74b1a5
fix(h3): record which weights the timestep MLP evidence used
fusheng-ji Oct 25, 2026
9a748eb
fix(h3): time candidate and provider with the rotating harness of the…
fusheng-ji Oct 26, 2026
9beb140
fix(h3): keep the weight source on every timestep MLP perf row
fusheng-ji Oct 26, 2026
31f342d
fix(h3): use one timing harness and record the MLP weight source addi…
fusheng-ji Oct 26, 2026
2db1bfd
Merge feat/h3-timestep-sinusoid into feat/h3-timestep-mlp-fp32
fusheng-ji Oct 26, 2026
92175db
fix(h3): refuse a random-weight MLP evidence run before measuring
fusheng-ji Oct 26, 2026
5447c59
Merge feat/h3-timestep-sinusoid into feat/h3-timestep-mlp-fp32
fusheng-ji Oct 26, 2026
0f66d75
fix(h3): do not consume the weight registers of columns past n_out
fusheng-ji Oct 26, 2026
50f1511
Merge feat/h3-timestep-sinusoid into feat/h3-timestep-mlp-fp32
fusheng-ji Oct 26, 2026
0e911be
fix(h3): fail at build time or with a clear error when det_linear lau…
fusheng-ji Oct 26, 2026
10e96ff
Merge feat/h3-timestep-sinusoid into feat/h3-timestep-mlp-fp32
fusheng-ji Oct 26, 2026
e1274b0
docs(h3): state the K and N tail contract of det_linear next to the l…
fusheng-ji Oct 26, 2026
1adec04
fix(h3): report a w1 that is not a matrix as a dimension error, and s…
fusheng-ji Oct 26, 2026
9db3759
Merge feat/h3-timestep-sinusoid into feat/h3-timestep-mlp-fp32
fusheng-ji Oct 27, 2026
2ee5abc
fix(h3): skip the MLP bias fold when no bias needs a gradient, and pi…
fusheng-ji Oct 27, 2026
a1594ae
Merge #483 round-5 fixes into #484
fusheng-ji Oct 27, 2026
30d722e
Merge branch 'test-h3' into feat/h3-timestep-mlp-fp32
maxiaosong1124 Oct 28, 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
5 changes: 4 additions & 1 deletion build_tools/extensions.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@
# approximations and flushes denormals, so these sources are left out of
# KERNEL_ALIGN_USE_FAST_MATH=1 builds; their bindings are gated on
# KERNEL_ALIGN_WITH_H3_KERNELS and dispatch falls back to the PyTorch reference.
H3_BITWISE_SOURCES = ("csrc/cuda/h3/timestep_sinusoid.cu",)
H3_BITWISE_SOURCES = (
"csrc/cuda/h3/timestep_sinusoid.cu",
"csrc/cuda/h3/det_linear.cu",
)
H3_KERNELS_DEFINE = "-DKERNEL_ALIGN_WITH_H3_KERNELS"
# nvcc options that relax FP32 math. They can also arrive through the environment, where PyTorch's
# BuildExtension appends them after the flags built here, so the H3 kernels check for them too.
Expand Down
18 changes: 18 additions & 0 deletions csrc/bindings/ops.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,14 @@ at::Tensor prefix_shared_attention(
#if defined(KERNEL_ALIGN_WITH_H3_KERNELS)
torch::Tensor h3_timestep_sinusoid_forward(torch::Tensor timestep, int64_t num_channels,
double max_period, bool check_range);
std::vector<torch::Tensor> h3_det_linear_forward(torch::Tensor x, torch::Tensor weight,
c10::optional<torch::Tensor> bias,
int64_t activation, bool save_pre_activation);
torch::Tensor h3_det_linear_backward_input(torch::Tensor grad, torch::Tensor weight,
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);
#endif

// PyBind11 Module Registration
Expand Down Expand Up @@ -771,5 +779,15 @@ PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) {
"MiniMax-H3 FP32 [cos | sin] timestep features, bitwise to the diffusers CUDA path",
py::arg("timestep"), py::arg("num_channels") = 256, py::arg("max_period") = 10000.0,
py::arg("check_range") = true);
m.def("h3_det_linear_forward", &h3_det_linear_forward,

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 · critical
torch::wrap_pybind_function is inconsistently applied: the three h3_det_linear_* ops are registered with the raw & function pointer. torch::wrap_pybind_function is what releases the GIL and re-acquires the current CUDA device around the call, so these ops run with the GIL held and (via pybind's implicit torch::Tensor caster) do not do the device-guard bookkeeping of the wrapped path. Please wrap them too, matching h3_timestep_sinusoid_forward.

Suggestion:

Suggested change
m.def("h3_det_linear_forward", &h3_det_linear_forward,
m.def("h3_det_linear_forward", torch::wrap_pybind_function(h3_det_linear_forward),

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.

Not changed. torch::wrap_pybind_function does not release the GIL and does not touch the CUDA device: in torch 2.13 (torch/csrc/Exceptions.h) it instantiates wrap_pybind_function_impl_ with release_gil = false; the GIL-releasing variant is wrap_pybind_function_no_gil. What the wrapper adds is PyTorch's exception and warning translation. The device is handled inside the entry points: h3_det_linear_forward, h3_det_linear_backward_input and h3_det_linear_backward_weight each take a c10::cuda::CUDAGuard on their tensors' device before the first allocation or launch and read the stream after it. The sinusoid op keeps its wrapper for its own reason: it is the one H3 op that raises a typed error (TORCH_CHECK_VALUE, so the range check reaches Python as ValueError); the det_linear checks are plain TORCH_CHECKs that reach Python as RuntimeError either way (the validation tests assert those messages), and every other native op in ops.cpp is registered with the raw pointer. Pinned in 2ee5abc: test_ops_run_on_the_device_of_their_tensors_not_the_current_one calls forward and both backwards with the tensors on cuda:1 while cuda:0 is current, for FP32 and BF16, and compares the bytes with the same calls on cuda:0.

"Batch-invariant warp-per-column linear (contract h3-det-linear-v1), optional SiLU",
py::arg("x"), py::arg("weight"), py::arg("bias") = py::none(),
py::arg("activation") = 0, py::arg("save_pre_activation") = false);
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_weight", &h3_det_linear_backward_weight,
Comment on lines +786 to +789

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_det_linear_backward_input / h3_det_linear_backward_weight are likewise registered with the raw function pointer, so these (potentially long, allocating) backward kernels run while holding the GIL and without torch::wrap_pybind_function's device handling. Wrap both for consistency with the other native ops.

Suggestion:

Suggested change
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_weight", &h3_det_linear_backward_weight,
m.def("h3_det_linear_backward_input", torch::wrap_pybind_function(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_weight", torch::wrap_pybind_function(h3_det_linear_backward_weight),

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.

Not changed. torch::wrap_pybind_function does not release the GIL and does not touch the CUDA device: in torch 2.13 (torch/csrc/Exceptions.h) it instantiates wrap_pybind_function_impl_ with release_gil = false; the GIL-releasing variant is wrap_pybind_function_no_gil. What the wrapper adds is PyTorch's exception and warning translation. The device is handled inside the entry points: h3_det_linear_forward, h3_det_linear_backward_input and h3_det_linear_backward_weight each take a c10::cuda::CUDAGuard on their tensors' device before the first allocation or launch and read the stream after it. The sinusoid op keeps its wrapper for its own reason: it is the one H3 op that raises a typed error (TORCH_CHECK_VALUE, so the range check reaches Python as ValueError); the det_linear checks are plain TORCH_CHECKs that reach Python as RuntimeError either way (the validation tests assert those messages), and every other native op in ops.cpp is registered with the raw pointer. Pinned in 2ee5abc: test_ops_run_on_the_device_of_their_tensors_not_the_current_one calls forward and both backwards with the tensors on cuda:1 while cuda:0 is current, for FP32 and BF16, and compares the bytes with the same calls on cuda:0.

"Deterministic dW/dbias as ascending-row FP32 folds",
py::arg("grad"), py::arg("x"), py::arg("w_dtype"), py::arg("with_bias") = true);
#endif
}
Loading
Loading