mirror of
https://github.com/HChaZZY/Stockfish.git
synced 2025-12-25 11:36:51 +08:00
PascalCase -> snake_case for consistency with the rest of the codebase.
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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])));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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)...);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user