diff --git a/src_files/eval.cpp b/src_files/eval.cpp index 3751a15..59e99e7 100644 --- a/src_files/eval.cpp +++ b/src_files/eval.cpp @@ -74,7 +74,9 @@ using avx_register_type_32 = int32x4_t; #define avx_max_epi16(a, b) (vmaxq_s16(a, b)) #endif +#ifndef NO_EMBED_NET INCBIN(Eval, EVALFILE); +#endif inline int32_t sumRegisterEpi32(avx_register_type_32& reg) { // first summarize in case of avx512 registers into one 256 bit register @@ -104,6 +106,54 @@ inline int32_t sumRegisterEpi32(avx_register_type_32& reg) { #endif } +#ifdef NO_EMBED_NET +#include +bool nn::networkLoaded = false; +static constexpr long NETWORK_FILE_SIZE = + (long) (INPUT_SIZE * HIDDEN_SIZE * sizeof(int16_t) + HIDDEN_SIZE * sizeof(int16_t) + + HIDDEN_DSIZE * OUTPUT_SIZE * sizeof(int16_t) + OUTPUT_SIZE * sizeof(int32_t)); + +bool nn::loadNetwork(const char* path, std::string& err) { + FILE* f = std::fopen(path, "rb"); + if (!f) { + err = "cannot open file"; + return false; + } + std::fseek(f, 0, SEEK_END); + long size = std::ftell(f); + std::fseek(f, 0, SEEK_SET); + if (size != NETWORK_FILE_SIZE) { + std::fclose(f); + err = "wrong file size " + std::to_string(size) + ", expected " + std::to_string(NETWORK_FILE_SIZE); + return false; + } + bool ok = std::fread(inputWeights, sizeof(int16_t), INPUT_SIZE * HIDDEN_SIZE, f) == (size_t) (INPUT_SIZE * HIDDEN_SIZE) + && std::fread(inputBias, sizeof(int16_t), HIDDEN_SIZE, f) == (size_t) HIDDEN_SIZE + && std::fread(hiddenWeights, sizeof(int16_t), HIDDEN_DSIZE * OUTPUT_SIZE, f) == (size_t) (HIDDEN_DSIZE * OUTPUT_SIZE) + && std::fread(hiddenBias, sizeof(int32_t), OUTPUT_SIZE, f) == (size_t) OUTPUT_SIZE; + std::fclose(f); + if (!ok) { + std::memset(inputWeights, 0, sizeof(inputWeights)); + std::memset(inputBias, 0, sizeof(inputBias)); + std::memset(hiddenWeights, 0, sizeof(hiddenWeights)); + std::memset(hiddenBias, 0, sizeof(hiddenBias)); + err = "read error"; + return false; + } + networkLoaded = true; + return true; +} + +void nn::init() { + // weights stay zero until EvalFile is set +} +#else +bool nn::networkLoaded = true; +bool nn::loadNetwork(const char*, std::string& err) { + err = "this build has the net built in"; + return false; +} + void nn::init() { int memoryIndex = 0; std::memcpy(inputWeights, &gEvalData[memoryIndex], INPUT_SIZE * HIDDEN_SIZE * sizeof(int16_t)); @@ -116,6 +166,7 @@ void nn::init() { std::memcpy(hiddenBias, &gEvalData[memoryIndex], OUTPUT_SIZE * sizeof(int32_t)); memoryIndex += OUTPUT_SIZE * sizeof(int32_t); } +#endif int nn::index(bb::PieceType pieceType, bb::Color pieceColor, bb::Square square, bb::Color view, bb::Square kingSquare) { diff --git a/src_files/eval.h b/src_files/eval.h index c0a22bd..4b1d159 100644 --- a/src_files/eval.h +++ b/src_files/eval.h @@ -29,6 +29,7 @@ #include #endif #include +#include #include #define INPUT_SIZE (bb::N_PIECE_TYPES * bb::N_SQUARES * 2 * 16) @@ -61,6 +62,10 @@ extern int32_t hiddenBias [OUTPUT_SIZE]; // initialise and load the weights void init(); +// Rama Chess patch: load the net from a file (UCI option EvalFile) +bool loadNetwork(const char* path, std::string& err); +extern bool networkLoaded; + // computes the index for a piece (piece type) and its color on the specified square // also takes the view from with we view at the board as well as the king square of the view side [[nodiscard]] int index(bb::PieceType pieceType, bb::Color pieceColor, bb::Square square, diff --git a/src_files/uci.cpp b/src_files/uci.cpp index 9122ad3..9b74d5c 100644 --- a/src_files/uci.cpp +++ b/src_files/uci.cpp @@ -118,6 +118,9 @@ void uci::mainloop(int argc, char* argv[]) { void uci::uci() { std::cout << "id name Koivisto " << MAJOR_VERSION << "." << MINOR_VERSION << std::endl; std::cout << "id author K. Kahre, F. Eggers" << std::endl; +#ifdef NO_EMBED_NET + std::cout << "option name EvalFile type string default " << std::endl; +#endif std::cout << "option name Hash type spin default 16 min 1 max " << maxTTSize() << std::endl; std::cout << "option name Threads type spin default 1 min 1 max " << MAX_THREADS << std::endl; std::cout << "option name OwnBook type check default false" << std::endl; @@ -221,8 +224,33 @@ void uci::processCommand(std::string str) { const std::string name = getValue(split, "name"); const std::string value = getValue(split, "value"); +#ifdef NO_EMBED_NET + if (name == "EvalFile") { + // take everything after " value " so paths with spaces work + std::string path = value; + size_t pos = str.find(" value "); + if (pos != std::string::npos) + { std::string rest = str.substr(pos + 7); path = trim(rest); } + uci::stop(); + std::string err; + if (nn::loadNetwork(path.c_str(), err)) { + board = Board(); + searchObject.clearHash(); + searchObject.clearHistory(); + std::cout << "info string EvalFile loaded: " << path << std::endl; + } else { + std::cout << "info string ERROR: EvalFile " << path << ": " << err << std::endl; + } + return; + } +#endif uci::set_option(name, value); } else if (split.at(0) == "go") { + if (!nn::networkLoaded) { + std::cout << "info string ERROR: no net loaded, send setoption name EvalFile value first" << std::endl; + std::cout << "bestmove 0000" << std::endl; + return; + } go(split, str); } else if (split.at(0) == "stop") { uci::stop(); @@ -267,6 +295,10 @@ void uci::processCommand(std::string str) { uci::eval(); } else if (split.at(0) == "bench"){ + if (!nn::networkLoaded) { + std::cout << "info string ERROR: no net loaded, send setoption name EvalFile value first" << std::endl; + return; + } bench(); } else if (split.at(0) == "exit" || split.at(0) == "quit"){ exit(0);