Update NNUE architecture to SFNNv14 and net nn-7bf13f9655c8.nnue

[STC](https://tests.stockfishchess.org/tests/live_elo/69cb991bc025c305b7daa219)

LLR: 2.97 (-2.94,2.94) <0.00,2.00>
Total: 47520 W: 12558 L: 12219 D: 22743
Ptnml(0-2): 190, 5474, 12102, 5795, 199

[LTC](https://tests.stockfishchess.org/tests/live_elo/69cc6b42731dfb72d2e92128)

LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 123756 W: 31996 L: 31497 D: 60263
Ptnml(0-2): 81, 13512, 34221, 13955, 109

Adds features for pawns pushing against other pawns. For indexing, we
use the existing threats feature set by adding the forward square to the
squares threatened by a pawn. This threat is only enabled when another
pawn occupies that square. We then add appropriate logic changes in
`update_piece_threats` and `features/full_threats.cpp`.

The wonderful Ciekce (of Stormphrax) and peregrine (of Reckless) also
had similar ideas with adding forward pawn movements to TI, and I
appreciate their giving me motivation to figure out `nnue-pytorch` and
test it.

closes https://github.com/official-stockfish/Stockfish/pull/6694

Bench: 2926703
This commit is contained in:
anematode
2026-04-02 20:32:43 +02:00
committed by Disservin
parent 8a1b0f8b04
commit 5eeca7392e
5 changed files with 55 additions and 7 deletions
+15
View File
@@ -155,6 +155,9 @@ constexpr Bitboard pawn_attacks_bb(Bitboard b) {
: shift<SOUTH_WEST>(b) | shift<SOUTH_EAST>(b); : shift<SOUTH_WEST>(b) | shift<SOUTH_EAST>(b);
} }
constexpr Bitboard pawn_single_push_bb(Color c, Bitboard b) {
return c == WHITE ? shift<NORTH>(b) : shift<SOUTH>(b);
}
// Returns a bitboard representing an entire line (from board edge // Returns a bitboard representing an entire line (from board edge
// to board edge) that intersects the two given squares. If the given squares // to board edge) that intersects the two given squares. If the given squares
@@ -397,6 +400,18 @@ inline constexpr auto PseudoAttacks = []() constexpr {
return attacks; return attacks;
}(); }();
inline constexpr auto PawnPushOrAttacks = []() constexpr {
std::array<std::array<Bitboard, SQUARE_NB>, COLOR_NB> attacks{};
for (Square s1 = SQ_A1; s1 <= SQ_H8; ++s1)
{
attacks[WHITE][s1] = pawn_single_push_bb(WHITE, square_bb(s1)) | PseudoAttacks[WHITE][s1];
attacks[BLACK][s1] = pawn_single_push_bb(BLACK, square_bb(s1)) | PseudoAttacks[BLACK][s1];
}
return attacks;
}();
// Returns the pseudo attacks of the given piece type // Returns the pseudo attacks of the given piece type
// assuming an empty board. // assuming an empty board.
+1 -1
View File
@@ -33,7 +33,7 @@ namespace Eval {
// for the build process (profile-build and fishtest) to work. Do not change the // for the build process (profile-build and fishtest) to work. Do not change the
// name of the macro or the location where this macro is defined, as it is used // name of the macro or the location where this macro is defined, as it is used
// in the Makefile/Fishtest. // in the Makefile/Fishtest.
#define EvalFileDefaultNameBig "nn-9a0cc2a62c52.nnue" #define EvalFileDefaultNameBig "nn-7bf13f9655c8.nnue"
#define EvalFileDefaultNameSmall "nn-47fc8b7fff06.nnue" #define EvalFileDefaultNameSmall "nn-47fc8b7fff06.nnue"
namespace NNUE { namespace NNUE {
+19 -3
View File
@@ -21,6 +21,7 @@
#include "full_threats.h" #include "full_threats.h"
#include <array> #include <array>
#include <cassert>
#include <cstddef> #include <cstddef>
#include <cstdint> #include <cstdint>
#include <initializer_list> #include <initializer_list>
@@ -72,7 +73,7 @@ constexpr auto make_piece_indices_piece() {
for (Square from = SQ_A1; from <= SQ_H8; ++from) for (Square from = SQ_A1; from <= SQ_H8; ++from)
{ {
Bitboard attacks = PseudoAttacks[C][from]; Bitboard attacks = PawnPushOrAttacks[C][from];
for (Square to = SQ_A1; to <= SQ_H8; ++to) for (Square to = SQ_A1; to <= SQ_H8; ++to)
{ {
@@ -135,8 +136,8 @@ constexpr auto init_threat_offsets() {
else if (from >= SQ_A2 && from <= SQ_H7) else if (from >= SQ_A2 && from <= SQ_H7)
{ {
Bitboard attacks = (pieceIdx < 8) ? pawn_attacks_bb<WHITE>(square_bb(from)) Bitboard attacks =
: pawn_attacks_bb<BLACK>(square_bb(from)); (pieceIdx < 8) ? PawnPushOrAttacks[WHITE][from] : PawnPushOrAttacks[BLACK][from];
cumulativePieceOffset += constexpr_popcount(attacks); cumulativePieceOffset += constexpr_popcount(attacks);
} }
} }
@@ -209,6 +210,7 @@ inline sf_always_inline IndexType FullThreats::make_index(
void FullThreats::append_active_indices(Color perspective, const Position& pos, IndexList& active) { void FullThreats::append_active_indices(Color perspective, const Position& pos, IndexList& active) {
Square ksq = pos.square<KING>(perspective); Square ksq = pos.square<KING>(perspective);
Bitboard occupied = pos.pieces(); Bitboard occupied = pos.pieces();
Bitboard pawns = pos.pieces(PAWN);
for (Color color : {WHITE, BLACK}) for (Color color : {WHITE, BLACK})
{ {
@@ -248,6 +250,20 @@ void FullThreats::append_active_indices(Color perspective, const Position& pos,
if (index < Dimensions) if (index < Dimensions)
active.push_back(index); active.push_back(index);
} }
// Set of pawns which are prevented from movement by a pawn in front of them
Bitboard pushers = pawn_single_push_bb(~c, pawns) & pos.pieces(c, PAWN);
while (pushers)
{
Square from = pop_lsb(pushers);
Square to = from + pawn_push(c);
Piece attacked = pos.piece_on(to);
assert(type_of(attacked) == PAWN);
IndexType index = make_index(perspective, attacker, from, to, attacked, ksq);
if (index < Dimensions)
active.push_back(index);
}
} }
else else
{ {
+1 -1
View File
@@ -42,7 +42,7 @@ class FullThreats {
static constexpr std::uint32_t HashValue = 0x8f234cb8u; static constexpr std::uint32_t HashValue = 0x8f234cb8u;
// Number of feature dimensions // Number of feature dimensions
static constexpr IndexType Dimensions = 60144; static constexpr IndexType Dimensions = 60720;
// clang-format off // clang-format off
// Orient a square according to perspective (rotates by 180 for black) // Orient a square according to perspective (rotates by 180 for black)
+19 -2
View File
@@ -1265,8 +1265,25 @@ void Position::update_piece_threats(Piece pc,
Bitboard threatened = attacks_bb(pc, s, occupied) & occupiedNoK; Bitboard threatened = attacks_bb(pc, s, occupied) & occupiedNoK;
Bitboard incoming_threats = Bitboard incoming_threats =
(PseudoAttacks[KNIGHT][s] & knights) | (attacks_bb<PAWN>(s, WHITE) & blackPawns) (PseudoAttacks[KNIGHT][s] & knights) | (PseudoAttacks[KING][s] & kings);
| (attacks_bb<PAWN>(s, BLACK) & whitePawns) | (PseudoAttacks[KING][s] & kings);
// Compute both incoming and outgoing pawn threats. Incoming pawn pushers are only
// added if 'pc' is a pawn.
if (type_of(pc) == PAWN)
{
Bitboard whiteAttacks = PawnPushOrAttacks[WHITE][s];
Bitboard blackAttacks = PawnPushOrAttacks[BLACK][s];
threatened |= (color_of(pc) == WHITE ? whiteAttacks : blackAttacks) & pieces(PAWN);
incoming_threats |= whiteAttacks & blackPawns;
incoming_threats |= blackAttacks & whitePawns;
}
else
{
incoming_threats |=
(attacks_bb<PAWN>(s, WHITE) & blackPawns) | (attacks_bb<PAWN>(s, BLACK) & whitePawns);
}
#ifdef USE_AVX512ICL #ifdef USE_AVX512ICL
if constexpr (PutPiece) if constexpr (PutPiece)