Skip to content

CUDA and ROCm optimizations - #1239

Open
lightvector wants to merge 5 commits into
masterfrom
cudarocmopt
Open

CUDA and ROCm optimizations#1239
lightvector wants to merge 5 commits into
masterfrom
cudarocmopt

Conversation

@lightvector

@lightvector lightvector commented Aug 18, 2026

Copy link
Copy Markdown
Owner

I worked on this PR over the last few days with a large number of optimizations to the CUDA and ROCm backends, hopefully speeding them up a bunch.
Thanks to @hzyhhzy and @zsqdx for forwarding along the hint from doomoooo in https://github.com/doomoooo/KataGomo_fork/tree/final-migration/final-migration that such an improvement was possible in the CUDA backend. A lot of the improvements also straightforwardly carry over to the ROCm backend due to how the ROCm backend shares most of its logic with CUDA.

Fortunately, unlike what was initially forwarded to me, I found many of the optimizations were not GPU-dependent. The optimizations implemented in this PR mostly are general speedups that apply across GPUs, although the exact amount that they each help might vary by GPU.

This PR incorporates also part of @Looong01's PR #1237, (not all of it), thanks to them for pointing out this additional optimization on rocm.

Here are measured visits per second on the katago benchmark on the GPUs I rented temporarily and tested with. Benchmark settings were 10k visits per position, 10 positions (the particular 10 that the benchmark chooses if you ask for 10).

  • old is master branch ccdec95 and new is the tip of this PR.
  • b11c768tf is the big strong transformer from the v1.17.1 release, b28c512 was s12674M model and b40c768 was the zhizi s11472M model from https://katagotraining.org/networks/
  • mi300x is using the rocm backend. All others are using the cuda backend.
  • NN threads 2 is using two server threads on the same GPU, numNNServerThreadsPerModel = 2. Interestingly, it seems that this is bad on master branch, but now with this PR it becomes good - the improvements on this branch enable the GPU to efficiently alternate between batches of requests.
                              NN Threads = 1   NN Threads = 2
GPU        Model     Threads  old  new factor  old  new factor
a5000      b11c768tf      32 1023 1228  1.20x  915 1283  1.40x
a5000      b11c768tf      64 1084 1341  1.24x 1042 1371  1.32x
a5000      b11c768tf      96 1065 1325  1.24x 1046 1332  1.27x
a5000      b11c768tf     128 1104 1324  1.20x 1077 1345  1.25x
rtx4090    b11c768tf      32 2685 3567  1.33x 2310 3928  1.70x
rtx4090    b11c768tf      64 2957 3970  1.34x 2719 4286  1.58x
rtx4090    b11c768tf      96 2866 4096  1.43x 2804 4242  1.51x
rtx4090    b11c768tf     128 2740 3963  1.45x 2766 4103  1.48x
h100       b11c768tf      32 3362 4482  1.33x 2390 4970  2.08x
h100       b11c768tf      64 4098 5494  1.34x 3305 5945  1.80x
h100       b11c768tf      96 4456 5895  1.32x 3910 6085  1.56x
h100       b11c768tf     128 4603 5805  1.26x 4144 6208  1.50x
rtxpro6000 b11c768tf      32 2027 4045  2.00x 1883 4128  2.19x
rtxpro6000 b11c768tf      64 2332 4395  1.88x 2243 4560  2.03x
rtxpro6000 b11c768tf      96 2319 4417  1.90x 2268 4529  2.00x
rtxpro6000 b11c768tf     128 2329 4329  1.86x 2245 4408  1.96x
mi300x     b11c768tf      32 1378 3173  2.30x 1059 3252  3.07x
mi300x     b11c768tf      64 2029 3987  1.97x 1654 4177  2.53x
mi300x     b11c768tf      96 2089 4228  2.02x 1920 4573  2.38x
mi300x     b11c768tf     128 2225 4472  2.01x 2068 4825  2.33x


                              NN Threads = 1   NN Threads = 2
GPU        Model     Threads  old  new factor  old  new factor
a5000      b28c512        32 1288 1263  0.98x 1188 1505  1.27x
a5000      b28c512        64 1490 1499  1.01x 1379 1582  1.15x
a5000      b28c512        96 1481 1591  1.07x 1464 1713  1.17x
a5000      b28c512       128 1538 1567  1.02x 1489 1709  1.15x
rtx4090    b28c512        32 2306 2306  1.00x 2291 2933  1.28x
rtx4090    b28c512        64 2654 2820  1.06x 2675 3510  1.31x
rtx4090    b28c512        96 2915 2986  1.02x 2876 3444  1.20x
rtx4090    b28c512       128 3054 3170  1.04x 2918 3661  1.25x
h100       b28c512        32 3294 3426  1.04x 3332 3947  1.18x
h100       b28c512        64 5533 5972  1.08x 4958 6840  1.38x
h100       b28c512        96 6725 7170  1.07x 5835 7931  1.36x
h100       b28c512       128 7337 7891  1.08x 6708 8712  1.30x
rtxpro6000 b28c512        32 4698 4692  1.00x 3891 4326  1.11x
rtxpro6000 b28c512        64 4952 5186  1.05x 4394 4941  1.12x
rtxpro6000 b28c512        96 4960 5139  1.04x 4560 5145  1.13x
rtxpro6000 b28c512       128 5022 5091  1.01x 4631 5124  1.11x
mi300x     b28c512        32 2413 3244  1.34x 2060 3387  1.64x
mi300x     b28c512        64 3201 3747  1.17x 2942 4578  1.56x
mi300x     b28c512        96 3674 4523  1.23x 3401 5332  1.57x
mi300x     b28c512       128 3850 4876  1.27x 3603 5509  1.53x

                              NN Threads = 1   NN Threads = 2
GPU        Model     Threads  old  new factor  old  new factor
a5000      b40c768        32  494  542  1.10x  510  563  1.10x
a5000      b40c768        64  582  593  1.02x  561  620  1.10x
a5000      b40c768        96  596  625  1.05x  579  634  1.09x
a5000      b40c768       128  579  627  1.08x  566  638  1.13x
rtx4090    b40c768        32 1041 1041  1.00x  936 1251  1.34x
rtx4090    b40c768        64 1177 1197  1.02x 1083 1389  1.28x
rtx4090    b40c768        96 1223 1271  1.04x 1201 1478  1.23x
rtx4090    b40c768       128 1222 1261  1.03x 1154 1423  1.23x
h100       b40c768        32 1975 2095  1.06x 1714 2346  1.37x
h100       b40c768        64 2985 3103  1.04x 2501 3148  1.26x
h100       b40c768        96 3260 3422  1.05x 2806 3371  1.20x
h100       b40c768       128 3144 3443  1.10x 3010 3434  1.14x
rtxpro6000 b40c768        32 1641 1719  1.05x 1504 1755  1.17x
rtxpro6000 b40c768        64 1853 1896  1.02x 1700 1819  1.07x
rtxpro6000 b40c768        96 1854 1903  1.03x 1736 1940  1.12x
rtxpro6000 b40c768       128 1823 1864  1.02x 1763 1863  1.06x
mi300x     b40c768        32 1097 1165  1.06x  954 1334  1.40x
mi300x     b40c768        64 1183 1353  1.14x 1131 1450  1.28x
mi300x     b40c768        96 1282 1392  1.09x 1212 1554  1.28x
mi300x     b40c768       128 1329 1422  1.07x 1236 1538  1.24x

@Looong01

Looong01 commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Agree! Thanks for ur hard work and effort!

@lightvector

Copy link
Copy Markdown
Owner Author

@Looong01 thanks. Would be great if you can also test it out, since we currently lack any datapoints for gpus like your gfx1100, and in case there is some error or incompatibility it would also be very good to know that so we can fix it.

@Looong01

Copy link
Copy Markdown
Contributor

Tested on my RX 7900 XTX (gfx1100), everything compiled and ran cleanly with no errors or incompatibilities. Great speedups across the board!

Environment: ROCm 7.14 (HIP 7.14.60850) / MIOpen 3.5.2, Intel i7-9700 (8 cores), self-compiled Release build with hipcc for gfx1100 only. Same benchmark settings as yours: 10k visits, 10 positions, threads 32/64/96/128, numNNServerThreadsPerModel 1 and 2. old is master ccdec95 and new is the tip of this branch (0893945).

Models: b11c768tf is the same big transformer from v1.17.1 and b40c768 is the same zhizi s11472M model you tested. b10c384 and b10c512 are the two smaller models shipped in the v1.17.2 release zip, included as extra datapoints.

                              NN Threads = 1   NN Threads = 2
GPU        Model     Threads  old  new factor  old  new factor
7900xtx    b10c384       32 3756 4303  1.15x 3120 4896  1.57x
7900xtx    b10c384       64 4063 4892  1.20x 3985 5618  1.41x
7900xtx    b10c384       96 4254 4997  1.17x 4176 5645  1.35x
7900xtx    b10c384      128 4368 4914  1.12x 4201 5721  1.36x
7900xtx    b10c512       32 2206 2709  1.23x 1890 3127  1.65x
7900xtx    b10c512       64 2373 3063  1.29x 2264 3412  1.51x
7900xtx    b10c512       96 2473 3141  1.27x 2433 3494  1.44x
7900xtx    b10c512      128 2399 3134  1.31x 2417 3478  1.44x
7900xtx    b11c768tf     32 1174 1538  1.31x 1077 1684  1.56x
7900xtx    b11c768tf     64 1278 1682  1.32x 1219 1773  1.45x
7900xtx    b11c768tf     96 1239 1664  1.34x 1236 1761  1.43x
7900xtx    b11c768tf    128 1233 1613  1.31x 1264 1698  1.34x
7900xtx    b40c768       32  515  608  1.18x  467  593  1.27x
7900xtx    b40c768       64  552  651  1.18x  546  649  1.19x
7900xtx    b40c768       96  564  646  1.14x  548  671  1.23x
7900xtx    b40c768      128  547  639  1.17x  554  665  1.20x

A few observations:

Thanks for putting this together!

@zhaob1n

zhaob1n commented Aug 18, 2026

Copy link
Copy Markdown

Hi, I have just tested on my RX 6800XT(gfx1030):

                                       NN Threads = 1           NN Threads = 2    
GPU          Model           Threads    old    new  factor      old    new  factor
-----------------------------------------------------------------------------------
RX 6800 XT   b11c768tf (TF)       32     10    410  39.95x       10    315  32.50x
                                  64     11    374  35.61x       10    298  30.62x
                                  96     11    353  32.65x       10    296  30.31x
                                 128     11    335  30.73x       10    292  29.81x
-----------------------------------------------------------------------------------
RX 6800 XT   b28c512 (Conv)       32    550    679   1.24x      517    658   1.27x
                                  64    550    694   1.26x      546    693   1.27x
                                  96    538    682   1.27x      545    689   1.27x
                                 128    555    669   1.20x      538    678   1.26x
-----------------------------------------------------------------------------------
RX 6800 XT   b40c768 (Conv)       32    207    248   1.20x      196    240   1.23x
                                  64    210    239   1.14x      201    241   1.20x
                                  96    206    240   1.17x      202    240   1.19x
                                 128    203    238   1.17x      201    239   1.19x
-----------------------------------------------------------------------------------

Note that improvements to transformer model is HUGE because without the 1x1 convolution GEMM optimization, the old version fell back to MIOpen's slow convolution path on RDNA, bottlenecking search performance at only ~10 visits/s. However, b11c768, while being smaller, is still slower than b28, so there must still be room for optimization.

@lightvector

lightvector commented Aug 18, 2026

Copy link
Copy Markdown
Owner Author

Thanks for the tests!

However, b11c768, while being smaller, is still slower than b28, so there must still be room for optimization.

b11c768 transformer is about the same number of parameters as b28c512 convnet, but is expected to be slightly slower because transformers at equal param counts are generally slower than convnets. There's always room for optimization on any model, but it's not the case that you should expect it to reach the same speed. However transformers at equal param counts are far stronger than convnets, b11c768 transformer at equal visits is stronger than b40c768 convnet, and should be considered in terms of model quality to be the same class as the b40c768 zhizi models. So based on your results, b11c768 is already the clear winner now, since it's both stronger and faster.

zhihuidu-amd added a commit to zhihuidu-amd/KataGo that referenced this pull request Aug 18, 2026
linear1 and linearGate read the same normalized input and differ only in weights, so they are
one matmul with the weight matrices concatenated along the output axis, split back afterwards.
Applied to both the NHWC and NCHW transformer FFN paths. The FFN projection is the widest GEMM
in a transformer block (ffnC > numHeads*headDim), so this is the larger of the two available
projection fusions; QKV is the other.

PR lightvector#1239 fuses the same pair, but its CUTLASS dual-GEMM path is guarded by
'#if defined(KATAGO_GPU_CUDA) && defined(USE_CUTLASS_FUSED_FFN)' and needs sm_80+, so on CDNA
its FFN stays unfused. This closes that gap on AMD.

Split rather than two Slices: one node stating 'two equal halves' leaves a single producer with
two consumers, and needs no index initializers. Those initializers were also a correctness
problem in the obvious formulation, since addInitializer does not deduplicate and every FFN
block would emit the same names; the remaining fused-weight initializer is run through uniq()
for that reason. The fused NCHW conv sets kernel_shape explicitly, as buildMatMul does.

Not yet measured: the NHWC path is still gated off by the transformer policy bug.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants