Stockfish now uses a neural network for position evaluation. The structure of this neural network was introduced for Shogi by Yu Nasu in the paper dubbed "Efficiently updatable neural network - NNUE". Unfortunately it is in Japanese.
It is a fully connected neural network with four layers. The first layer receives an encoded chess position. The second and third are hidden layers and then there is final output layer that gives the evaluation.
The input layer receives a chess position encoded as a "HalfKP" structure, and this is where I am completely lost. A picture is available here.
The encoding seems to work like this. Suppose we have the starting position. We first consider only the white pieces. We encode the position by always considering the position of the white king together with a white non-king piece for each square. The resulting value is then either '1' or '0'.
Consider the starting position. We have
King on a1, Pawn on a1 -> 0
King on a1, Pawn on a2 -> 0
...
King on e1, Pawn on a2 -> 1
...
King on e1, Pawn on e2 -> 1
...
and so on. This input is fully connected to the next layer. Then we do the same for the black pieces.
Question 1.) Is my understanding correct?
Suppose we have the move e2e4
. There are only two inputs which change:
King on e1, Pawn on e2
changes from 1 to 0King on e1, Pawn on e4
changes from 0 to 1
There is apparently some efficiency gain here claimed in the original paper, but I do not see where. After all, the two nodes above are connected to every node in the second layer, so we have to update all second layer nodes.
Question 2.) Why is this efficient?
An encoding that would be much more straight-forward would be to simply use bits to indicate positions of the pieces, similar to bitboards.
King on a1 -> 0
...
King on e1 -> 1
...
Pawn on e2 -> 1
Pawn on e4 -> 0
If we use such an input encoding, we have less input nodes. Also updating for the move e2e4
just changes two input nodes. Such input seems to be common in other approaches, like AlphaZero and Lc0.
Question 3.) Why does one not use such a much easier encoding? Why do we use combinations of King + Piece? What do we gain here?
Question 4.) The first layer uses 16 bit integers, the next layers 8 bit integers. What is the reason for this choice? Obviously we need to limit the range to operate with fixed-point arithmetic due to memory constraints, but why 16 and 8, and not 16 and 16, or 32bit and 32bit?
The first half of the input layer (for white) is fully connected to the first 256 nodes of the second layer; the second half of the input (for black) is fully connected to the latter 256 nodes of the second layer.
Question 5.) Why do we consider the white and black pieces separately? What is the benefit? What is the so-called (full) KP
, and what is the relation to HalfKP
?
Question 6.) Is it possible to illustrate the update and efficiency gain with the above e2e4
example?