Skip to content
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

Dual NNUE with L1-128 smallnet #4915

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
32 changes: 20 additions & 12 deletions src/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -806,7 +806,7 @@ help:
@echo "help > Display architecture details"
@echo "profile-build > standard build with profile-guided optimization"
@echo "build > skip profile-guided optimization"
@echo "net > Download the default nnue net"
@echo "net > Download the default nnue nets"
@echo "strip > Strip executable"
@echo "install > Install executable"
@echo "clean > Clean up"
Expand Down Expand Up @@ -922,16 +922,7 @@ profileclean:
@rm -f stockfish.res
@rm -f ./-lstdc++.res

# set up shell variables for the net stuff
netvariables:
$(eval nnuenet := $(shell grep EvalFileDefaultName evaluate.h | grep define | sed 's/.*\(nn-[a-z0-9]\{12\}.nnue\).*/\1/'))
$(eval nnuedownloadurl1 := https://tests.stockfishchess.org/api/nn/$(nnuenet))
$(eval nnuedownloadurl2 := https://github.com/official-stockfish/networks/raw/master/$(nnuenet))
$(eval curl_or_wget := $(shell if hash curl 2>/dev/null; then echo "curl -skL"; elif hash wget 2>/dev/null; then echo "wget -qO-"; fi))
$(eval shasum_command := $(shell if hash shasum 2>/dev/null; then echo "shasum -a 256 "; elif hash sha256sum 2>/dev/null; then echo "sha256sum "; fi))

# evaluation network (nnue)
net: netvariables
define fetch_network
@echo "Default net: $(nnuenet)"
@if [ "x$(curl_or_wget)" = "x" ]; then \
echo "Neither curl nor wget is installed. Install one of these tools unless the net has been downloaded manually"; \
Expand Down Expand Up @@ -966,7 +957,24 @@ net: netvariables
if [ "$(nnuenet)" = "nn-"`$(shasum_command) $(nnuenet) | cut -c1-12`".nnue" ]; then \
echo "Network validated"; break; \
fi; \
fi; \
fi;
endef

# set up shell variables for the net stuff
define netvariables
$(eval nnuenet := $(shell grep $(1) evaluate.h | grep define | sed 's/.*\(nn-[a-z0-9]\{12\}.nnue\).*/\1/'))
$(eval nnuedownloadurl1 := https://tests.stockfishchess.org/api/nn/$(nnuenet))
$(eval nnuedownloadurl2 := https://github.com/official-stockfish/networks/raw/master/$(nnuenet))
$(eval curl_or_wget := $(shell if hash curl 2>/dev/null; then echo "curl -skL"; elif hash wget 2>/dev/null; then echo "wget -qO-"; fi))
$(eval shasum_command := $(shell if hash shasum 2>/dev/null; then echo "shasum -a 256 "; elif hash sha256sum 2>/dev/null; then echo "sha256sum "; fi))
endef

# evaluation network (nnue)
net:
$(call netvariables, EvalFileDefaultNameBig)
$(call fetch_network)
$(call netvariables, EvalFileDefaultNameSmall)
$(call fetch_network)

format:
$(CLANG-FORMAT) -i $(SRCS) $(HEADERS) -style=file
Expand Down
163 changes: 92 additions & 71 deletions src/evaluate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include <cmath>
#include <cstdlib>
#include <fstream>
#include <initializer_list>
#include <iomanip>
#include <iostream>
#include <sstream>
Expand All @@ -31,6 +32,7 @@
#include "incbin/incbin.h"
#include "misc.h"
#include "nnue/evaluate_nnue.h"
#include "nnue/nnue_architecture.h"
#include "position.h"
#include "thread.h"
#include "types.h"
Expand All @@ -44,19 +46,25 @@
// const unsigned int gEmbeddedNNUESize; // the size of the embedded file
// Note that this does not work in Microsoft Visual Studio.
#if !defined(_MSC_VER) && !defined(NNUE_EMBEDDING_OFF)
INCBIN(EmbeddedNNUE, EvalFileDefaultName);
INCBIN(EmbeddedNNUEBig, EvalFileDefaultNameBig);
INCBIN(EmbeddedNNUESmall, EvalFileDefaultNameSmall);
#else
const unsigned char gEmbeddedNNUEData[1] = {0x0};
const unsigned char* const gEmbeddedNNUEEnd = &gEmbeddedNNUEData[1];
const unsigned int gEmbeddedNNUESize = 1;
const unsigned char gEmbeddedNNUEBigData[1] = {0x0};
const unsigned char* const gEmbeddedNNUEBigEnd = &gEmbeddedNNUEBigData[1];
const unsigned int gEmbeddedNNUEBigSize = 1;
const unsigned char gEmbeddedNNUESmallData[1] = {0x0};
const unsigned char* const gEmbeddedNNUESmallEnd = &gEmbeddedNNUESmallData[1];
const unsigned int gEmbeddedNNUESmallSize = 1;
#endif


namespace Stockfish {

namespace Eval {

std::string currentEvalFileName = "None";
std::string currentEvalFileName[2] = {"None", "None"};
const std::string EvFiles[2] = {"EvalFile", "EvalFileSmall"};
const std::string EvFileNames[2] = {EvalFileDefaultNameBig, EvalFileDefaultNameSmall};

// Tries to load a NNUE network at startup time, or when the engine
// receives a UCI command "setoption name EvalFile value nn-[a-z0-9]{12}.nnue"
Expand All @@ -67,84 +75,96 @@ std::string currentEvalFileName = "None";
// variable to have the engine search in a special directory in their distro.
void NNUE::init() {

std::string eval_file = std::string(Options["EvalFile"]);
if (eval_file.empty())
eval_file = EvalFileDefaultName;
for (NetSize netSize : {Big, Small})
{
// change after fishtest supports EvalFileSmall
std::string eval_file =
std::string(netSize == Small ? EvalFileDefaultNameSmall : Options[EvFiles[netSize]]);
if (eval_file.empty())
eval_file = EvFileNames[netSize];

#if defined(DEFAULT_NNUE_DIRECTORY)
std::vector<std::string> dirs = {"<internal>", "", CommandLine::binaryDirectory,
stringify(DEFAULT_NNUE_DIRECTORY)};
std::vector<std::string> dirs = {"<internal>", "", CommandLine::binaryDirectory,
stringify(DEFAULT_NNUE_DIRECTORY)};
#else
std::vector<std::string> dirs = {"<internal>", "", CommandLine::binaryDirectory};
std::vector<std::string> dirs = {"<internal>", "", CommandLine::binaryDirectory};
#endif

for (const std::string& directory : dirs)
if (currentEvalFileName != eval_file)
for (const std::string& directory : dirs)
{
if (directory != "<internal>")
{
std::ifstream stream(directory + eval_file, std::ios::binary);
if (NNUE::load_eval(eval_file, stream))
currentEvalFileName = eval_file;
}

if (directory == "<internal>" && eval_file == EvalFileDefaultName)
if (currentEvalFileName[netSize] != eval_file)
{
// C++ way to prepare a buffer for a memory stream
class MemoryBuffer: public std::basic_streambuf<char> {
public:
MemoryBuffer(char* p, size_t n) {
setg(p, p, p + n);
setp(p, p + n);
}
};

MemoryBuffer buffer(
const_cast<char*>(reinterpret_cast<const char*>(gEmbeddedNNUEData)),
size_t(gEmbeddedNNUESize));
(void) gEmbeddedNNUEEnd; // Silence warning on unused variable

std::istream stream(&buffer);
if (NNUE::load_eval(eval_file, stream))
currentEvalFileName = eval_file;
if (directory != "<internal>")
{
std::ifstream stream(directory + eval_file, std::ios::binary);
if (NNUE::load_eval(eval_file, stream, netSize))
currentEvalFileName[netSize] = eval_file;
}

if (directory == "<internal>" && eval_file == EvFileNames[netSize])
{
// C++ way to prepare a buffer for a memory stream
class MemoryBuffer: public std::basic_streambuf<char> {
public:
MemoryBuffer(char* p, size_t n) {
setg(p, p, p + n);
setp(p, p + n);
}
};

MemoryBuffer buffer(
const_cast<char*>(reinterpret_cast<const char*>(
netSize == Small ? gEmbeddedNNUESmallData : gEmbeddedNNUEBigData)),
size_t(netSize == Small ? gEmbeddedNNUESmallSize : gEmbeddedNNUEBigSize));
(void) gEmbeddedNNUEBigEnd; // Silence warning on unused variable
(void) gEmbeddedNNUESmallEnd;

std::istream stream(&buffer);
if (NNUE::load_eval(eval_file, stream, netSize))
currentEvalFileName[netSize] = eval_file;
}
}
}
}
}

// Verifies that the last net used was loaded successfully
void NNUE::verify() {

std::string eval_file = std::string(Options["EvalFile"]);
if (eval_file.empty())
eval_file = EvalFileDefaultName;

if (currentEvalFileName != eval_file)
for (NetSize netSize : {Big, Small})
{
// change after fishtest supports EvalFileSmall
std::string eval_file =
std::string(netSize == Small ? EvalFileDefaultNameSmall : Options[EvFiles[netSize]]);
if (eval_file.empty())
eval_file = EvFileNames[netSize];

std::string msg1 =
"Network evaluation parameters compatible with the engine must be available.";
std::string msg2 = "The network file " + eval_file + " was not loaded successfully.";
std::string msg3 = "The UCI option EvalFile might need to specify the full path, "
"including the directory name, to the network file.";
std::string msg4 = "The default net can be downloaded from: "
"https://tests.stockfishchess.org/api/nn/"
+ std::string(EvalFileDefaultName);
std::string msg5 = "The engine will be terminated now.";

sync_cout << "info string ERROR: " << msg1 << sync_endl;
sync_cout << "info string ERROR: " << msg2 << sync_endl;
sync_cout << "info string ERROR: " << msg3 << sync_endl;
sync_cout << "info string ERROR: " << msg4 << sync_endl;
sync_cout << "info string ERROR: " << msg5 << sync_endl;

exit(EXIT_FAILURE);
}
if (currentEvalFileName[netSize] != eval_file)
{
std::string msg1 =
"Network evaluation parameters compatible with the engine must be available.";
std::string msg2 = "The network file " + eval_file + " was not loaded successfully.";
std::string msg3 = "The UCI option EvalFile might need to specify the full path, "
"including the directory name, to the network file.";
std::string msg4 = "The default net can be downloaded from: "
"https://tests.stockfishchess.org/api/nn/"
+ std::string(EvFileNames[netSize]);
std::string msg5 = "The engine will be terminated now.";

sync_cout << "info string ERROR: " << msg1 << sync_endl;
sync_cout << "info string ERROR: " << msg2 << sync_endl;
sync_cout << "info string ERROR: " << msg3 << sync_endl;
sync_cout << "info string ERROR: " << msg4 << sync_endl;
sync_cout << "info string ERROR: " << msg5 << sync_endl;

exit(EXIT_FAILURE);
}

sync_cout << "info string NNUE evaluation using " << eval_file << sync_endl;
sync_cout << "info string NNUE evaluation using " << eval_file << sync_endl;
}
}
}


// Returns a static, purely materialistic evaluation of the position from
// the point of view of the given color. It can be divided by PawnValue to get
// an approximation of the material advantage on the board in terms of pawns.
Expand All @@ -163,18 +183,19 @@ Value Eval::evaluate(const Position& pos) {
int v;
Color stm = pos.side_to_move();
int shuffling = pos.rule50_count();
int simpleEval = simple_eval(pos, stm) + (int(pos.key() & 7) - 3);

bool lazy = std::abs(simpleEval) >= RookValue + KnightValue + 16 * shuffling * shuffling
+ std::abs(pos.this_thread()->bestValue)
+ std::abs(pos.this_thread()->rootSimpleEval);
int simpleEval = simple_eval(pos, stm);

bool lazy = std::abs(simpleEval) > 2300;
if (lazy)
v = simpleEval;
else
{
int nnueComplexity;
Value nnue = NNUE::evaluate(pos, true, &nnueComplexity);
bool smallNet = std::abs(simpleEval) > 1100;

int nnueComplexity;

Value nnue = smallNet ? NNUE::evaluate<NNUE::Small>(pos, true, &nnueComplexity)
: NNUE::evaluate<NNUE::Big>(pos, true, &nnueComplexity);

int optimism = pos.this_thread()->optimism[stm];

Expand Down Expand Up @@ -217,7 +238,7 @@ std::string Eval::trace(Position& pos) {
ss << std::showpoint << std::showpos << std::fixed << std::setprecision(2) << std::setw(15);

Value v;
v = NNUE::evaluate(pos, false);
v = NNUE::evaluate<NNUE::Big>(pos, false);
v = pos.side_to_move() == WHITE ? v : -v;
ss << "NNUE evaluation " << 0.01 * UCI::to_cp(v) << " (white side)\n";

Expand Down
5 changes: 3 additions & 2 deletions src/evaluate.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,13 @@ std::string trace(Position& pos);
int simple_eval(const Position& pos, Color c);
Value evaluate(const Position& pos);

extern std::string currentEvalFileName;
extern std::string currentEvalFileName[2];

// The default net name MUST follow the format nn-[SHA256 first 12 digits].nnue
// for the build process (profile-build and fishtest) to work. Do not change the
// name of the macro, as it is used in the Makefile.
#define EvalFileDefaultName "nn-b1e55edbea57.nnue"
#define EvalFileDefaultNameBig "nn-b1e55edbea57.nnue"
#define EvalFileDefaultNameSmall "nn-c01dc0ffeede.nnue"

namespace NNUE {

Expand Down
Loading