-
Notifications
You must be signed in to change notification settings - Fork 2.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Optimise pairwise multiplication #5282
Conversation
clang-format 17 needs to be run on this PR. (execution 9209296365 / attempt 1) |
This speedup was first inspired by a comment by @AndyGrant on my recent PR "If mullo_epi16 would preserve the signedness, then this could be used to remove 50% of the max operations during the halfkp-pairwise mat-mul relu deal." That got me thinking, because although mullo_epi16 did not preserve the signedness, mulhi_epi16 did, and so we could shift left and then use mulhi_epi16, instead of shifting right after the mullo. However, due to some issues with shifting into the sign bit, the FT weights and biases had to be multiplied by 2 for the optimisation to work. In the future we can increase the quantisation number in the FT to 255 (instead of 2x127=254) and also train a net from scratch to make use of the extra bit (currently all the weights and biases are even) Speedup on "Arch=x86-64-bmi2 COMP=clang", courtesy of @Torom Result of 50 runs base (...es/stockfish) = 962946 +/- 1202 test (...ise-max-less) = 979696 +/- 1084 diff = +16750 +/- 1794 speedup = +0.0174 P(speedup > 0) = 1.0000 CPU: 4 x Intel(R) Core(TM) i7-6700K CPU @ 4.00GHz Hyperthreading: on Also a speedup on "COMP=gcc", courtesy of Torom once again Result of 50 runs base (...tockfish_gcc) = 966033 +/- 1574 test (...max-less_gcc) = 983319 +/- 1513 diff = +17286 +/- 2515 speedup = +0.0179 P(speedup > 0) = 1.0000 CPU: 4 x Intel(R) Core(TM) i7-6700K CPU @ 4.00GHz Hyperthreading: on closes official-stockfish#5282 Passed STC: LLR: 2.96 (-2.94,2.94) <0.00,2.00> Total: 67712 W: 17715 L: 17358 D: 32639 Ptnml(0-2): 225, 7472, 18140, 7759, 260 https://tests.stockfishchess.org/tests/view/664c1d75830eb9f886616906 No functional change
I think it should also be mentioned that this is only a small speedup if any for NEON:
This is also the reason why the first SPRT failed when vondeles fleet was active: https://tests.stockfishchess.org/tests/view/664b21fb830eb9f886614a79 |
Congrats! Nice speedup. |
nice speedup, maybe it will help with larger L1.
|
To convert the nets I simply doubled all the weights and biases on net loading, and then exported it For changes on the trainer side, I'm not sure where to edit, but the change should be as simple as changing the FT quantised_one value. Maybe Sopel can help with this? |
This speedup was first inspired by a comment by @AndyGrant on my recent PR "If mullo_epi16 would preserve the signedness, then this could be used to remove 50% of the max operations during the halfkp-pairwise mat-mul relu deal." That got me thinking, because although mullo_epi16 did not preserve the signedness, mulhi_epi16 did, and so we could shift left and then use mulhi_epi16, instead of shifting right after the mullo. However, due to some issues with shifting into the sign bit, the FT weights and biases had to be multiplied by 2 for the optimisation to work. In the future we can increase the quantisation number in the FT to 255 (instead of 2x127=254) and also train a net from scratch to make use of the extra bit (currently all the weights and biases are even) Speedup on "Arch=x86-64-bmi2 COMP=clang", courtesy of @Torom Result of 50 runs base (...es/stockfish) = 962946 +/- 1202 test (...ise-max-less) = 979696 +/- 1084 diff = +16750 +/- 1794 speedup = +0.0174 P(speedup > 0) = 1.0000 CPU: 4 x Intel(R) Core(TM) i7-6700K CPU @ 4.00GHz Hyperthreading: on Also a speedup on "COMP=gcc", courtesy of Torom once again Result of 50 runs base (...tockfish_gcc) = 966033 +/- 1574 test (...max-less_gcc) = 983319 +/- 1513 diff = +17286 +/- 2515 speedup = +0.0179 P(speedup > 0) = 1.0000 CPU: 4 x Intel(R) Core(TM) i7-6700K CPU @ 4.00GHz Hyperthreading: on closes official-stockfish#5282 Passed STC: LLR: 2.96 (-2.94,2.94) <0.00,2.00> Total: 67712 W: 17715 L: 17358 D: 32639 Ptnml(0-2): 225, 7472, 18140, 7759, 260 https://tests.stockfishchess.org/tests/view/664c1d75830eb9f886616906 No functional change
looks good, but this requires modifying the network, and renders all others silently incompatible, as far as I understand. I'd instead multiply the weights and biases within the engine, and think of a way to version this change within the network, should we decide to change it in the trainer. I believe feature with index 0 may be unused in all sound feature sets, so we could use that space potentially |
This speedup was first inspired by a comment by @AndyGrant on my recent PR "If mullo_epi16 would preserve the signedness, then this could be used to remove 50% of the max operations during the halfkp-pairwise mat-mul relu deal." That got me thinking, because although mullo_epi16 did not preserve the signedness, mulhi_epi16 did, and so we could shift left and then use mulhi_epi16, instead of shifting right after the mullo. However, due to some issues with shifting into the sign bit, the FT weights and biases had to be multiplied by 2 for the optimisation to work. In the future we can increase the quantisation number in the FT to 255 (instead of 2x127=254) and also train a net from scratch to make use of the extra bit (currently all the weights and biases are even) Speedup on "Arch=x86-64-bmi2 COMP=clang", courtesy of @Torom Result of 50 runs base (...es/stockfish) = 962946 +/- 1202 test (...ise-max-less) = 979696 +/- 1084 diff = +16750 +/- 1794 speedup = +0.0174 P(speedup > 0) = 1.0000 CPU: 4 x Intel(R) Core(TM) i7-6700K CPU @ 4.00GHz Hyperthreading: on Also a speedup on "COMP=gcc", courtesy of Torom once again Result of 50 runs base (...tockfish_gcc) = 966033 +/- 1574 test (...max-less_gcc) = 983319 +/- 1513 diff = +17286 +/- 2515 speedup = +0.0179 P(speedup > 0) = 1.0000 CPU: 4 x Intel(R) Core(TM) i7-6700K CPU @ 4.00GHz Hyperthreading: on closes official-stockfish#5282 Passed STC: LLR: 2.96 (-2.94,2.94) <0.00,2.00> Total: 67712 W: 17715 L: 17358 D: 32639 Ptnml(0-2): 225, 7472, 18140, 7759, 260 https://tests.stockfishchess.org/tests/view/664c1d75830eb9f886616906 No functional change
Have moved it into the engine |
This speedup was first inspired by a comment by @AndyGrant on my recent PR "If mullo_epi16 would preserve the signedness, then this could be used to remove 50% of the max operations during the halfkp-pairwise mat-mul relu deal." That got me thinking, because although mullo_epi16 did not preserve the signedness, mulhi_epi16 did, and so we could shift left and then use mulhi_epi16, instead of shifting right after the mullo. However, due to some issues with shifting into the sign bit, the FT weights and biases had to be multiplied by 2 for the optimisation to work. Speedup on "Arch=x86-64-bmi2 COMP=clang", courtesy of @Torom Result of 50 runs base (...es/stockfish) = 962946 +/- 1202 test (...ise-max-less) = 979696 +/- 1084 diff = +16750 +/- 1794 speedup = +0.0174 P(speedup > 0) = 1.0000 CPU: 4 x Intel(R) Core(TM) i7-6700K CPU @ 4.00GHz Hyperthreading: on Also a speedup on "COMP=gcc", courtesy of Torom once again Result of 50 runs base (...tockfish_gcc) = 966033 +/- 1574 test (...max-less_gcc) = 983319 +/- 1513 diff = +17286 +/- 2515 speedup = +0.0179 P(speedup > 0) = 1.0000 CPU: 4 x Intel(R) Core(TM) i7-6700K CPU @ 4.00GHz Hyperthreading: on closes official-stockfish#5282 Passed STC: LLR: 2.96 (-2.94,2.94) <0.00,2.00> Total: 67712 W: 17715 L: 17358 D: 32639 Ptnml(0-2): 225, 7472, 18140, 7759, 260 https://tests.stockfishchess.org/tests/view/664c1d75830eb9f886616906 No functional change
This speedup was first inspired by a comment by @AndyGrant on my recent PR "If mullo_epi16 would preserve the signedness, then this could be used to remove 50% of the max operations during the halfkp-pairwise mat-mul relu deal." That got me thinking, because although mullo_epi16 did not preserve the signedness, mulhi_epi16 did, and so we could shift left and then use mulhi_epi16, instead of shifting right after the mullo. However, due to some issues with shifting into the sign bit, the FT weights and biases had to be multiplied by 2 for the optimisation to work. Speedup on "Arch=x86-64-bmi2 COMP=clang", courtesy of @Torom Result of 50 runs base (...es/stockfish) = 962946 +/- 1202 test (...ise-max-less) = 979696 +/- 1084 diff = +16750 +/- 1794 speedup = +0.0174 P(speedup > 0) = 1.0000 CPU: 4 x Intel(R) Core(TM) i7-6700K CPU @ 4.00GHz Hyperthreading: on Also a speedup on "COMP=gcc", courtesy of Torom once again Result of 50 runs base (...tockfish_gcc) = 966033 +/- 1574 test (...max-less_gcc) = 983319 +/- 1513 diff = +17286 +/- 2515 speedup = +0.0179 P(speedup > 0) = 1.0000 CPU: 4 x Intel(R) Core(TM) i7-6700K CPU @ 4.00GHz Hyperthreading: on closes official-stockfish#5282 Passed STC: LLR: 2.96 (-2.94,2.94) <0.00,2.00> Total: 67712 W: 17715 L: 17358 D: 32639 Ptnml(0-2): 225, 7472, 18140, 7759, 260 https://tests.stockfishchess.org/tests/view/664c1d75830eb9f886616906 No functional change
we could potentially test if the additional precision matters by randomly altering all affected weights by a value from [-1, 0, 1] and see the Elo impact |
Trying something like that with this test https://tests.stockfishchess.org/tests/view/665176bca86388d5e27da95f Edit: the test description is wrong, it rounds up if magnitude > 192, not 255 |
@cj5716 Can you say a bit more about this? I naively thought this https://tests.stockfishchess.org/tests/view/665244aaa86388d5e27da999 would be non functional and get rid of the load scaling but clearly not. |
127 == 0b0000000001111111 And what if we use mulhi_epu16 instead? In this case, we will have to add the lower-side clip for the |
Makes sense. Thanks! The pre multiplication is clever to avoid the issue. As you mentioned if we move this to the trainer and train the weights using the larger range we may get some benefit from better resolution. Pre multiplying by 4 also works |
Should note that in theory you will be adding up to 31 weights (1 for every piece relation, except the kings are combined as one). Any weights above 32767/31 = 1057 are prone to overflow. If sum(biggest-31-weights) > 32767 or sum (smallest-31-weights) < -32768 for an individual neuron, then you have issues in theory. |
yea, we would need to add an entry for weight clipping for the first layer, careful not to touch PSQT https://github.com/official-stockfish/nnue-pytorch/blob/a32432ec99859b7a8583e8f8f4ca051fd4b3dab0/model.py#L156 |
So in theory we could already have a problem because some of our weights are above 1057. On the other hand it's extremely unlikely this is actually happening in practice and constraining the weights to below 1057 could hurt elo. It would be possible to check no relevant combinations of 31 weights add to over 32767 at load time. |
I suppose a "band-aid" solution would be to simply switch all the accumulator changes to adds and subs instead of add and sub? Also, did we have this problem before? |
I think that is a very good band-aid fix, and might let me make use of this optimization in Torch, while I try to take back the reigns on network training. With adds/subs instead of add/sub, your new fear is to have a series of inputs cause you to cap out, and then a series after to get you back BELOW 127, or 254/255 in Stockfish's case now. If you pretend that weights are truly random, and the order they get added together is random, it seems exceptionally unlikely you'll run into this case.
Having 31+ weights that are >= 1057 is a prerequisite for being able to overflow. So you probably could in that sense. But really you need 31 weights that all contribute to the same index of the accumulator, AND can be active at the same time. So take all the accum weights, and split them up based on the output neuron. Next question is do you have 31+ weights there that can exceed 1057? Well we know we can only have 16 pieces of each colour, so you need to look at those ones. ... and they all have to be for the same King sq So at the end of the day, the math to say "Can I actually overflow" is quite complicated IMO. Perhaps I will write something up in python that works for Torch, and I can share it with you Cj. |
It might not be a good solution actually, since adds and subs requires more specialized execution ports, at least on zen, lowering the throughput of the intruction. I don't know what Intel does, but the intrinsics guides notes a dropping in throughput there as well, IE fewer execution ports present for the operations. The following is probably good enough to convince yourselves for Stockfish... you look at chunks of 64x11 weights, IE King Squares, for each output neuron. If you want to get really pedantic, there are times where you can add more than 31 inputs at once, since you are in the midst of removing another. IE suppose your Finny table has 31 inputs added. Then the order of these operations technically matters:
|
I'll see how we can handle this, hopefully all goes well |
This speedup was first inspired by a comment by @AndyGrant on my recent PR "If mullo_epi16 would preserve the signedness, then this could be used to remove 50% of the max operations during the halfkp-pairwise mat-mul relu deal."
That got me thinking, because although mullo_epi16 did not preserve the signedness, mulhi_epi16 did, and so we could shift left and then use mulhi_epi16, instead of shifting right after the mullo.
However, due to some issues with shifting into the sign bit, the FT weights and biases had to be multiplied by 2 for the optimisation to work.
Speedup on "Arch=x86-64-bmi2 COMP=clang", courtesy of @Torom
Result of 50 runs
base (...es/stockfish) = 962946 +/- 1202
test (...ise-max-less) = 979696 +/- 1084
diff = +16750 +/- 1794
speedup = +0.0174
P(speedup > 0) = 1.0000
CPU: 4 x Intel(R) Core(TM) i7-6700K CPU @ 4.00GHz
Hyperthreading: on
Also a speedup on "COMP=gcc", courtesy of Torom once again
Result of 50 runs
base (...tockfish_gcc) = 966033 +/- 1574
test (...max-less_gcc) = 983319 +/- 1513
diff = +17286 +/- 2515
speedup = +0.0179
P(speedup > 0) = 1.0000
CPU: 4 x Intel(R) Core(TM) i7-6700K CPU @ 4.00GHz
Hyperthreading: on
closes #5282
Passed STC:
LLR: 2.96 (-2.94,2.94) <0.00,2.00>
Total: 67712 W: 17715 L: 17358 D: 32639
Ptnml(0-2): 225, 7472, 18140, 7759, 260
https://tests.stockfishchess.org/tests/view/664c1d75830eb9f886616906
No functional change