PascalCase -> snake_case for consistency with the rest of the codebase.

This commit is contained in:
Tomasz Sobczyk
2020-10-14 22:42:58 +02:00
committed by nodchip
parent 2398d34e87
commit 146a6b056e
37 changed files with 844 additions and 737 deletions

View File

@@ -964,7 +964,7 @@ namespace Learner
// Lock the evaluation function so that it is not used during updating.
lock_guard<shared_timed_mutex> write_lock(nn_mutex);
Eval::NNUE::UpdateParameters();
Eval::NNUE::update_parameters();
}
++epoch;
@@ -998,7 +998,7 @@ namespace Learner
// loss calculation
calc_loss(thread_id, done);
Eval::NNUE::CheckHealth();
Eval::NNUE::check_health();
// Make a note of how far you have totaled.
sr.last_done = sr.total_done;
@@ -1127,7 +1127,7 @@ namespace Learner
learn_sum_entropy_win += learn_entropy_win;
learn_sum_entropy += learn_entropy;
Eval::NNUE::AddExample(pos, rootColor, ps, 1.0);
Eval::NNUE::add_example(pos, rootColor, ps, 1.0);
// Since the processing is completed, the counter of the processed number is incremented
sr.total_done++;
@@ -1194,7 +1194,7 @@ namespace Learner
{
cout << " < best (" << best_loss << "), accepted" << endl;
best_loss = latest_loss;
best_nn_directory = Path::Combine((std::string)Options["EvalSaveDir"], dir_name);
best_nn_directory = Path::combine((std::string)Options["EvalSaveDir"], dir_name);
trials = newbob_num_trials;
if (tot >= last_lr_drop + auto_lr_drop)
@@ -1207,13 +1207,13 @@ namespace Learner
{
cout << " < best (" << best_loss << "), accepted" << endl;
best_loss = latest_loss;
best_nn_directory = Path::Combine((std::string)Options["EvalSaveDir"], dir_name);
best_nn_directory = Path::combine((std::string)Options["EvalSaveDir"], dir_name);
trials = newbob_num_trials;
}
else
{
cout << " >= best (" << best_loss << "), rejected" << endl;
best_nn_directory = Path::Combine((std::string)Options["EvalSaveDir"], dir_name);
best_nn_directory = Path::combine((std::string)Options["EvalSaveDir"], dir_name);
if (--trials > 0 && !is_final)
{
@@ -1713,14 +1713,14 @@ namespace Learner
// Display learning game file
if (target_dir != "")
{
string kif_base_dir = Path::Combine(base_dir, target_dir);
string kif_base_dir = Path::combine(base_dir, target_dir);
namespace sys = std::filesystem;
sys::path p(kif_base_dir); // Origin of enumeration
std::for_each(sys::directory_iterator(p), sys::directory_iterator(),
[&](const sys::path& path) {
if (sys::is_regular_file(path))
filenames.push_back(Path::Combine(target_dir, path.filename().generic_string()));
filenames.push_back(Path::combine(target_dir, path.filename().generic_string()));
});
}
@@ -1814,7 +1814,7 @@ namespace Learner
// order so I'll reverse it here. I'm sorry.
for (auto it = filenames.rbegin(); it != filenames.rend(); ++it)
{
sr.filenames.push_back(Path::Combine(base_dir, *it));
sr.filenames.push_back(Path::combine(base_dir, *it));
}
}
@@ -1858,9 +1858,9 @@ namespace Learner
set_learning_search_limits();
cout << "init_training.." << endl;
Eval::NNUE::InitializeTraining(seed);
Eval::NNUE::SetBatchSize(nn_batch_size);
Eval::NNUE::SetOptions(nn_options);
Eval::NNUE::initialize_training(seed);
Eval::NNUE::set_batch_size(nn_batch_size);
Eval::NNUE::set_options(nn_options);
if (newbob_decay != 1.0 && !Options["SkipLoadingEval"]) {
// Save the current net to [EvalSaveDir]\original.
Eval::NNUE::save_eval("original");
@@ -1868,7 +1868,7 @@ namespace Learner
// Set the folder above to best_nn_directory so that the trainer can
// resotre the network parameters from the original net file.
learn_think.best_nn_directory =
Path::Combine(Options["EvalSaveDir"], "original");
Path::combine(Options["EvalSaveDir"], "original");
}
cout << "init done." << endl;
@@ -1925,7 +1925,7 @@ namespace Learner
// Start learning.
learn_think.go_think();
Eval::NNUE::FinalizeNet();
Eval::NNUE::finalize_net();
// Save once at the end.
learn_think.save(true);

View File

@@ -299,7 +299,7 @@ struct Path
{
// Combine the path name and file name and return it.
// If the folder name is not an empty string, append it if there is no'/' or'\\' at the end.
static std::string Combine(const std::string& folder, const std::string& filename)
static std::string combine(const std::string& folder, const std::string& filename)
{
if (folder.length() >= 1 && *folder.rbegin() != '/' && *folder.rbegin() != '\\')
return folder + "/" + filename;
@@ -308,7 +308,7 @@ struct Path
}
// Get the file name part (excluding the folder name) from the full path expression.
static std::string GetFileName(const std::string& path)
static std::string get_file_name(const std::string& path)
{
// I don't know which "\" or "/" is used.
auto path_index1 = path.find_last_of("\\") + 1;

View File

@@ -1,303 +1,338 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file)
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Stockfish is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
Stockfish is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// Code for calculating NNUE evaluation function
#include "evaluate_nnue.h"
#include "position.h"
#include "misc.h"
#include "uci.h"
#include "types.h"
#include <iostream>
#include <string>
#include <fstream>
#include <set>
#include "../position.h"
#include "../misc.h"
#include "../uci.h"
#include "../types.h"
#include "evaluate_nnue.h"
namespace Eval::NNUE {
const uint32_t kpp_board_index[PIECE_NB][COLOR_NB] = {
// convention: W - us, B - them
// viewed from other side, W and B are reversed
{ PS_NONE, PS_NONE },
{ PS_W_PAWN, PS_B_PAWN },
{ PS_W_KNIGHT, PS_B_KNIGHT },
{ PS_W_BISHOP, PS_B_BISHOP },
{ PS_W_ROOK, PS_B_ROOK },
{ PS_W_QUEEN, PS_B_QUEEN },
{ PS_W_KING, PS_B_KING },
{ PS_NONE, PS_NONE },
{ PS_NONE, PS_NONE },
{ PS_B_PAWN, PS_W_PAWN },
{ PS_B_KNIGHT, PS_W_KNIGHT },
{ PS_B_BISHOP, PS_W_BISHOP },
{ PS_B_ROOK, PS_W_ROOK },
{ PS_B_QUEEN, PS_W_QUEEN },
{ PS_B_KING, PS_W_KING },
{ PS_NONE, PS_NONE }
};
const uint32_t kpp_board_index[PIECE_NB][COLOR_NB] = {
// convention: W - us, B - them
// viewed from other side, W and B are reversed
{ PS_NONE, PS_NONE },
{ PS_W_PAWN, PS_B_PAWN },
{ PS_W_KNIGHT, PS_B_KNIGHT },
{ PS_W_BISHOP, PS_B_BISHOP },
{ PS_W_ROOK, PS_B_ROOK },
{ PS_W_QUEEN, PS_B_QUEEN },
{ PS_W_KING, PS_B_KING },
{ PS_NONE, PS_NONE },
{ PS_NONE, PS_NONE },
{ PS_B_PAWN, PS_W_PAWN },
{ PS_B_KNIGHT, PS_W_KNIGHT },
{ PS_B_BISHOP, PS_W_BISHOP },
{ PS_B_ROOK, PS_W_ROOK },
{ PS_B_QUEEN, PS_W_QUEEN },
{ PS_B_KING, PS_W_KING },
{ PS_NONE, PS_NONE }
};
// Input feature converter
LargePagePtr<FeatureTransformer> feature_transformer;
// Input feature converter
LargePagePtr<FeatureTransformer> feature_transformer;
// Evaluation function
AlignedPtr<Network> network;
// Evaluation function
AlignedPtr<Network> network;
// Evaluation function file name
std::string fileName;
// Evaluation function file name
std::string fileName;
// Saved evaluation function file name
std::string savedfileName = "nn.bin";
// Saved evaluation function file name
std::string savedfileName = "nn.bin";
// Get a string that represents the structure of the evaluation function
std::string GetArchitectureString() {
return "Features=" + FeatureTransformer::GetStructureString() +
",Network=" + Network::GetStructureString();
}
UseNNUEMode useNNUE;
std::string eval_file_loaded = "None";
namespace Detail {
// Initialize the evaluation function parameters
template <typename T>
void Initialize(AlignedPtr<T>& pointer) {
pointer.reset(reinterpret_cast<T*>(std_aligned_alloc(alignof(T), sizeof(T))));
std::memset(pointer.get(), 0, sizeof(T));
}
template <typename T>
void Initialize(LargePagePtr<T>& pointer) {
static_assert(alignof(T) <= 4096, "aligned_large_pages_alloc() may fail for such a big alignment requirement of T");
pointer.reset(reinterpret_cast<T*>(aligned_large_pages_alloc(sizeof(T))));
std::memset(pointer.get(), 0, sizeof(T));
}
// Read evaluation function parameters
template <typename T>
bool ReadParameters(std::istream& stream, T& reference) {
std::uint32_t header;
header = read_little_endian<std::uint32_t>(stream);
if (!stream || header != T::GetHashValue()) return false;
return reference.ReadParameters(stream);
}
// write evaluation function parameters
template <typename T>
bool WriteParameters(std::ostream& stream, const AlignedPtr<T>& pointer) {
constexpr std::uint32_t header = T::GetHashValue();
stream.write(reinterpret_cast<const char*>(&header), sizeof(header));
return pointer->WriteParameters(stream);
}
template <typename T>
bool WriteParameters(std::ostream& stream, const LargePagePtr<T>& pointer) {
constexpr std::uint32_t header = T::GetHashValue();
stream.write(reinterpret_cast<const char*>(&header), sizeof(header));
return pointer->WriteParameters(stream);
}
} // namespace Detail
// Initialize the evaluation function parameters
void Initialize() {
Detail::Initialize(feature_transformer);
Detail::Initialize(network);
}
// Read network header
bool ReadHeader(std::istream& stream, std::uint32_t* hash_value, std::string* architecture)
{
std::uint32_t version, size;
version = read_little_endian<std::uint32_t>(stream);
*hash_value = read_little_endian<std::uint32_t>(stream);
size = read_little_endian<std::uint32_t>(stream);
if (!stream || version != kVersion) return false;
architecture->resize(size);
stream.read(&(*architecture)[0], size);
return !stream.fail();
}
// write the header
bool WriteHeader(std::ostream& stream,
std::uint32_t hash_value, const std::string& architecture) {
stream.write(reinterpret_cast<const char*>(&kVersion), sizeof(kVersion));
stream.write(reinterpret_cast<const char*>(&hash_value), sizeof(hash_value));
const std::uint32_t size = static_cast<std::uint32_t>(architecture.size());
stream.write(reinterpret_cast<const char*>(&size), sizeof(size));
stream.write(architecture.data(), size);
return !stream.fail();
}
// Read network parameters
bool ReadParameters(std::istream& stream) {
std::uint32_t hash_value;
std::string architecture;
if (!ReadHeader(stream, &hash_value, &architecture)) return false;
if (hash_value != kHashValue) return false;
if (!Detail::ReadParameters(stream, *feature_transformer)) return false;
if (!Detail::ReadParameters(stream, *network)) return false;
return stream && stream.peek() == std::ios::traits_type::eof();
}
// write evaluation function parameters
bool WriteParameters(std::ostream& stream) {
if (!WriteHeader(stream, kHashValue, GetArchitectureString())) return false;
if (!Detail::WriteParameters(stream, feature_transformer)) return false;
if (!Detail::WriteParameters(stream, network)) return false;
return !stream.fail();
}
// Evaluation function. Perform differential calculation.
Value evaluate(const Position& pos) {
alignas(kCacheLineSize) TransformedFeatureType
transformed_features[FeatureTransformer::kBufferSize];
feature_transformer->Transform(pos, transformed_features);
alignas(kCacheLineSize) char buffer[Network::kBufferSize];
const auto output = network->Propagate(transformed_features, buffer);
return static_cast<Value>(output[0] / FV_SCALE);
}
// Load eval, from a file stream or a memory stream
bool load_eval(std::string name, std::istream& stream) {
Initialize();
fileName = name;
return ReadParameters(stream);
}
static UseNNUEMode nnue_mode_from_option(const UCI::Option& mode)
{
if (mode == "false")
return UseNNUEMode::False;
else if (mode == "true")
return UseNNUEMode::True;
else if (mode == "pure")
return UseNNUEMode::Pure;
return UseNNUEMode::False;
}
void init() {
useNNUE = nnue_mode_from_option(Options["Use NNUE"]);
if (Options["SkipLoadingEval"] || useNNUE == UseNNUEMode::False)
{
eval_file_loaded.clear();
return;
// Get a string that represents the structure of the evaluation function
std::string get_architecture_string() {
return "Features=" + FeatureTransformer::get_structure_string() +
",Network=" + Network::get_structure_string();
}
std::string eval_file = std::string(Options["EvalFile"]);
UseNNUEMode useNNUE;
std::string eval_file_loaded = "None";
namespace Detail {
// Initialize the evaluation function parameters
template <typename T>
void initialize(AlignedPtr<T>& pointer) {
pointer.reset(reinterpret_cast<T*>(std_aligned_alloc(alignof(T), sizeof(T))));
std::memset(pointer.get(), 0, sizeof(T));
}
template <typename T>
void initialize(LargePagePtr<T>& pointer) {
static_assert(alignof(T) <= 4096, "aligned_large_pages_alloc() may fail for such a big alignment requirement of T");
pointer.reset(reinterpret_cast<T*>(aligned_large_pages_alloc(sizeof(T))));
std::memset(pointer.get(), 0, sizeof(T));
}
// Read evaluation function parameters
template <typename T>
bool read_parameters(std::istream& stream, T& reference) {
std::uint32_t header;
header = read_little_endian<std::uint32_t>(stream);
if (!stream || header != T::get_hash_value())
return false;
return reference.read_parameters(stream);
}
// write evaluation function parameters
template <typename T>
bool write_parameters(std::ostream& stream, const AlignedPtr<T>& pointer) {
constexpr std::uint32_t header = T::get_hash_value();
stream.write(reinterpret_cast<const char*>(&header), sizeof(header));
return pointer->write_parameters(stream);
}
template <typename T>
bool write_parameters(std::ostream& stream, const LargePagePtr<T>& pointer) {
constexpr std::uint32_t header = T::get_hash_value();
stream.write(reinterpret_cast<const char*>(&header), sizeof(header));
return pointer->write_parameters(stream);
}
} // namespace Detail
// Initialize the evaluation function parameters
void initialize() {
Detail::initialize(feature_transformer);
Detail::initialize(network);
}
// Read network header
bool read_header(std::istream& stream, std::uint32_t* hash_value, std::string* architecture)
{
std::uint32_t version, size;
version = read_little_endian<std::uint32_t>(stream);
*hash_value = read_little_endian<std::uint32_t>(stream);
size = read_little_endian<std::uint32_t>(stream);
if (!stream || version != kVersion)
return false;
architecture->resize(size);
stream.read(&(*architecture)[0], size);
return !stream.fail();
}
// write the header
bool write_header(std::ostream& stream,
std::uint32_t hash_value, const std::string& architecture) {
stream.write(reinterpret_cast<const char*>(&kVersion), sizeof(kVersion));
stream.write(reinterpret_cast<const char*>(&hash_value), sizeof(hash_value));
const std::uint32_t size = static_cast<std::uint32_t>(architecture.size());
stream.write(reinterpret_cast<const char*>(&size), sizeof(size));
stream.write(architecture.data(), size);
return !stream.fail();
}
// Read network parameters
bool read_parameters(std::istream& stream) {
std::uint32_t hash_value;
std::string architecture;
if (!read_header(stream, &hash_value, &architecture))
return false;
if (hash_value != kHashValue)
return false;
if (!Detail::read_parameters(stream, *feature_transformer))
return false;
if (!Detail::read_parameters(stream, *network))
return false;
return stream && stream.peek() == std::ios::traits_type::eof();
}
// write evaluation function parameters
bool write_parameters(std::ostream& stream) {
if (!write_header(stream, kHashValue, get_architecture_string()))
return false;
if (!Detail::write_parameters(stream, feature_transformer))
return false;
if (!Detail::write_parameters(stream, network))
return false;
return !stream.fail();
}
// Evaluation function. Perform differential calculation.
Value evaluate(const Position& pos) {
alignas(kCacheLineSize) TransformedFeatureType
transformed_features[FeatureTransformer::kBufferSize];
feature_transformer->transform(pos, transformed_features);
alignas(kCacheLineSize) char buffer[Network::kBufferSize];
const auto output = network->propagate(transformed_features, buffer);
return static_cast<Value>(output[0] / FV_SCALE);
}
// Load eval, from a file stream or a memory stream
bool load_eval(std::string name, std::istream& stream) {
initialize();
fileName = name;
return read_parameters(stream);
}
static UseNNUEMode nnue_mode_from_option(const UCI::Option& mode)
{
if (mode == "false")
return UseNNUEMode::False;
else if (mode == "true")
return UseNNUEMode::True;
else if (mode == "pure")
return UseNNUEMode::Pure;
return UseNNUEMode::False;
}
void init() {
useNNUE = nnue_mode_from_option(Options["Use NNUE"]);
if (Options["SkipLoadingEval"] || useNNUE == UseNNUEMode::False)
{
eval_file_loaded.clear();
return;
}
std::string eval_file = std::string(Options["EvalFile"]);
#if defined(DEFAULT_NNUE_DIRECTORY)
#define stringify2(x) #x
#define stringify(x) stringify2(x)
std::vector<std::string> dirs = { "" , CommandLine::binaryDirectory , stringify(DEFAULT_NNUE_DIRECTORY) };
std::vector<std::string> dirs = { "" , CommandLine::binaryDirectory , stringify(DEFAULT_NNUE_DIRECTORY) };
#else
std::vector<std::string> dirs = { "" , CommandLine::binaryDirectory };
std::vector<std::string> dirs = { "" , CommandLine::binaryDirectory };
#endif
for (std::string directory : dirs)
if (eval_file_loaded != eval_file)
for (std::string directory : dirs)
{
std::ifstream stream(directory + eval_file, std::ios::binary);
if (load_eval(eval_file, stream))
if (eval_file_loaded != eval_file)
{
sync_cout << "info string Loaded eval file " << directory + eval_file << sync_endl;
eval_file_loaded = eval_file;
}
else
{
sync_cout << "info string ERROR: failed to load eval file " << directory + eval_file << sync_endl;
eval_file_loaded.clear();
std::ifstream stream(directory + eval_file, std::ios::binary);
if (load_eval(eval_file, stream))
{
sync_cout << "info string Loaded eval file " << directory + eval_file << sync_endl;
eval_file_loaded = eval_file;
}
else
{
sync_cout << "info string ERROR: failed to load eval file " << directory + eval_file << sync_endl;
eval_file_loaded.clear();
}
}
}
#undef stringify2
#undef stringify
}
/// NNUE::verify() verifies that the last net used was loaded successfully
void verify_eval_file_loaded() {
std::string eval_file = std::string(Options["EvalFile"]);
if (useNNUE != UseNNUEMode::False && eval_file_loaded != eval_file)
{
UCI::OptionsMap defaults;
UCI::init(defaults);
std::string msg1 = "If the UCI option \"Use NNUE\" is set to true, network evaluation parameters compatible with the engine must be available.";
std::string msg2 = "The option is set to true, but 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(defaults["EvalFile"]);
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;
std::exit(EXIT_FAILURE);
}
if (useNNUE != UseNNUEMode::False)
sync_cout << "info string NNUE evaluation using " << eval_file << " enabled" << sync_endl;
else
sync_cout << "info string classical evaluation enabled" << sync_endl;
}
/// NNUE::verify() verifies that the last net used was loaded successfully
void verify_eval_file_loaded() {
/// In training we override eval file so this is useful.
void verify_any_net_loaded() {
std::string eval_file = std::string(Options["EvalFile"]);
if (!Options["SkipLoadingEval"] && useNNUE != UseNNUEMode::False && eval_file_loaded.empty())
{
UCI::OptionsMap defaults;
UCI::init(defaults);
if (useNNUE != UseNNUEMode::False && eval_file_loaded != eval_file)
{
UCI::OptionsMap defaults;
UCI::init(defaults);
std::string msg1 = "If the UCI option \"Use NNUE\" is set to true, network evaluation parameters compatible with the engine must be available.";
std::string msg2 = "The option is set to true, but the network 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 msg5 = "The engine will be terminated now.";
std::string msg1 = "If the UCI option \"Use NNUE\" is set to true, network evaluation parameters compatible with the engine must be available.";
std::string msg2 = "The option is set to true, but 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(defaults["EvalFile"]);
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: " << msg5 << sync_endl;
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;
std::exit(EXIT_FAILURE);
std::exit(EXIT_FAILURE);
}
if (useNNUE != UseNNUEMode::False)
sync_cout << "info string NNUE evaluation using " << eval_file << " enabled" << sync_endl;
else
sync_cout << "info string classical evaluation enabled" << sync_endl;
}
if (useNNUE != UseNNUEMode::False)
sync_cout << "info string NNUE evaluation using " << eval_file_loaded << " enabled" << sync_endl;
else
sync_cout << "info string classical evaluation enabled" << sync_endl;
}
/// In training we override eval file so this is useful.
void verify_any_net_loaded() {
if (!Options["SkipLoadingEval"] && useNNUE != UseNNUEMode::False && eval_file_loaded.empty())
{
UCI::OptionsMap defaults;
UCI::init(defaults);
std::string msg1 = "If the UCI option \"Use NNUE\" is set to true, network evaluation parameters compatible with the engine must be available.";
std::string msg2 = "The option is set to true, but the network 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 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: " << msg5 << sync_endl;
std::exit(EXIT_FAILURE);
}
if (useNNUE != UseNNUEMode::False)
sync_cout << "info string NNUE evaluation using " << eval_file_loaded << " enabled" << sync_endl;
else
sync_cout << "info string classical evaluation enabled" << sync_endl;
}
} // namespace Eval::NNUE

View File

@@ -37,7 +37,7 @@ namespace Eval::NNUE {
// Hash value of evaluation function structure
constexpr std::uint32_t kHashValue =
FeatureTransformer::GetHashValue() ^ Network::GetHashValue();
FeatureTransformer::get_hash_value() ^ Network::get_hash_value();
// Deleter for automating release of memory area
template <typename T>
@@ -79,21 +79,21 @@ namespace Eval::NNUE {
extern std::string eval_file_loaded;
// Get a string that represents the structure of the evaluation function
std::string GetArchitectureString();
std::string get_architecture_string();
// read the header
bool ReadHeader(std::istream& stream,
bool read_header(std::istream& stream,
std::uint32_t* hash_value, std::string* architecture);
// write the header
bool WriteHeader(std::ostream& stream,
bool write_header(std::ostream& stream,
std::uint32_t hash_value, const std::string& architecture);
// read evaluation function parameters
bool ReadParameters(std::istream& stream);
bool read_parameters(std::istream& stream);
// write evaluation function parameters
bool WriteParameters(std::ostream& stream);
bool write_parameters(std::ostream& stream);
Value evaluate(const Position& pos);
bool load_eval(std::string name, std::istream& stream);

View File

@@ -44,9 +44,9 @@ namespace Eval::NNUE {
std::shared_ptr<Trainer<Network>> trainer;
// Tell the learner options such as hyperparameters
void SendMessages(std::vector<Message> messages) {
void send_messages(std::vector<Message> messages) {
for (auto& message : messages) {
trainer->SendMessage(&message);
trainer->send_message(&message);
assert(message.num_receivers > 0);
}
}
@@ -54,31 +54,31 @@ namespace Eval::NNUE {
} // namespace
// Initialize learning
void InitializeTraining(const std::string& seed) {
void initialize_training(const std::string& seed) {
std::cout << "Initializing NN training for "
<< GetArchitectureString() << std::endl;
<< get_architecture_string() << std::endl;
assert(feature_transformer);
assert(network);
trainer = Trainer<Network>::Create(network.get(), feature_transformer.get());
trainer = Trainer<Network>::create(network.get(), feature_transformer.get());
rng.seed(PRNG(seed).rand<uint64_t>());
if (Options["SkipLoadingEval"]) {
trainer->Initialize(rng);
trainer->initialize(rng);
}
}
// set the number of samples in the mini-batch
void SetBatchSize(uint64_t size) {
void set_batch_size(uint64_t size) {
assert(size > 0);
batch_size = size;
}
// Set options such as hyperparameters
void SetOptions(const std::string& options) {
void set_options(const std::string& options) {
std::vector<Message> messages;
for (const auto& option : Split(options, ',')) {
const auto fields = Split(option, '=');
for (const auto& option : Algo::split(options, ',')) {
const auto fields = Algo::split(option, '=');
assert(fields.size() == 1 || fields.size() == 2);
if (fields.size() == 1) {
@@ -88,30 +88,30 @@ namespace Eval::NNUE {
}
}
SendMessages(std::move(messages));
send_messages(std::move(messages));
}
// Reread the evaluation function parameters for learning from the file
void RestoreParameters(const std::string& dir_name) {
const std::string file_name = Path::Combine(dir_name, NNUE::savedfileName);
void restore_parameters(const std::string& dir_name) {
const std::string file_name = Path::combine(dir_name, NNUE::savedfileName);
std::ifstream stream(file_name, std::ios::binary);
#ifndef NDEBUG
bool result =
#endif
ReadParameters(stream);
read_parameters(stream);
#ifndef NDEBUG
assert(result);
#endif
SendMessages({{"reset"}});
send_messages({{"reset"}});
}
void FinalizeNet() {
SendMessages({{"clear_unobserved_feature_weights"}});
void finalize_net() {
send_messages({{"clear_unobserved_feature_weights"}});
}
// Add 1 sample of learning data
void AddExample(Position& pos, Color rootColor,
void add_example(Position& pos, Color rootColor,
const Learner::PackedSfenValue& psv, double weight) {
Example example;
@@ -126,7 +126,7 @@ namespace Eval::NNUE {
Features::IndexList active_indices[2];
for (const auto trigger : kRefreshTriggers) {
RawFeatures::AppendActiveIndices(pos, trigger, active_indices);
RawFeatures::append_active_indices(pos, trigger, active_indices);
}
if (pos.side_to_move() != WHITE) {
@@ -136,9 +136,9 @@ namespace Eval::NNUE {
for (const auto color : Colors) {
std::vector<TrainingFeature> training_features;
for (const auto base_index : active_indices[color]) {
static_assert(Features::Factorizer<RawFeatures>::GetDimensions() <
static_assert(Features::Factorizer<RawFeatures>::get_dimensions() <
(1 << TrainingFeature::kIndexBits), "");
Features::Factorizer<RawFeatures>::AppendTrainingFeatures(
Features::Factorizer<RawFeatures>::append_training_features(
base_index, &training_features);
}
@@ -147,7 +147,7 @@ namespace Eval::NNUE {
auto& unique_features = example.training_features[color];
for (const auto& feature : training_features) {
if (!unique_features.empty() &&
feature.GetIndex() == unique_features.back().GetIndex()) {
feature.get_index() == unique_features.back().get_index()) {
unique_features.back() += feature;
} else {
@@ -161,7 +161,7 @@ namespace Eval::NNUE {
}
// update the evaluation function parameters
void UpdateParameters() {
void update_parameters() {
assert(batch_size > 0);
const auto learning_rate = static_cast<LearnFloatType>(
@@ -173,30 +173,30 @@ namespace Eval::NNUE {
std::vector<Example> batch(examples.end() - batch_size, examples.end());
examples.resize(examples.size() - batch_size);
const auto network_output = trainer->Propagate(batch);
const auto network_output = trainer->propagate(batch);
std::vector<LearnFloatType> gradients(batch.size());
for (std::size_t b = 0; b < batch.size(); ++b) {
const auto shallow = static_cast<Value>(Round<std::int32_t>(
const auto shallow = static_cast<Value>(round<std::int32_t>(
batch[b].sign * network_output[b] * kPonanzaConstant));
const auto& psv = batch[b].psv;
const double gradient = batch[b].sign * Learner::calc_grad(shallow, psv);
gradients[b] = static_cast<LearnFloatType>(gradient * batch[b].weight);
}
trainer->Backpropagate(gradients.data(), learning_rate);
trainer->backpropagate(gradients.data(), learning_rate);
}
SendMessages({{"quantize_parameters"}});
send_messages({{"quantize_parameters"}});
}
// Check if there are any problems with learning
void CheckHealth() {
SendMessages({{"check_health"}});
void check_health() {
send_messages({{"check_health"}});
}
// save merit function parameters to a file
void save_eval(std::string dir_name) {
auto eval_dir = Path::Combine(Options["EvalSaveDir"], dir_name);
auto eval_dir = Path::combine(Options["EvalSaveDir"], dir_name);
std::cout << "save_eval() start. folder = " << eval_dir << std::endl;
// mkdir() will fail if this folder already exists, but
@@ -204,12 +204,12 @@ namespace Eval::NNUE {
// Also, assume that the folders up to EvalSaveDir have been dug.
std::filesystem::create_directories(eval_dir);
const std::string file_name = Path::Combine(eval_dir, NNUE::savedfileName);
const std::string file_name = Path::combine(eval_dir, NNUE::savedfileName);
std::ofstream stream(file_name, std::ios::binary);
#ifndef NDEBUG
bool result =
#endif
WriteParameters(stream);
write_parameters(stream);
#ifndef NDEBUG
assert(result);
#endif

View File

@@ -7,28 +7,31 @@
namespace Eval::NNUE {
// Initialize learning
void InitializeTraining(const std::string& seed);
void initialize_training(const std::string& seed);
// set the number of samples in the mini-batch
void SetBatchSize(uint64_t size);
void set_batch_size(uint64_t size);
// Set options such as hyperparameters
void SetOptions(const std::string& options);
void set_options(const std::string& options);
// Reread the evaluation function parameters for learning from the file
void RestoreParameters(const std::string& dir_name);
void restore_parameters(const std::string& dir_name);
// Add 1 sample of learning data
void AddExample(Position& pos, Color rootColor,
const Learner::PackedSfenValue& psv, double weight);
void add_example(
Position& pos,
Color rootColor,
const Learner::PackedSfenValue& psv,
double weight);
// update the evaluation function parameters
void UpdateParameters();
void update_parameters();
// Check if there are any problems with learning
void CheckHealth();
void check_health();
void FinalizeNet();
void finalize_net();
void save_eval(std::string suffix);
} // namespace Eval::NNUE

View File

@@ -5,8 +5,11 @@
namespace Eval::NNUE::Features {
// Get a list of indices with a value of 1 among the features
void CastlingRight::AppendActiveIndices(
const Position& pos, Color perspective, IndexList* active) {
void CastlingRight::append_active_indices(
const Position& pos,
Color perspective,
IndexList* active) {
// do nothing if array size is small to avoid compiler warning
if (RawFeatures::kMaxActiveDimensions < kMaxActiveDimensions) return;
@@ -29,9 +32,11 @@ namespace Eval::NNUE::Features {
}
// Get a list of indices whose values have changed from the previous one in the feature quantity
void CastlingRight::AppendChangedIndices(
const Position& pos, Color perspective,
IndexList* removed, IndexList* /* added */) {
void CastlingRight::append_changed_indices(
const Position& pos,
Color perspective,
IndexList* removed,
IndexList* /* added */) {
int previous_castling_rights = pos.state()->previous->castlingRights;
int current_castling_rights = pos.state()->castlingRights;

View File

@@ -26,12 +26,17 @@ namespace Eval::NNUE::Features {
static constexpr TriggerEvent kRefreshTrigger = TriggerEvent::kNone;
// Get a list of indices with a value of 1 among the features
static void AppendActiveIndices(const Position& pos, Color perspective,
static void append_active_indices(
const Position& pos,
Color perspective,
IndexList* active);
// Get a list of indices whose values have changed from the previous one in the feature quantity
static void AppendChangedIndices(const Position& pos, Color perspective,
IndexList* removed, IndexList* added);
static void append_changed_indices(
const Position& pos,
Color perspective,
IndexList* removed,
IndexList* added);
};
} // namespace Eval::NNUE::Features

View File

@@ -5,8 +5,10 @@
namespace Eval::NNUE::Features {
// Get a list of indices with a value of 1 among the features
void EnPassant::AppendActiveIndices(
const Position& pos, Color /* perspective */, IndexList* active) {
void EnPassant::append_active_indices(
const Position& pos,
Color /* perspective */,
IndexList* active) {
// do nothing if array size is small to avoid compiler warning
if (RawFeatures::kMaxActiveDimensions < kMaxActiveDimensions)
@@ -21,9 +23,11 @@ namespace Eval::NNUE::Features {
}
// Get a list of indices whose values have changed from the previous one in the feature quantity
void EnPassant::AppendChangedIndices(
const Position& pos, Color /* perspective */,
IndexList* removed, IndexList* added) {
void EnPassant::append_changed_indices(
const Position& pos,
Color /* perspective */,
IndexList* removed,
IndexList* added) {
auto previous_epSquare = pos.state()->previous->epSquare;
auto epSquare = pos.state()->epSquare;

View File

@@ -22,12 +22,17 @@ namespace Eval::NNUE::Features {
static constexpr TriggerEvent kRefreshTrigger = TriggerEvent::kNone;
// Get a list of indices with a value of 1 among the features
static void AppendActiveIndices(const Position& pos, Color perspective,
static void append_active_indices(
const Position& pos,
Color perspective,
IndexList* active);
// Get a list of indices whose values have changed from the previous one in the feature quantity
static void AppendChangedIndices(const Position& pos, Color perspective,
IndexList* removed, IndexList* added);
static void append_changed_indices(
const Position& pos,
Color perspective,
IndexList* removed,
IndexList* added);
};
} // namespace Eval::NNUE::Features

View File

@@ -33,8 +33,8 @@ namespace Eval::NNUE::Features {
template <typename T, T First, T... Remaining>
struct CompileTimeList<T, First, Remaining...> {
static constexpr bool Contains(T value) {
return value == First || CompileTimeList<T, Remaining...>::Contains(value);
static constexpr bool contains(T value) {
return value == First || CompileTimeList<T, Remaining...>::contains(value);
}
static constexpr std::array<T, sizeof...(Remaining) + 1>
@@ -47,7 +47,7 @@ namespace Eval::NNUE::Features {
template <typename T>
struct CompileTimeList<T> {
static constexpr bool Contains(T /*value*/) {
static constexpr bool contains(T /*value*/) {
return false;
}
static constexpr std::array<T, 0> kValues = { {} };
@@ -70,7 +70,7 @@ namespace Eval::NNUE::Features {
struct InsertToSet<T, CompileTimeList<T, First, Remaining...>, AnotherValue> {
using Result =
std::conditional_t<
CompileTimeList<T, First, Remaining...>::Contains(AnotherValue),
CompileTimeList<T, First, Remaining...>::contains(AnotherValue),
CompileTimeList<T, First, Remaining...>,
std::conditional_t<
(AnotherValue < First),
@@ -95,20 +95,23 @@ namespace Eval::NNUE::Features {
public:
// Get a list of indices for active features
template <typename IndexListType>
static void AppendActiveIndices(
static void append_active_indices(
const Position& pos, TriggerEvent trigger, IndexListType active[2]) {
for (Color perspective : { WHITE, BLACK }) {
Derived::CollectActiveIndices(
Derived::collect_active_indices(
pos, trigger, perspective, &active[perspective]);
}
}
// Get a list of indices for recently changed features
template <typename PositionType, typename IndexListType>
static void AppendChangedIndices(
const PositionType& pos, TriggerEvent trigger,
IndexListType removed[2], IndexListType added[2], bool reset[2]) {
static void append_changed_indices(
const PositionType& pos,
TriggerEvent trigger,
IndexListType removed[2],
IndexListType added[2],
bool reset[2]) {
const auto& dp = pos.state()->dirtyPiece;
@@ -137,10 +140,10 @@ namespace Eval::NNUE::Features {
}
if (reset[perspective]) {
Derived::CollectActiveIndices(
Derived::collect_active_indices(
pos, trigger, perspective, &added[perspective]);
} else {
Derived::CollectChangedIndices(
Derived::collect_changed_indices(
pos, trigger, perspective,
&removed[perspective], &added[perspective]);
}
@@ -180,20 +183,23 @@ namespace Eval::NNUE::Features {
static constexpr auto kRefreshTriggers = SortedTriggerSet::kValues;
// Get the feature quantity name
static std::string GetName() {
return std::string(Head::kName) + "+" + Tail::GetName();
static std::string get_name() {
return std::string(Head::kName) + "+" + Tail::get_name();
}
private:
// Get a list of indices with a value of 1 among the features
template <typename IndexListType>
static void CollectActiveIndices(
const Position& pos, const TriggerEvent trigger, const Color perspective,
static void collect_active_indices(
const Position& pos,
const TriggerEvent trigger,
const Color perspective,
IndexListType* const active) {
Tail::CollectActiveIndices(pos, trigger, perspective, active);
Tail::collect_active_indices(pos, trigger, perspective, active);
if (Head::kRefreshTrigger == trigger) {
const auto start = active->size();
Head::AppendActiveIndices(pos, perspective, active);
Head::append_active_indices(pos, perspective, active);
for (auto i = start; i < active->size(); ++i) {
(*active)[i] += Tail::kDimensions;
@@ -203,14 +209,18 @@ namespace Eval::NNUE::Features {
// Get a list of indices whose values have changed from the previous one in the feature quantity
template <typename IndexListType>
static void CollectChangedIndices(
const Position& pos, const TriggerEvent trigger, const Color perspective,
IndexListType* const removed, IndexListType* const added) {
Tail::CollectChangedIndices(pos, trigger, perspective, removed, added);
static void collect_changed_indices(
const Position& pos,
const TriggerEvent trigger,
const Color perspective,
IndexListType* const removed,
IndexListType* const added) {
Tail::collect_changed_indices(pos, trigger, perspective, removed, added);
if (Head::kRefreshTrigger == trigger) {
const auto start_removed = removed->size();
const auto start_added = added->size();
Head::AppendChangedIndices(pos, perspective, removed, added);
Head::append_changed_indices(pos, perspective, removed, added);
for (auto i = start_removed; i < removed->size(); ++i) {
(*removed)[i] += Tail::kDimensions;
@@ -251,28 +261,33 @@ namespace Eval::NNUE::Features {
static constexpr auto kRefreshTriggers = SortedTriggerSet::kValues;
// Get the feature quantity name
static std::string GetName() {
static std::string get_name() {
return FeatureType::kName;
}
private:
// Get a list of indices for active features
static void CollectActiveIndices(
const Position& pos, const TriggerEvent trigger, const Color perspective,
static void collect_active_indices(
const Position& pos,
const TriggerEvent trigger,
const Color perspective,
IndexList* const active) {
if (FeatureType::kRefreshTrigger == trigger) {
FeatureType::AppendActiveIndices(pos, perspective, active);
FeatureType::append_active_indices(pos, perspective, active);
}
}
// Get a list of indices for recently changed features
static void CollectChangedIndices(
const Position& pos, const TriggerEvent trigger, const Color perspective,
IndexList* const removed, IndexList* const added) {
static void collect_changed_indices(
const Position& pos,
const TriggerEvent trigger,
const Color perspective,
IndexList* const removed,
IndexList* const added) {
if (FeatureType::kRefreshTrigger == trigger) {
FeatureType::AppendChangedIndices(pos, perspective, removed, added);
FeatureType::append_changed_indices(pos, perspective, removed, added);
}
}

View File

@@ -30,30 +30,41 @@ namespace Eval::NNUE::Features {
// Find the index of the feature quantity from the king position and PieceSquare
template <Side AssociatedKing>
inline IndexType HalfKP<AssociatedKing>::MakeIndex(
Color perspective, Square s, Piece pc, Square ksq) {
inline IndexType HalfKP<AssociatedKing>::make_index(
Color perspective,
Square s,
Piece pc,
Square ksq) {
return IndexType(orient(perspective, s) + kpp_board_index[pc][perspective] + PS_END * ksq);
}
// Get a list of indices for active features
template <Side AssociatedKing>
void HalfKP<AssociatedKing>::AppendActiveIndices(
const Position& pos, Color perspective, IndexList* active) {
void HalfKP<AssociatedKing>::append_active_indices(
const Position& pos,
Color perspective,
IndexList* active) {
Square ksq = orient(
perspective,
pos.square<KING>(
AssociatedKing == Side::kFriend ? perspective : ~perspective));
Square ksq = orient(perspective, pos.square<KING>(AssociatedKing == Side::kFriend ? perspective : ~perspective));
Bitboard bb = pos.pieces() & ~pos.pieces(KING);
while (bb) {
Square s = pop_lsb(&bb);
active->push_back(MakeIndex(perspective, s, pos.piece_on(s), ksq));
active->push_back(make_index(perspective, s, pos.piece_on(s), ksq));
}
}
// Get a list of indices for recently changed features
template <Side AssociatedKing>
void HalfKP<AssociatedKing>::AppendChangedIndices(
const Position& pos, Color perspective,
IndexList* removed, IndexList* added) {
void HalfKP<AssociatedKing>::append_changed_indices(
const Position& pos,
Color perspective,
IndexList* removed,
IndexList* added) {
Square ksq = orient(
perspective,
@@ -68,10 +79,10 @@ namespace Eval::NNUE::Features {
continue;
if (dp.from[i] != SQ_NONE)
removed->push_back(MakeIndex(perspective, dp.from[i], pc, ksq));
removed->push_back(make_index(perspective, dp.from[i], pc, ksq));
if (dp.to[i] != SQ_NONE)
added->push_back(MakeIndex(perspective, dp.to[i], pc, ksq));
added->push_back(make_index(perspective, dp.to[i], pc, ksq));
}
}

View File

@@ -53,16 +53,21 @@ namespace Eval::NNUE::Features {
TriggerEvent::kFriendKingMoved : TriggerEvent::kEnemyKingMoved;
// Get a list of indices for active features
static void AppendActiveIndices(const Position& pos, Color perspective,
IndexList* active);
static void append_active_indices(
const Position& pos,
Color perspective,
IndexList* active);
// Get a list of indices for recently changed features
static void AppendChangedIndices(const Position& pos, Color perspective,
IndexList* removed, IndexList* added);
static void append_changed_indices(
const Position& pos,
Color perspective,
IndexList* removed,
IndexList* added);
private:
// Index of a feature for a given king position and another piece on some square
static IndexType MakeIndex(Color perspective, Square s, Piece pc, Square sq_k);
static IndexType make_index(Color perspective, Square s, Piece pc, Square sq_k);
};
} // namespace Eval::NNUE::Features

View File

@@ -11,16 +11,21 @@ namespace Eval::NNUE::Features {
// Find the index of the feature quantity from the ball position and PieceSquare
template <Side AssociatedKing>
inline IndexType HalfRelativeKP<AssociatedKing>::MakeIndex(
Color perspective, Square s, Piece pc, Square sq_k) {
inline IndexType HalfRelativeKP<AssociatedKing>::make_index(
Color perspective,
Square s,
Piece pc,
Square sq_k) {
const IndexType p = IndexType(orient(perspective, s) + kpp_board_index[pc][perspective]);
return MakeIndex(sq_k, p);
return make_index(sq_k, p);
}
// Find the index of the feature quantity from the ball position and PieceSquare
template <Side AssociatedKing>
inline IndexType HalfRelativeKP<AssociatedKing>::MakeIndex(
Square sq_k, IndexType p) {
inline IndexType HalfRelativeKP<AssociatedKing>::make_index(
Square sq_k,
IndexType p) {
constexpr IndexType W = kBoardWidth;
constexpr IndexType H = kBoardHeight;
@@ -33,8 +38,10 @@ namespace Eval::NNUE::Features {
// Get a list of indices with a value of 1 among the features
template <Side AssociatedKing>
void HalfRelativeKP<AssociatedKing>::AppendActiveIndices(
const Position& pos, Color perspective, IndexList* active) {
void HalfRelativeKP<AssociatedKing>::append_active_indices(
const Position& pos,
Color perspective,
IndexList* active) {
Square ksq = orient(
perspective,
@@ -44,15 +51,17 @@ namespace Eval::NNUE::Features {
Bitboard bb = pos.pieces() & ~pos.pieces(KING);
while (bb) {
Square s = pop_lsb(&bb);
active->push_back(MakeIndex(perspective, s, pos.piece_on(s), ksq));
active->push_back(make_index(perspective, s, pos.piece_on(s), ksq));
}
}
// Get a list of indices whose values have changed from the previous one in the feature quantity
template <Side AssociatedKing>
void HalfRelativeKP<AssociatedKing>::AppendChangedIndices(
const Position& pos, Color perspective,
IndexList* removed, IndexList* added) {
void HalfRelativeKP<AssociatedKing>::append_changed_indices(
const Position& pos,
Color perspective,
IndexList* removed,
IndexList* added) {
Square ksq = orient(
perspective,
@@ -67,10 +76,10 @@ namespace Eval::NNUE::Features {
continue;
if (dp.from[i] != SQ_NONE)
removed->push_back(MakeIndex(perspective, dp.from[i], pc, ksq));
removed->push_back(make_index(perspective, dp.from[i], pc, ksq));
if (dp.to[i] != SQ_NONE)
added->push_back(MakeIndex(perspective, dp.to[i], pc, ksq));
added->push_back(make_index(perspective, dp.to[i], pc, ksq));
}
}

View File

@@ -42,18 +42,23 @@ namespace Eval::NNUE::Features {
TriggerEvent::kFriendKingMoved : TriggerEvent::kEnemyKingMoved;
// Get a list of indices with a value of 1 among the features
static void AppendActiveIndices(const Position& pos, Color perspective,
IndexList* active);
static void append_active_indices(
const Position& pos,
Color perspective,
IndexList* active);
// Get a list of indices whose values have changed from the previous one in the feature quantity
static void AppendChangedIndices(const Position& pos, Color perspective,
IndexList* removed, IndexList* added);
static void append_changed_indices(
const Position& pos,
Color perspective,
IndexList* removed,
IndexList* added);
// Find the index of the feature quantity from the ball position and PieceSquare
static IndexType MakeIndex(Square s, IndexType p);
static IndexType make_index(Square s, IndexType p);
// Find the index of the feature quantity from the ball position and PieceSquare
static IndexType MakeIndex(Color perspective, Square s, Piece pc, Square sq_k);
static IndexType make_index(Color perspective, Square s, Piece pc, Square sq_k);
};
} // namespace Eval::NNUE::Features

View File

@@ -10,29 +10,33 @@ namespace Eval::NNUE::Features {
}
// Index of a feature for a given king position.
IndexType K::MakeIndex(Color perspective, Square s, Color king_color) {
IndexType K::make_index(Color perspective, Square s, Color king_color) {
return IndexType(orient(perspective, s) + bool(perspective ^ king_color) * 64);
}
// Get a list of indices with a value of 1 among the features
void K::AppendActiveIndices(
const Position& pos, Color perspective, IndexList* active) {
void K::append_active_indices(
const Position& pos,
Color perspective,
IndexList* active) {
for (auto color : Colors) {
active->push_back(MakeIndex(perspective, pos.square<KING>(color), color));
active->push_back(make_index(perspective, pos.square<KING>(color), color));
}
}
// Get a list of indices whose values have changed from the previous one in the feature quantity
void K::AppendChangedIndices(
const Position& pos, Color perspective,
IndexList* removed, IndexList* added) {
void K::append_changed_indices(
const Position& pos,
Color perspective,
IndexList* removed,
IndexList* added) {
const auto& dp = pos.state()->dirtyPiece;
if (type_of(dp.piece[0]) == KING)
{
removed->push_back(MakeIndex(perspective, dp.from[0], color_of(dp.piece[0])));
added->push_back(MakeIndex(perspective, dp.to[0], color_of(dp.piece[0])));
removed->push_back(make_index(perspective, dp.from[0], color_of(dp.piece[0])));
added->push_back(make_index(perspective, dp.to[0], color_of(dp.piece[0])));
}
}

View File

@@ -8,36 +8,41 @@
//Definition of input feature quantity K of NNUE evaluation function
namespace Eval::NNUE::Features {
// Feature K: Ball position
class K {
public:
// feature quantity name
static constexpr const char* kName = "K";
// Feature K: Ball position
class K {
public:
// feature quantity name
static constexpr const char* kName = "K";
// Hash value embedded in the evaluation function file
static constexpr std::uint32_t kHashValue = 0xD3CEE169u;
// Hash value embedded in the evaluation function file
static constexpr std::uint32_t kHashValue = 0xD3CEE169u;
// number of feature dimensions
static constexpr IndexType kDimensions = SQUARE_NB * 2;
// number of feature dimensions
static constexpr IndexType kDimensions = SQUARE_NB * 2;
// The maximum value of the number of indexes whose value is 1 at the same time among the feature values
static constexpr IndexType kMaxActiveDimensions = 2;
// The maximum value of the number of indexes whose value is 1 at the same time among the feature values
static constexpr IndexType kMaxActiveDimensions = 2;
// Timing of full calculation instead of difference calculation
static constexpr TriggerEvent kRefreshTrigger = TriggerEvent::kNone;
// Timing of full calculation instead of difference calculation
static constexpr TriggerEvent kRefreshTrigger = TriggerEvent::kNone;
// Get a list of indices with a value of 1 among the features
static void AppendActiveIndices(const Position& pos, Color perspective,
IndexList* active);
// Get a list of indices with a value of 1 among the features
static void append_active_indices(
const Position& pos,
Color perspective,
IndexList* active);
// Get a list of indices whose values have changed from the previous one in the feature quantity
static void AppendChangedIndices(const Position& pos, Color perspective,
IndexList* removed, IndexList* added);
// Get a list of indices whose values have changed from the previous one in the feature quantity
static void append_changed_indices(
const Position& pos,
Color perspective,
IndexList* removed,
IndexList* added);
private:
// Index of a feature for a given king position.
static IndexType MakeIndex(Color perspective, Square s, Color king_color);
};
private:
// Index of a feature for a given king position.
static IndexType make_index(Color perspective, Square s, Color king_color);
};
} // namespace Eval::NNUE::Features

View File

@@ -10,26 +10,30 @@ namespace Eval::NNUE::Features {
}
// Find the index of the feature quantity from the king position and PieceSquare
inline IndexType P::MakeIndex(
inline IndexType P::make_index(
Color perspective, Square s, Piece pc) {
return IndexType(orient(perspective, s) + kpp_board_index[pc][perspective]);
}
// Get a list of indices with a value of 1 among the features
void P::AppendActiveIndices(
const Position& pos, Color perspective, IndexList* active) {
void P::append_active_indices(
const Position& pos,
Color perspective,
IndexList* active) {
Bitboard bb = pos.pieces() & ~pos.pieces(KING);
while (bb) {
Square s = pop_lsb(&bb);
active->push_back(MakeIndex(perspective, s, pos.piece_on(s)));
active->push_back(make_index(perspective, s, pos.piece_on(s)));
}
}
// Get a list of indices whose values have changed from the previous one in the feature quantity
void P::AppendChangedIndices(
const Position& pos, Color perspective,
IndexList* removed, IndexList* added) {
void P::append_changed_indices(
const Position& pos,
Color perspective,
IndexList* removed,
IndexList* added) {
const auto& dp = pos.state()->dirtyPiece;
for (int i = 0; i < dp.dirty_num; ++i) {
@@ -39,10 +43,10 @@ namespace Eval::NNUE::Features {
continue;
if (dp.from[i] != SQ_NONE)
removed->push_back(MakeIndex(perspective, dp.from[i], pc));
removed->push_back(make_index(perspective, dp.from[i], pc));
if (dp.to[i] != SQ_NONE)
added->push_back(MakeIndex(perspective, dp.to[i], pc));
added->push_back(make_index(perspective, dp.to[i], pc));
}
}

View File

@@ -8,36 +8,41 @@
//Definition of input feature P of NNUE evaluation function
namespace Eval::NNUE::Features {
// Feature P: PieceSquare of pieces other than balls
class P {
public:
// feature quantity name
static constexpr const char* kName = "P";
// Feature P: PieceSquare of pieces other than balls
class P {
public:
// feature quantity name
static constexpr const char* kName = "P";
// Hash value embedded in the evaluation function file
static constexpr std::uint32_t kHashValue = 0x764CFB4Bu;
// Hash value embedded in the evaluation function file
static constexpr std::uint32_t kHashValue = 0x764CFB4Bu;
// number of feature dimensions
static constexpr IndexType kDimensions = PS_END;
// number of feature dimensions
static constexpr IndexType kDimensions = PS_END;
// The maximum value of the number of indexes whose value is 1 at the same time among the feature values
static constexpr IndexType kMaxActiveDimensions = 30; // Kings don't count
// The maximum value of the number of indexes whose value is 1 at the same time among the feature values
static constexpr IndexType kMaxActiveDimensions = 30; // Kings don't count
// Timing of full calculation instead of difference calculation
static constexpr TriggerEvent kRefreshTrigger = TriggerEvent::kNone;
// Timing of full calculation instead of difference calculation
static constexpr TriggerEvent kRefreshTrigger = TriggerEvent::kNone;
// Get a list of indices with a value of 1 among the features
static void AppendActiveIndices(const Position& pos, Color perspective,
IndexList* active);
// Get a list of indices with a value of 1 among the features
static void append_active_indices(
const Position& pos,
Color perspective,
IndexList* active);
// Get a list of indices whose values have changed from the previous one in the feature quantity
static void AppendChangedIndices(const Position& pos, Color perspective,
IndexList* removed, IndexList* added);
// Get a list of indices whose values have changed from the previous one in the feature quantity
static void append_changed_indices(
const Position& pos,
Color perspective,
IndexList* removed,
IndexList* added);
private:
// Index of a feature for a given piece on some square
static IndexType MakeIndex(Color perspective, Square s, Piece pc);
};
private:
// Index of a feature for a given piece on some square
static IndexType make_index(Color perspective, Square s, Piece pc);
};
} // namespace Eval::NNUE::Features

View File

@@ -47,36 +47,36 @@ namespace Eval::NNUE::Layers {
static constexpr IndexType kOutputDimensions = OutputDimensions;
static constexpr IndexType kPaddedInputDimensions =
CeilToMultiple<IndexType>(kInputDimensions, kMaxSimdWidth);
ceil_to_multiple<IndexType>(kInputDimensions, kMaxSimdWidth);
// Size of forward propagation buffer used in this layer
static constexpr std::size_t kSelfBufferSize =
CeilToMultiple(kOutputDimensions * sizeof(OutputType), kCacheLineSize);
ceil_to_multiple(kOutputDimensions * sizeof(OutputType), kCacheLineSize);
// Size of the forward propagation buffer used from the input layer to this layer
static constexpr std::size_t kBufferSize =
PreviousLayer::kBufferSize + kSelfBufferSize;
// Hash value embedded in the evaluation file
static constexpr std::uint32_t GetHashValue() {
static constexpr std::uint32_t get_hash_value() {
std::uint32_t hash_value = 0xCC03DAE4u;
hash_value += kOutputDimensions;
hash_value ^= PreviousLayer::GetHashValue() >> 1;
hash_value ^= PreviousLayer::GetHashValue() << 31;
hash_value ^= PreviousLayer::get_hash_value() >> 1;
hash_value ^= PreviousLayer::get_hash_value() << 31;
return hash_value;
}
// A string that represents the structure from the input layer to this layer
static std::string GetStructureString() {
static std::string get_structure_string() {
return "AffineTransform[" +
std::to_string(kOutputDimensions) + "<-" +
std::to_string(kInputDimensions) + "](" +
PreviousLayer::GetStructureString() + ")";
PreviousLayer::get_structure_string() + ")";
}
// Read network parameters
bool ReadParameters(std::istream& stream) {
if (!previous_layer_.ReadParameters(stream))
bool read_parameters(std::istream& stream) {
if (!previous_layer_.read_parameters(stream))
return false;
for (std::size_t i = 0; i < kOutputDimensions; ++i)
@@ -89,8 +89,8 @@ namespace Eval::NNUE::Layers {
}
// write parameters
bool WriteParameters(std::ostream& stream) const {
if (!previous_layer_.WriteParameters(stream))
bool write_parameters(std::ostream& stream) const {
if (!previous_layer_.write_parameters(stream))
return false;
stream.write(reinterpret_cast<const char*>(biases_),
@@ -104,10 +104,10 @@ namespace Eval::NNUE::Layers {
}
// Forward propagation
const OutputType* Propagate(
const OutputType* propagate(
const TransformedFeatureType* transformed_features, char* buffer) const {
const auto input = previous_layer_.Propagate(
const auto input = previous_layer_.propagate(
transformed_features, buffer + kSelfBufferSize);
const auto output = reinterpret_cast<OutputType*>(buffer);

View File

@@ -48,41 +48,41 @@ namespace Eval::NNUE::Layers {
// Size of forward propagation buffer used in this layer
static constexpr std::size_t kSelfBufferSize =
CeilToMultiple(kOutputDimensions * sizeof(OutputType), kCacheLineSize);
ceil_to_multiple(kOutputDimensions * sizeof(OutputType), kCacheLineSize);
// Size of the forward propagation buffer used from the input layer to this layer
static constexpr std::size_t kBufferSize =
PreviousLayer::kBufferSize + kSelfBufferSize;
// Hash value embedded in the evaluation file
static constexpr std::uint32_t GetHashValue() {
static constexpr std::uint32_t get_hash_value() {
std::uint32_t hash_value = 0x538D24C7u;
hash_value += PreviousLayer::GetHashValue();
hash_value += PreviousLayer::get_hash_value();
return hash_value;
}
// A string that represents the structure from the input layer to this layer
static std::string GetStructureString() {
static std::string get_structure_string() {
return "ClippedReLU[" +
std::to_string(kOutputDimensions) + "](" +
PreviousLayer::GetStructureString() + ")";
PreviousLayer::get_structure_string() + ")";
}
// Read network parameters
bool ReadParameters(std::istream& stream) {
return previous_layer_.ReadParameters(stream);
bool read_parameters(std::istream& stream) {
return previous_layer_.read_parameters(stream);
}
// write parameters
bool WriteParameters(std::ostream& stream) const {
return previous_layer_.WriteParameters(stream);
bool write_parameters(std::ostream& stream) const {
return previous_layer_.write_parameters(stream);
}
// Forward propagation
const OutputType* Propagate(
const OutputType* propagate(
const TransformedFeatureType* transformed_features, char* buffer) const {
const auto input = previous_layer_.Propagate(
const auto input = previous_layer_.propagate(
transformed_features, buffer + kSelfBufferSize);
const auto output = reinterpret_cast<OutputType*>(buffer);

View File

@@ -45,31 +45,31 @@ namespace Eval::NNUE::Layers {
static constexpr std::size_t kBufferSize = 0;
// Hash value embedded in the evaluation file
static constexpr std::uint32_t GetHashValue() {
static constexpr std::uint32_t get_hash_value() {
std::uint32_t hash_value = 0xEC42E90Du;
hash_value ^= kOutputDimensions ^ (Offset << 10);
return hash_value;
}
// A string that represents the structure from the input layer to this layer
static std::string GetStructureString() {
static std::string get_structure_string() {
return "InputSlice[" + std::to_string(kOutputDimensions) + "(" +
std::to_string(Offset) + ":" +
std::to_string(Offset + kOutputDimensions) + ")]";
}
// Read network parameters
bool ReadParameters(std::istream& /*stream*/) {
bool read_parameters(std::istream& /*stream*/) {
return true;
}
// write parameters
bool WriteParameters(std::ostream& /*stream*/) const {
bool write_parameters(std::ostream& /*stream*/) const {
return true;
}
// Forward propagation
const OutputType* Propagate(
const OutputType* propagate(
const TransformedFeatureType* transformed_features,
char* /*buffer*/) const {

View File

@@ -30,51 +30,51 @@ namespace Eval::NNUE::Layers {
// Size of forward propagation buffer used in this layer
static constexpr std::size_t kSelfBufferSize =
CeilToMultiple(kOutputDimensions * sizeof(OutputType), kCacheLineSize);
ceil_to_multiple(kOutputDimensions * sizeof(OutputType), kCacheLineSize);
// Size of the forward propagation buffer used from the input layer to this layer
static constexpr std::size_t kBufferSize =
std::max(Head::kBufferSize + kSelfBufferSize, Tail::kBufferSize);
// Hash value embedded in the evaluation function file
static constexpr std::uint32_t GetHashValue() {
static constexpr std::uint32_t get_hash_value() {
std::uint32_t hash_value = 0xBCE400B4u;
hash_value ^= Head::GetHashValue() >> 1;
hash_value ^= Head::GetHashValue() << 31;
hash_value ^= Tail::GetHashValue() >> 2;
hash_value ^= Tail::GetHashValue() << 30;
hash_value ^= Head::get_hash_value() >> 1;
hash_value ^= Head::get_hash_value() << 31;
hash_value ^= Tail::get_hash_value() >> 2;
hash_value ^= Tail::get_hash_value() << 30;
return hash_value;
}
// A string that represents the structure from the input layer to this layer
static std::string GetStructureString() {
static std::string get_structure_string() {
return "Sum[" +
std::to_string(kOutputDimensions) + "](" + GetSummandsString() + ")";
std::to_string(kOutputDimensions) + "](" + get_summands_string() + ")";
}
// read parameters
bool ReadParameters(std::istream& stream) {
if (!Tail::ReadParameters(stream))
bool read_parameters(std::istream& stream) {
if (!Tail::read_parameters(stream))
return false;
return previous_layer_.ReadParameters(stream);
return previous_layer_.read_parameters(stream);
}
// write parameters
bool WriteParameters(std::ostream& stream) const {
if (!Tail::WriteParameters(stream))
bool write_parameters(std::ostream& stream) const {
if (!Tail::write_parameters(stream))
return false;
return previous_layer_.WriteParameters(stream);
return previous_layer_.write_parameters(stream);
}
// forward propagation
const OutputType* Propagate(
const OutputType* propagate(
const TransformedFeatureType* transformed_features, char* buffer) const {
Tail::Propagate(transformed_features, buffer);
Tail::propagate(transformed_features, buffer);
const auto head_output = previous_layer_.Propagate(
const auto head_output = previous_layer_.propagate(
transformed_features, buffer + kSelfBufferSize);
const auto output = reinterpret_cast<OutputType*>(buffer);
@@ -88,8 +88,8 @@ namespace Eval::NNUE::Layers {
protected:
// A string that represents the list of layers to be summed
static std::string GetSummandsString() {
return Head::GetStructureString() + "," + Tail::GetSummandsString();
static std::string get_summands_string() {
return Head::get_structure_string() + "," + Tail::get_summands_string();
}
// Make the learning class a friend
@@ -118,40 +118,40 @@ namespace Eval::NNUE::Layers {
static constexpr std::size_t kBufferSize = PreviousLayer::kBufferSize;
// Hash value embedded in the evaluation function file
static constexpr std::uint32_t GetHashValue() {
static constexpr std::uint32_t get_hash_value() {
std::uint32_t hash_value = 0xBCE400B4u;
hash_value ^= PreviousLayer::GetHashValue() >> 1;
hash_value ^= PreviousLayer::GetHashValue() << 31;
hash_value ^= PreviousLayer::get_hash_value() >> 1;
hash_value ^= PreviousLayer::get_hash_value() << 31;
return hash_value;
}
// A string that represents the structure from the input layer to this layer
static std::string GetStructureString() {
static std::string get_structure_string() {
return "Sum[" +
std::to_string(kOutputDimensions) + "](" + GetSummandsString() + ")";
std::to_string(kOutputDimensions) + "](" + get_summands_string() + ")";
}
// read parameters
bool ReadParameters(std::istream& stream) {
return previous_layer_.ReadParameters(stream);
bool read_parameters(std::istream& stream) {
return previous_layer_.read_parameters(stream);
}
// write parameters
bool WriteParameters(std::ostream& stream) const {
return previous_layer_.WriteParameters(stream);
bool write_parameters(std::ostream& stream) const {
return previous_layer_.write_parameters(stream);
}
// forward propagation
const OutputType* Propagate(
const OutputType* propagate(
const TransformedFeatureType* transformed_features, char* buffer) const {
return previous_layer_.Propagate(transformed_features, buffer);
return previous_layer_.propagate(transformed_features, buffer);
}
protected:
// A string that represents the list of layers to be summed
static std::string GetSummandsString() {
return PreviousLayer::GetStructureString();
static std::string get_summands_string() {
return PreviousLayer::get_structure_string();
}
// Make the learning class a friend

View File

@@ -127,7 +127,7 @@ namespace Eval::NNUE {
// Round n up to be a multiple of base
template <typename IntType>
constexpr IntType CeilToMultiple(IntType n, IntType base) {
constexpr IntType ceil_to_multiple(IntType n, IntType base) {
return (n + base - 1) / base * base;
}

View File

@@ -111,20 +111,20 @@ namespace Eval::NNUE {
kOutputDimensions * sizeof(OutputType);
// Hash value embedded in the evaluation file
static constexpr std::uint32_t GetHashValue() {
static constexpr std::uint32_t get_hash_value() {
return RawFeatures::kHashValue ^ kOutputDimensions;
}
// a string representing the structure
static std::string GetStructureString() {
return RawFeatures::GetName() + "[" +
static std::string get_structure_string() {
return RawFeatures::get_name() + "[" +
std::to_string(kInputDimensions) + "->" +
std::to_string(kHalfDimensions) + "x2]";
}
// Read network parameters
bool ReadParameters(std::istream& stream) {
bool read_parameters(std::istream& stream) {
for (std::size_t i = 0; i < kHalfDimensions; ++i)
biases_[i] = read_little_endian<BiasType>(stream);
@@ -136,7 +136,7 @@ namespace Eval::NNUE {
}
// write parameters
bool WriteParameters(std::ostream& stream) const {
bool write_parameters(std::ostream& stream) const {
stream.write(reinterpret_cast<const char*>(biases_),
kHalfDimensions * sizeof(BiasType));
@@ -147,7 +147,7 @@ namespace Eval::NNUE {
}
// Proceed with the difference calculation if possible
bool UpdateAccumulatorIfPossible(const Position& pos) const {
bool update_accumulator_if_possible(const Position& pos) const {
const auto now = pos.state();
if (now->accumulator.computed_accumulation)
@@ -155,7 +155,7 @@ namespace Eval::NNUE {
const auto prev = now->previous;
if (prev && prev->accumulator.computed_accumulation) {
UpdateAccumulator(pos);
update_accumulator(pos);
return true;
}
@@ -163,10 +163,10 @@ namespace Eval::NNUE {
}
// Convert input features
void Transform(const Position& pos, OutputType* output) const {
void transform(const Position& pos, OutputType* output) const {
if (!UpdateAccumulatorIfPossible(pos))
RefreshAccumulator(pos);
if (!update_accumulator_if_possible(pos))
refresh_accumulator(pos);
const auto& accumulation = pos.state()->accumulator.accumulation;
@@ -294,13 +294,13 @@ namespace Eval::NNUE {
private:
// Calculate cumulative value without using difference calculation
void RefreshAccumulator(const Position& pos) const {
void refresh_accumulator(const Position& pos) const {
auto& accumulator = pos.state()->accumulator;
for (IndexType i = 0; i < kRefreshTriggers.size(); ++i) {
Features::IndexList active_indices[2];
RawFeatures::AppendActiveIndices(pos, kRefreshTriggers[i],
active_indices);
RawFeatures::append_active_indices(pos, kRefreshTriggers[i],
active_indices);
for (Color perspective : { WHITE, BLACK }) {
#ifdef TILING
for (unsigned j = 0; j < kHalfDimensions / kTileHeight; ++j) {
@@ -357,15 +357,15 @@ namespace Eval::NNUE {
}
// Calculate cumulative value using difference calculation
void UpdateAccumulator(const Position& pos) const {
void update_accumulator(const Position& pos) const {
const auto& prev_accumulator = pos.state()->previous->accumulator;
auto& accumulator = pos.state()->accumulator;
for (IndexType i = 0; i < kRefreshTriggers.size(); ++i) {
Features::IndexList removed_indices[2], added_indices[2];
bool reset[2] = { false, false };
RawFeatures::AppendChangedIndices(pos, kRefreshTriggers[i],
removed_indices, added_indices, reset);
RawFeatures::append_changed_indices(pos, kRefreshTriggers[i],
removed_indices, added_indices, reset);
#ifdef TILING
for (IndexType j = 0; j < kHalfDimensions / kTileHeight; ++j) {

View File

@@ -24,7 +24,7 @@ namespace Eval::NNUE {
namespace {
// Testing RawFeatures mainly for difference calculation
void TestFeatures(Position& pos) {
void test_features(Position& pos) {
const std::uint64_t num_games = 1000;
StateInfo si;
pos.set(StartFEN, false, &si, Threads.main());
@@ -47,7 +47,7 @@ namespace Eval::NNUE {
for (IndexType i = 0; i < kRefreshTriggers.size(); ++i) {
Features::IndexList active_indices[2];
RawFeatures::AppendActiveIndices(position, kRefreshTriggers[i],
RawFeatures::append_active_indices(position, kRefreshTriggers[i],
active_indices);
for (const auto perspective : Colors) {
@@ -68,7 +68,7 @@ namespace Eval::NNUE {
for (IndexType i = 0; i < kRefreshTriggers.size(); ++i) {
Features::IndexList removed_indices[2], added_indices[2];
bool reset[2] = { false, false };
RawFeatures::AppendChangedIndices(position, kRefreshTriggers[i],
RawFeatures::append_changed_indices(position, kRefreshTriggers[i],
removed_indices, added_indices, reset);
for (const auto perspective : Colors) {
if (reset[perspective]) {
@@ -99,7 +99,7 @@ namespace Eval::NNUE {
}
};
std::cout << "feature set: " << RawFeatures::GetName()
std::cout << "feature set: " << RawFeatures::get_name()
<< "[" << RawFeatures::kDimensions << "]" << std::endl;
std::cout << "start testing with random games";
@@ -154,8 +154,8 @@ namespace Eval::NNUE {
}
// Output a string that represents the structure of the evaluation function
void PrintInfo(std::istream& stream) {
std::cout << "network architecture: " << GetArchitectureString() << std::endl;
void print_info(std::istream& stream) {
std::cout << "network architecture: " << get_architecture_string() << std::endl;
while (true) {
std::string file_name;
@@ -170,7 +170,7 @@ namespace Eval::NNUE {
if (!file_stream)
return false;
if (!ReadHeader(file_stream, &hash_value, &architecture))
if (!read_header(file_stream, &hash_value, &architecture))
return false;
return true;
@@ -180,7 +180,7 @@ namespace Eval::NNUE {
if (success) {
if (hash_value == kHashValue) {
std::cout << "matches with this binary";
if (architecture != GetArchitectureString()) {
if (architecture != get_architecture_string()) {
std::cout << ", but architecture string differs: " << architecture;
}
@@ -197,14 +197,14 @@ namespace Eval::NNUE {
} // namespace
// USI extended command for NNUE evaluation function
void TestCommand(Position& pos, std::istream& stream) {
void test_command(Position& pos, std::istream& stream) {
std::string sub_command;
stream >> sub_command;
if (sub_command == "test_features") {
TestFeatures(pos);
test_features(pos);
} else if (sub_command == "info") {
PrintInfo(stream);
print_info(stream);
} else {
std::cout << "usage:" << std::endl;
std::cout << " test nnue test_features" << std::endl;

View File

@@ -5,7 +5,7 @@
namespace Eval::NNUE {
// USI extended command for NNUE evaluation function
void TestCommand(Position& pos, std::istream& stream);
void test_command(Position& pos, std::istream& stream);
} // namespace Eval::NNUE

View File

@@ -14,12 +14,12 @@ namespace Eval::NNUE::Features {
class Factorizer {
public:
// Get the dimensionality of the learning feature
static constexpr IndexType GetDimensions() {
static constexpr IndexType get_dimensions() {
return FeatureType::kDimensions;
}
// Get index of learning feature and scale of learning rate
static void AppendTrainingFeatures(
static void append_training_features(
IndexType base_index, std::vector<TrainingFeature>* training_features) {
assert(base_index <FeatureType::kDimensions);
@@ -35,7 +35,7 @@ namespace Eval::NNUE::Features {
// Add the original input features to the learning features
template <typename FeatureType>
IndexType AppendBaseFeature(
IndexType append_base_feature(
FeatureProperties properties, IndexType base_index,
std::vector<TrainingFeature>* training_features) {
@@ -47,7 +47,7 @@ namespace Eval::NNUE::Features {
// If the learning rate scale is not 0, inherit other types of learning features
template <typename FeatureType>
IndexType InheritFeaturesIfRequired(
IndexType inherit_features_if_required(
IndexType index_offset, FeatureProperties properties, IndexType base_index,
std::vector<TrainingFeature>* training_features) {
@@ -55,17 +55,17 @@ namespace Eval::NNUE::Features {
return 0;
}
assert(properties.dimensions == Factorizer<FeatureType>::GetDimensions());
assert(properties.dimensions == Factorizer<FeatureType>::get_dimensions());
assert(base_index < FeatureType::kDimensions);
const auto start = training_features->size();
Factorizer<FeatureType>::AppendTrainingFeatures(
Factorizer<FeatureType>::append_training_features(
base_index, training_features);
for (auto i = start; i < training_features->size(); ++i) {
auto& feature = (*training_features)[i];
assert(feature.GetIndex() < Factorizer<FeatureType>::GetDimensions());
feature.ShiftIndex(index_offset);
assert(feature.get_index() < Factorizer<FeatureType>::get_dimensions());
feature.shift_index(index_offset);
}
return properties.dimensions;
@@ -73,7 +73,7 @@ namespace Eval::NNUE::Features {
// Return the index difference as needed, without adding learning features
// Call instead of InheritFeaturesIfRequired() if there are no corresponding features
IndexType SkipFeatures(FeatureProperties properties) {
IndexType skip_features(FeatureProperties properties) {
if (!properties.active)
return 0;
@@ -82,7 +82,7 @@ namespace Eval::NNUE::Features {
// Get the dimensionality of the learning feature
template <std::size_t N>
constexpr IndexType GetActiveDimensions(
constexpr IndexType get_active_dimensions(
const FeatureProperties (&properties)[N]) {
static_assert(N > 0, "");
@@ -100,7 +100,7 @@ namespace Eval::NNUE::Features {
// get the number of elements in the array
template <typename T, std::size_t N>
constexpr std::size_t GetArrayLength(const T (&/*array*/)[N]) {
constexpr std::size_t get_array_length(const T (&/*array*/)[N]) {
return N;
}

View File

@@ -22,12 +22,12 @@ namespace Eval::NNUE::Features {
FeatureSet<FirstFeatureType, RemainingFeatureTypes...>::kDimensions;
// Get the dimensionality of the learning feature
static constexpr IndexType GetDimensions() {
return Head::GetDimensions() + Tail::GetDimensions();
static constexpr IndexType get_dimensions() {
return Head::get_dimensions() + Tail::get_dimensions();
}
// Get index of learning feature and scale of learning rate
static void AppendTrainingFeatures(
static void append_training_features(
IndexType base_index, std::vector<TrainingFeature>* training_features,
IndexType base_dimensions = kBaseDimensions) {
@@ -36,29 +36,29 @@ namespace Eval::NNUE::Features {
constexpr auto boundary = FeatureSet<RemainingFeatureTypes...>::kDimensions;
if (base_index < boundary) {
Tail::AppendTrainingFeatures(
Tail::append_training_features(
base_index, training_features, base_dimensions);
}
else {
const auto start = training_features->size();
Head::AppendTrainingFeatures(
Head::append_training_features(
base_index - boundary, training_features, base_dimensions);
for (auto i = start; i < training_features->size(); ++i) {
auto& feature = (*training_features)[i];
const auto index = feature.GetIndex();
const auto index = feature.get_index();
assert(index < Head::GetDimensions() ||
assert(index < Head::get_dimensions() ||
(index >= base_dimensions &&
index < base_dimensions +
Head::GetDimensions() - Head::kBaseDimensions));
Head::get_dimensions() - Head::kBaseDimensions));
if (index < Head::kBaseDimensions) {
feature.ShiftIndex(Tail::kBaseDimensions);
feature.shift_index(Tail::kBaseDimensions);
}
else {
feature.ShiftIndex(Tail::GetDimensions() - Tail::kBaseDimensions);
feature.shift_index(Tail::get_dimensions() - Tail::kBaseDimensions);
}
}
}
@@ -74,12 +74,12 @@ namespace Eval::NNUE::Features {
static constexpr IndexType kBaseDimensions = FeatureType::kDimensions;
// Get the dimensionality of the learning feature
static constexpr IndexType GetDimensions() {
return Factorizer<FeatureType>::GetDimensions();
static constexpr IndexType get_dimensions() {
return Factorizer<FeatureType>::get_dimensions();
}
// Get index of learning feature and scale of learning rate
static void AppendTrainingFeatures(
static void append_training_features(
IndexType base_index, std::vector<TrainingFeature>* training_features,
IndexType base_dimensions = kBaseDimensions) {
@@ -87,14 +87,14 @@ namespace Eval::NNUE::Features {
const auto start = training_features->size();
Factorizer<FeatureType>::AppendTrainingFeatures(
Factorizer<FeatureType>::append_training_features(
base_index, training_features);
for (auto i = start; i < training_features->size(); ++i) {
auto& feature = (*training_features)[i];
assert(feature.GetIndex() < Factorizer<FeatureType>::GetDimensions());
if (feature.GetIndex() >= kBaseDimensions) {
feature.ShiftIndex(base_dimensions - kBaseDimensions);
assert(feature.get_index() < Factorizer<FeatureType>::get_dimensions());
if (feature.get_index() >= kBaseDimensions) {
feature.shift_index(base_dimensions - kBaseDimensions);
}
}
}

View File

@@ -37,25 +37,25 @@ namespace Eval::NNUE::Features {
// kFeaturesHalfK
{true, SQUARE_NB},
// kFeaturesP
{true, Factorizer<P>::GetDimensions()},
{true, Factorizer<P>::get_dimensions()},
// kFeaturesHalfRelativeKP
{true, Factorizer<HalfRelativeKP<AssociatedKing>>::GetDimensions()},
{true, Factorizer<HalfRelativeKP<AssociatedKing>>::get_dimensions()},
};
static_assert(GetArrayLength(kProperties) == kNumTrainingFeatureTypes, "");
static_assert(get_array_length(kProperties) == kNumTrainingFeatureTypes, "");
public:
// Get the dimensionality of the learning feature
static constexpr IndexType GetDimensions() {
return GetActiveDimensions(kProperties);
static constexpr IndexType get_dimensions() {
return get_active_dimensions(kProperties);
}
// Get index of learning feature and scale of learning rate
static void AppendTrainingFeatures(
static void append_training_features(
IndexType base_index, std::vector<TrainingFeature>* training_features) {
// kFeaturesHalfKP
IndexType index_offset = AppendBaseFeature<FeatureType>(
IndexType index_offset = append_base_feature<FeatureType>(
kProperties[kFeaturesHalfKP], base_index, training_features);
const auto sq_k = static_cast<Square>(base_index / PS_END);
@@ -71,20 +71,20 @@ namespace Eval::NNUE::Features {
}
// kFeaturesP
index_offset += InheritFeaturesIfRequired<P>(
index_offset += inherit_features_if_required<P>(
index_offset, kProperties[kFeaturesP], p, training_features);
// kFeaturesHalfRelativeKP
if (p >= PS_W_PAWN) {
index_offset += InheritFeaturesIfRequired<HalfRelativeKP<AssociatedKing>>(
index_offset += inherit_features_if_required<HalfRelativeKP<AssociatedKing>>(
index_offset, kProperties[kFeaturesHalfRelativeKP],
HalfRelativeKP<AssociatedKing>::MakeIndex(sq_k, p),
HalfRelativeKP<AssociatedKing>::make_index(sq_k, p),
training_features);
}
else {
index_offset += SkipFeatures(kProperties[kFeaturesHalfRelativeKP]);
index_offset += skip_features(kProperties[kFeaturesHalfRelativeKP]);
}
assert(index_offset == GetDimensions());
assert(index_offset == get_dimensions());
}
};

View File

@@ -37,22 +37,22 @@ namespace Eval::NNUE {
}
TrainingFeature& operator+=(const TrainingFeature& other) {
assert(other.GetIndex() == GetIndex());
assert(other.GetCount() + GetCount() < (1 << kCountBits));
index_and_count_ += other.GetCount();
assert(other.get_index() == get_index());
assert(other.get_index() + get_count() < (1 << kCountBits));
index_and_count_ += other.get_count();
return *this;
}
IndexType GetIndex() const {
IndexType get_index() const {
return static_cast<IndexType>(index_and_count_ >> kCountBits);
}
void ShiftIndex(IndexType offset) {
assert(GetIndex() + offset < (1 << kIndexBits));
void shift_index(IndexType offset) {
assert(get_index() + offset < (1 << kIndexBits));
index_and_count_ += offset << kCountBits;
}
IndexType GetCount() const {
IndexType get_count() const {
return static_cast<IndexType>(index_and_count_ & ((1 << kCountBits) - 1));
}
@@ -86,7 +86,7 @@ namespace Eval::NNUE {
};
// determine whether to accept the message
bool ReceiveMessage(const std::string& name, Message* message) {
bool receive_message(const std::string& name, Message* message) {
const auto subscript = "[" + std::to_string(message->num_peekers) + "]";
if (message->name.substr(0, name.size() + 1) == name + "[") {
@@ -101,28 +101,15 @@ namespace Eval::NNUE {
return false;
}
// split the string
std::vector<std::string> Split(const std::string& input, char delimiter) {
std::istringstream stream(input);
std::string field;
std::vector<std::string> fields;
while (std::getline(stream, field, delimiter)) {
fields.push_back(field);
}
return fields;
}
// round a floating point number to an integer
template <typename IntType>
IntType Round(double value) {
IntType round(double value) {
return static_cast<IntType>(std::floor(value + 0.5));
}
// make_shared with alignment
template <typename T, typename... ArgumentTypes>
std::shared_ptr<T> MakeAlignedSharedPtr(ArgumentTypes&&... arguments) {
std::shared_ptr<T> make_aligned_shared_ptr(ArgumentTypes&&... arguments) {
const auto ptr = new(std_aligned_alloc(alignof(T), sizeof(T)))
T(std::forward<ArgumentTypes>(arguments)...);

View File

@@ -21,7 +21,7 @@ namespace Eval::NNUE {
public:
// factory function
static std::shared_ptr<Trainer> Create(
static std::shared_ptr<Trainer> create(
LayerType* target_layer, FeatureTransformer* ft) {
return std::shared_ptr<Trainer>(
@@ -29,31 +29,31 @@ namespace Eval::NNUE {
}
// Set options such as hyperparameters
void SendMessage(Message* message) {
previous_layer_trainer_->SendMessage(message);
void send_message(Message* message) {
previous_layer_trainer_->send_message(message);
if (ReceiveMessage("momentum", message)) {
if (receive_message("momentum", message)) {
momentum_ = static_cast<LearnFloatType>(std::stod(message->value));
}
if (ReceiveMessage("learning_rate_scale", message)) {
if (receive_message("learning_rate_scale", message)) {
learning_rate_scale_ =
static_cast<LearnFloatType>(std::stod(message->value));
}
if (ReceiveMessage("reset", message)) {
DequantizeParameters();
if (receive_message("reset", message)) {
dequantize_parameters();
}
if (ReceiveMessage("quantize_parameters", message)) {
QuantizeParameters();
if (receive_message("quantize_parameters", message)) {
quantize_parameters();
}
}
// Initialize the parameters with random numbers
template <typename RNG>
void Initialize(RNG& rng) {
previous_layer_trainer_->Initialize(rng);
void initialize(RNG& rng) {
previous_layer_trainer_->initialize(rng);
if (kIsOutputLayer) {
// Initialize output layer with 0
@@ -80,18 +80,18 @@ namespace Eval::NNUE {
}
}
QuantizeParameters();
quantize_parameters();
}
// forward propagation
const LearnFloatType* Propagate(const std::vector<Example>& batch) {
const LearnFloatType* propagate(const std::vector<Example>& batch) {
if (output_.size() < kOutputDimensions * batch.size()) {
output_.resize(kOutputDimensions * batch.size());
gradients_.resize(kInputDimensions * batch.size());
}
batch_size_ = static_cast<IndexType>(batch.size());
batch_input_ = previous_layer_trainer_->Propagate(batch);
batch_input_ = previous_layer_trainer_->propagate(batch);
#if defined(USE_BLAS)
for (IndexType b = 0; b < batch_size_; ++b) {
const IndexType batch_offset = kOutputDimensions * b;
@@ -123,7 +123,7 @@ namespace Eval::NNUE {
}
// backpropagation
void Backpropagate(const LearnFloatType* gradients,
void backpropagate(const LearnFloatType* gradients,
LearnFloatType learning_rate) {
const LearnFloatType local_learning_rate =
@@ -206,7 +206,7 @@ namespace Eval::NNUE {
}
#endif
previous_layer_trainer_->Backpropagate(gradients_.data(), learning_rate);
previous_layer_trainer_->backpropagate(gradients_.data(), learning_rate);
}
private:
@@ -214,7 +214,7 @@ namespace Eval::NNUE {
Trainer(LayerType* target_layer, FeatureTransformer* ft) :
batch_size_(0),
batch_input_(nullptr),
previous_layer_trainer_(Trainer<PreviousLayer>::Create(
previous_layer_trainer_(Trainer<PreviousLayer>::create(
&target_layer->previous_layer_, ft)),
target_layer_(target_layer),
biases_(),
@@ -224,11 +224,11 @@ namespace Eval::NNUE {
momentum_(0.2),
learning_rate_scale_(1.0) {
DequantizeParameters();
dequantize_parameters();
}
// Weight saturation and parameterization
void QuantizeParameters() {
void quantize_parameters() {
for (IndexType i = 0; i < kOutputDimensions * kInputDimensions; ++i) {
weights_[i] = std::max(-kMaxWeightMagnitude,
std::min(+kMaxWeightMagnitude, weights_[i]));
@@ -236,7 +236,7 @@ namespace Eval::NNUE {
for (IndexType i = 0; i < kOutputDimensions; ++i) {
target_layer_->biases_[i] =
Round<typename LayerType::BiasType>(biases_[i] * kBiasScale);
round<typename LayerType::BiasType>(biases_[i] * kBiasScale);
}
for (IndexType i = 0; i < kOutputDimensions; ++i) {
@@ -244,14 +244,14 @@ namespace Eval::NNUE {
const auto padded_offset = LayerType::kPaddedInputDimensions * i;
for (IndexType j = 0; j < kInputDimensions; ++j) {
target_layer_->weights_[padded_offset + j] =
Round<typename LayerType::WeightType>(
round<typename LayerType::WeightType>(
weights_[offset + j] * kWeightScale);
}
}
}
// read parameterized integer
void DequantizeParameters() {
void dequantize_parameters() {
for (IndexType i = 0; i < kOutputDimensions; ++i) {
biases_[i] = static_cast<LearnFloatType>(
target_layer_->biases_[i] / kBiasScale);

View File

@@ -19,7 +19,7 @@ namespace Eval::NNUE {
public:
// factory function
static std::shared_ptr<Trainer> Create(
static std::shared_ptr<Trainer> create(
LayerType* target_layer, FeatureTransformer* ft) {
return std::shared_ptr<Trainer>(
@@ -27,27 +27,27 @@ namespace Eval::NNUE {
}
// Set options such as hyperparameters
void SendMessage(Message* message) {
previous_layer_trainer_->SendMessage(message);
if (ReceiveMessage("check_health", message)) {
CheckHealth();
void send_message(Message* message) {
previous_layer_trainer_->send_message(message);
if (receive_message("check_health", message)) {
check_health();
}
}
// Initialize the parameters with random numbers
template <typename RNG>
void Initialize(RNG& rng) {
previous_layer_trainer_->Initialize(rng);
void initialize(RNG& rng) {
previous_layer_trainer_->initialize(rng);
}
// forward propagation
const LearnFloatType* Propagate(const std::vector<Example>& batch) {
const LearnFloatType* propagate(const std::vector<Example>& batch) {
if (output_.size() < kOutputDimensions * batch.size()) {
output_.resize(kOutputDimensions * batch.size());
gradients_.resize(kInputDimensions * batch.size());
}
const auto input = previous_layer_trainer_->Propagate(batch);
const auto input = previous_layer_trainer_->propagate(batch);
batch_size_ = static_cast<IndexType>(batch.size());
for (IndexType b = 0; b < batch_size_; ++b) {
const IndexType batch_offset = kOutputDimensions * b;
@@ -63,7 +63,7 @@ namespace Eval::NNUE {
}
// backpropagation
void Backpropagate(const LearnFloatType* gradients,
void backpropagate(const LearnFloatType* gradients,
LearnFloatType learning_rate) {
for (IndexType b = 0; b < batch_size_; ++b) {
@@ -75,14 +75,14 @@ namespace Eval::NNUE {
}
}
previous_layer_trainer_->Backpropagate(gradients_.data(), learning_rate);
previous_layer_trainer_->backpropagate(gradients_.data(), learning_rate);
}
private:
// constructor
Trainer(LayerType* target_layer, FeatureTransformer* ft) :
batch_size_(0),
previous_layer_trainer_(Trainer<PreviousLayer>::Create(
previous_layer_trainer_(Trainer<PreviousLayer>::create(
&target_layer->previous_layer_, ft)),
target_layer_(target_layer) {
@@ -93,7 +93,7 @@ namespace Eval::NNUE {
}
// Check if there are any problems with learning
void CheckHealth() {
void check_health() {
const auto largest_min_activation = *std::max_element(
std::begin(min_activations_), std::end(min_activations_));
const auto smallest_max_activation = *std::min_element(

View File

@@ -34,44 +34,44 @@ namespace Eval::NNUE {
friend struct AlignedDeleter;
template <typename T, typename... ArgumentTypes>
friend std::shared_ptr<T> MakeAlignedSharedPtr(ArgumentTypes&&... arguments);
friend std::shared_ptr<T> make_aligned_shared_ptr(ArgumentTypes&&... arguments);
// factory function
static std::shared_ptr<Trainer> Create(LayerType* target_layer) {
return MakeAlignedSharedPtr<Trainer>(target_layer);
static std::shared_ptr<Trainer> create(LayerType* target_layer) {
return make_aligned_shared_ptr<Trainer>(target_layer);
}
// Set options such as hyperparameters
void SendMessage(Message* message) {
if (ReceiveMessage("momentum", message)) {
void send_message(Message* message) {
if (receive_message("momentum", message)) {
momentum_ = static_cast<LearnFloatType>(std::stod(message->value));
}
if (ReceiveMessage("learning_rate_scale", message)) {
if (receive_message("learning_rate_scale", message)) {
learning_rate_scale_ =
static_cast<LearnFloatType>(std::stod(message->value));
}
if (ReceiveMessage("reset", message)) {
DequantizeParameters();
if (receive_message("reset", message)) {
dequantize_parameters();
}
if (ReceiveMessage("quantize_parameters", message)) {
QuantizeParameters();
if (receive_message("quantize_parameters", message)) {
quantize_parameters();
}
if (ReceiveMessage("clear_unobserved_feature_weights", message)) {
ClearUnobservedFeatureWeights();
if (receive_message("clear_unobserved_feature_weights", message)) {
clear_unobserved_feature_weights();
}
if (ReceiveMessage("check_health", message)) {
CheckHealth();
if (receive_message("check_health", message)) {
check_health();
}
}
// Initialize the parameters with random numbers
template <typename RNG>
void Initialize(RNG& rng) {
void initialize(RNG& rng) {
std::fill(std::begin(weights_), std::end(weights_), +kZero);
const double kSigma = 0.1 / std::sqrt(RawFeatures::kMaxActiveDimensions);
@@ -86,11 +86,11 @@ namespace Eval::NNUE {
biases_[i] = static_cast<LearnFloatType>(0.5);
}
QuantizeParameters();
quantize_parameters();
}
// forward propagation
const LearnFloatType* Propagate(const std::vector<Example>& batch) {
const LearnFloatType* propagate(const std::vector<Example>& batch) {
if (output_.size() < kOutputDimensions * batch.size()) {
output_.resize(kOutputDimensions * batch.size());
gradients_.resize(kOutputDimensions * batch.size());
@@ -106,8 +106,8 @@ namespace Eval::NNUE {
#if defined(USE_BLAS)
cblas_scopy(kHalfDimensions, biases_, 1, &output_[output_offset], 1);
for (const auto& feature : batch[b].training_features[c]) {
const IndexType weights_offset = kHalfDimensions * feature.GetIndex();
cblas_saxpy(kHalfDimensions, (float)feature.GetCount(),
const IndexType weights_offset = kHalfDimensions * feature.get_index();
cblas_saxpy(kHalfDimensions, (float)feature.get_count(),
&weights_[weights_offset], 1, &output_[output_offset], 1);
}
#else
@@ -115,10 +115,10 @@ namespace Eval::NNUE {
output_[output_offset + i] = biases_[i];
}
for (const auto& feature : batch[b].training_features[c]) {
const IndexType weights_offset = kHalfDimensions * feature.GetIndex();
const IndexType weights_offset = kHalfDimensions * feature.get_index();
for (IndexType i = 0; i < kHalfDimensions; ++i) {
output_[output_offset + i] +=
feature.GetCount() * weights_[weights_offset + i];
feature.get_count() * weights_[weights_offset + i];
}
}
#endif
@@ -143,7 +143,7 @@ namespace Eval::NNUE {
}
// backpropagation
void Backpropagate(const LearnFloatType* gradients,
void backpropagate(const LearnFloatType* gradients,
LearnFloatType learning_rate) {
const LearnFloatType local_learning_rate =
@@ -188,13 +188,13 @@ namespace Eval::NNUE {
const IndexType output_offset = batch_offset + kHalfDimensions * c;
for (const auto& feature : (*batch_)[b].training_features[c]) {
#if defined(_OPENMP)
if (feature.GetIndex() % num_threads != thread_index)
if (feature.get_index() % num_threads != thread_index)
continue;
#endif
const IndexType weights_offset =
kHalfDimensions * feature.GetIndex();
kHalfDimensions * feature.get_index();
const auto scale = static_cast<LearnFloatType>(
effective_learning_rate / feature.GetCount());
effective_learning_rate / feature.get_count());
cblas_saxpy(kHalfDimensions, -scale,
&gradients_[output_offset], 1,
@@ -228,9 +228,9 @@ namespace Eval::NNUE {
for (IndexType c = 0; c < 2; ++c) {
const IndexType output_offset = batch_offset + kHalfDimensions * c;
for (const auto& feature : (*batch_)[b].training_features[c]) {
const IndexType weights_offset = kHalfDimensions * feature.GetIndex();
const IndexType weights_offset = kHalfDimensions * feature.get_index();
const auto scale = static_cast<LearnFloatType>(
effective_learning_rate / feature.GetCount());
effective_learning_rate / feature.get_count());
for (IndexType i = 0; i < kHalfDimensions; ++i) {
weights_[weights_offset + i] -=
@@ -244,7 +244,7 @@ namespace Eval::NNUE {
for (IndexType b = 0; b < batch_->size(); ++b) {
for (IndexType c = 0; c < 2; ++c) {
for (const auto& feature : (*batch_)[b].training_features[c]) {
observed_features.set(feature.GetIndex());
observed_features.set(feature.get_index());
}
}
}
@@ -269,14 +269,14 @@ namespace Eval::NNUE {
std::fill(std::begin(max_activations_), std::end(max_activations_),
std::numeric_limits<LearnFloatType>::lowest());
DequantizeParameters();
dequantize_parameters();
}
// Weight saturation and parameterization
void QuantizeParameters() {
void quantize_parameters() {
for (IndexType i = 0; i < kHalfDimensions; ++i) {
target_layer_->biases_[i] =
Round<typename LayerType::BiasType>(biases_[i] * kBiasScale);
round<typename LayerType::BiasType>(biases_[i] * kBiasScale);
}
std::vector<TrainingFeature> training_features;
@@ -284,23 +284,23 @@ namespace Eval::NNUE {
#pragma omp parallel for private(training_features)
for (IndexType j = 0; j < RawFeatures::kDimensions; ++j) {
training_features.clear();
Features::Factorizer<RawFeatures>::AppendTrainingFeatures(
Features::Factorizer<RawFeatures>::append_training_features(
j, &training_features);
for (IndexType i = 0; i < kHalfDimensions; ++i) {
double sum = 0.0;
for (const auto& feature : training_features) {
sum += weights_[kHalfDimensions * feature.GetIndex() + i];
sum += weights_[kHalfDimensions * feature.get_index() + i];
}
target_layer_->weights_[kHalfDimensions * j + i] =
Round<typename LayerType::WeightType>(sum * kWeightScale);
round<typename LayerType::WeightType>(sum * kWeightScale);
}
}
}
// read parameterized integer
void DequantizeParameters() {
void dequantize_parameters() {
for (IndexType i = 0; i < kHalfDimensions; ++i) {
biases_[i] = static_cast<LearnFloatType>(
target_layer_->biases_[i] / kBiasScale);
@@ -317,7 +317,7 @@ namespace Eval::NNUE {
}
// Set the weight corresponding to the feature that does not appear in the learning data to 0
void ClearUnobservedFeatureWeights() {
void clear_unobserved_feature_weights() {
for (IndexType i = 0; i < kInputDimensions; ++i) {
if (!observed_features.test(i)) {
std::fill(std::begin(weights_) + kHalfDimensions * i,
@@ -325,11 +325,11 @@ namespace Eval::NNUE {
}
}
QuantizeParameters();
quantize_parameters();
}
// Check if there are any problems with learning
void CheckHealth() {
void check_health() {
std::cout << "INFO: observed " << observed_features.count()
<< " (out of " << kInputDimensions << ") features" << std::endl;
@@ -359,7 +359,7 @@ namespace Eval::NNUE {
// number of input/output dimensions
static constexpr IndexType kInputDimensions =
Features::Factorizer<RawFeatures>::GetDimensions();
Features::Factorizer<RawFeatures>::get_dimensions();
static constexpr IndexType kOutputDimensions = LayerType::kOutputDimensions;
static constexpr IndexType kHalfDimensions = LayerType::kHalfDimensions;

View File

@@ -14,7 +14,7 @@ namespace Eval::NNUE {
class SharedInputTrainer {
public:
// factory function
static std::shared_ptr<SharedInputTrainer> Create(
static std::shared_ptr<SharedInputTrainer> create(
FeatureTransformer* ft) {
static std::shared_ptr<SharedInputTrainer> instance;
@@ -29,10 +29,10 @@ namespace Eval::NNUE {
}
// Set options such as hyperparameters
void SendMessage(Message* message) {
void send_message(Message* message) {
if (num_calls_ == 0) {
current_operation_ = Operation::kSendMessage;
feature_transformer_trainer_->SendMessage(message);
feature_transformer_trainer_->send_message(message);
}
assert(current_operation_ == Operation::kSendMessage);
@@ -45,10 +45,10 @@ namespace Eval::NNUE {
// Initialize the parameters with random numbers
template <typename RNG>
void Initialize(RNG& rng) {
void initialize(RNG& rng) {
if (num_calls_ == 0) {
current_operation_ = Operation::kInitialize;
feature_transformer_trainer_->Initialize(rng);
feature_transformer_trainer_->initialize(rng);
}
assert(current_operation_ == Operation::kInitialize);
@@ -60,7 +60,7 @@ namespace Eval::NNUE {
}
// forward propagation
const LearnFloatType* Propagate(const std::vector<Example>& batch) {
const LearnFloatType* propagate(const std::vector<Example>& batch) {
if (gradients_.size() < kInputDimensions * batch.size()) {
gradients_.resize(kInputDimensions * batch.size());
}
@@ -69,7 +69,7 @@ namespace Eval::NNUE {
if (num_calls_ == 0) {
current_operation_ = Operation::kPropagate;
output_ = feature_transformer_trainer_->Propagate(batch);
output_ = feature_transformer_trainer_->propagate(batch);
}
assert(current_operation_ == Operation::kPropagate);
@@ -83,11 +83,11 @@ namespace Eval::NNUE {
}
// backpropagation
void Backpropagate(const LearnFloatType* gradients,
void backpropagate(const LearnFloatType* gradients,
LearnFloatType learning_rate) {
if (num_referrers_ == 1) {
feature_transformer_trainer_->Backpropagate(gradients, learning_rate);
feature_transformer_trainer_->backpropagate(gradients, learning_rate);
return;
}
@@ -111,7 +111,7 @@ namespace Eval::NNUE {
}
if (++num_calls_ == num_referrers_) {
feature_transformer_trainer_->Backpropagate(
feature_transformer_trainer_->backpropagate(
gradients_.data(), learning_rate);
num_calls_ = 0;
current_operation_ = Operation::kNone;
@@ -125,7 +125,7 @@ namespace Eval::NNUE {
num_referrers_(0),
num_calls_(0),
current_operation_(Operation::kNone),
feature_transformer_trainer_(Trainer<FeatureTransformer>::Create(
feature_transformer_trainer_(Trainer<FeatureTransformer>::create(
ft)),
output_(nullptr) {
}
@@ -175,25 +175,25 @@ namespace Eval::NNUE {
public:
// factory function
static std::shared_ptr<Trainer> Create(
static std::shared_ptr<Trainer> create(
LayerType* /*target_layer*/, FeatureTransformer* ft) {
return std::shared_ptr<Trainer>(new Trainer(ft));
}
// Set options such as hyperparameters
void SendMessage(Message* message) {
shared_input_trainer_->SendMessage(message);
void send_message(Message* message) {
shared_input_trainer_->send_message(message);
}
// Initialize the parameters with random numbers
template <typename RNG>
void Initialize(RNG& rng) {
shared_input_trainer_->Initialize(rng);
void initialize(RNG& rng) {
shared_input_trainer_->initialize(rng);
}
// forward propagation
const LearnFloatType* Propagate(const std::vector<Example>& batch) {
const LearnFloatType* propagate(const std::vector<Example>& batch) {
if (output_.size() < kOutputDimensions * batch.size()) {
output_.resize(kOutputDimensions * batch.size());
gradients_.resize(kInputDimensions * batch.size());
@@ -201,7 +201,7 @@ namespace Eval::NNUE {
batch_size_ = static_cast<IndexType>(batch.size());
const auto input = shared_input_trainer_->Propagate(batch);
const auto input = shared_input_trainer_->propagate(batch);
for (IndexType b = 0; b < batch_size_; ++b) {
const IndexType input_offset = kInputDimensions * b;
const IndexType output_offset = kOutputDimensions * b;
@@ -219,7 +219,7 @@ namespace Eval::NNUE {
}
// backpropagation
void Backpropagate(const LearnFloatType* gradients,
void backpropagate(const LearnFloatType* gradients,
LearnFloatType learning_rate) {
for (IndexType b = 0; b < batch_size_; ++b) {
@@ -233,14 +233,14 @@ namespace Eval::NNUE {
}
}
}
shared_input_trainer_->Backpropagate(gradients_.data(), learning_rate);
shared_input_trainer_->backpropagate(gradients_.data(), learning_rate);
}
private:
// constructor
Trainer(FeatureTransformer* ft):
batch_size_(0),
shared_input_trainer_(SharedInputTrainer::Create(ft)) {
shared_input_trainer_(SharedInputTrainer::create(ft)) {
}
// number of input/output dimensions

View File

@@ -21,7 +21,7 @@ namespace Eval::NNUE {
public:
// factory function
static std::shared_ptr<Trainer> Create(
static std::shared_ptr<Trainer> create(
LayerType* target_layer, FeatureTransformer* ft) {
return std::shared_ptr<Trainer>(
@@ -29,26 +29,26 @@ namespace Eval::NNUE {
}
// Set options such as hyperparameters
void SendMessage(Message* message) {
void send_message(Message* message) {
// The results of other member functions do not depend on the processing order, so
// Tail is processed first for the purpose of simplifying the implementation, but
// SendMessage processes Head first to make it easier to understand subscript correspondence
previous_layer_trainer_->SendMessage(message);
Tail::SendMessage(message);
previous_layer_trainer_->send_message(message);
Tail::send_message(message);
}
// Initialize the parameters with random numbers
template <typename RNG>
void Initialize(RNG& rng) {
Tail::Initialize(rng);
previous_layer_trainer_->Initialize(rng);
void initialize(RNG& rng) {
Tail::initialize(rng);
previous_layer_trainer_->initialize(rng);
}
// forward propagation
/*const*/ LearnFloatType* Propagate(const std::vector<Example>& batch) {
/*const*/ LearnFloatType* propagate(const std::vector<Example>& batch) {
batch_size_ = static_cast<IndexType>(batch.size());
auto output = Tail::Propagate(batch);
const auto head_output = previous_layer_trainer_->Propagate(batch);
auto output = Tail::propagate(batch);
const auto head_output = previous_layer_trainer_->propagate(batch);
#if defined(USE_BLAS)
cblas_saxpy(kOutputDimensions * batch_size_, 1.0,
@@ -66,11 +66,11 @@ namespace Eval::NNUE {
}
// backpropagation
void Backpropagate(const LearnFloatType* gradients,
void backpropagate(const LearnFloatType* gradients,
LearnFloatType learning_rate) {
Tail::Backpropagate(gradients, learning_rate);
previous_layer_trainer_->Backpropagate(gradients, learning_rate);
Tail::backpropagate(gradients, learning_rate);
previous_layer_trainer_->backpropagate(gradients, learning_rate);
}
private:
@@ -78,7 +78,7 @@ namespace Eval::NNUE {
Trainer(LayerType* target_layer, FeatureTransformer* ft):
Tail(target_layer, ft),
batch_size_(0),
previous_layer_trainer_(Trainer<FirstPreviousLayer>::Create(
previous_layer_trainer_(Trainer<FirstPreviousLayer>::create(
&target_layer->previous_layer_, ft)),
target_layer_(target_layer) {
}
@@ -110,7 +110,7 @@ namespace Eval::NNUE {
public:
// factory function
static std::shared_ptr<Trainer> Create(
static std::shared_ptr<Trainer> create(
LayerType* target_layer, FeatureTransformer* ft) {
return std::shared_ptr<Trainer>(
@@ -118,24 +118,24 @@ namespace Eval::NNUE {
}
// Set options such as hyperparameters
void SendMessage(Message* message) {
previous_layer_trainer_->SendMessage(message);
void send_message(Message* message) {
previous_layer_trainer_->send_message(message);
}
// Initialize the parameters with random numbers
template <typename RNG>
void Initialize(RNG& rng) {
previous_layer_trainer_->Initialize(rng);
void initialize(RNG& rng) {
previous_layer_trainer_->initialize(rng);
}
// forward propagation
/*const*/ LearnFloatType* Propagate(const std::vector<Example>& batch) {
/*const*/ LearnFloatType* propagate(const std::vector<Example>& batch) {
if (output_.size() < kOutputDimensions * batch.size()) {
output_.resize(kOutputDimensions * batch.size());
}
batch_size_ = static_cast<IndexType>(batch.size());
const auto output = previous_layer_trainer_->Propagate(batch);
const auto output = previous_layer_trainer_->propagate(batch);
#if defined(USE_BLAS)
cblas_scopy(kOutputDimensions * batch_size_, output, 1, &output_[0], 1);
@@ -152,17 +152,17 @@ namespace Eval::NNUE {
}
// backpropagation
void Backpropagate(const LearnFloatType* gradients,
void backpropagate(const LearnFloatType* gradients,
LearnFloatType learning_rate) {
previous_layer_trainer_->Backpropagate(gradients, learning_rate);
previous_layer_trainer_->backpropagate(gradients, learning_rate);
}
private:
// constructor
Trainer(LayerType* target_layer, FeatureTransformer* ft) :
batch_size_(0),
previous_layer_trainer_(Trainer<PreviousLayer>::Create(
previous_layer_trainer_(Trainer<PreviousLayer>::create(
&target_layer->previous_layer_, ft)),
target_layer_(target_layer) {
}

View File

@@ -53,7 +53,7 @@ void test_cmd(Position& pos, istringstream& is)
std::string param;
is >> param;
if (param == "nnue") Eval::NNUE::TestCommand(pos, is);
if (param == "nnue") Eval::NNUE::test_command(pos, is);
}
namespace {