diff --git a/src/nnue/trainer/features/factorizer.h b/src/nnue/trainer/features/factorizer.h index 43950de2..784fe047 100644 --- a/src/nnue/trainer/features/factorizer.h +++ b/src/nnue/trainer/features/factorizer.h @@ -1,106 +1,109 @@ -// NNUE evaluation function feature conversion class template - -#ifndef _NNUE_TRAINER_FEATURES_FACTORIZER_H_ +#ifndef _NNUE_TRAINER_FEATURES_FACTORIZER_H_ #define _NNUE_TRAINER_FEATURES_FACTORIZER_H_ -#include "../../nnue_common.h" -#include "../trainer.h" +#include "nnue/nnue_common.h" -namespace Eval { +#include "nnue/trainer/trainer.h" -namespace NNUE { +// NNUE evaluation function feature conversion class template +namespace Eval::NNUE::Features { -namespace Features { + // Class template that converts input features into learning features + // By default, the learning feature is the same as the original input feature, and specialized as necessary + template + class Factorizer { + public: + // Get the dimensionality of the learning feature + static constexpr IndexType GetDimensions() { + return FeatureType::kDimensions; + } -// Class template that converts input features into learning features -// By default, the learning feature is the same as the original input feature, and specialized as necessary -template -class Factorizer { - public: - // Get the dimensionality of the learning feature - static constexpr IndexType GetDimensions() { - return FeatureType::kDimensions; - } + // Get index of learning feature and scale of learning rate + static void AppendTrainingFeatures( + IndexType base_index, std::vector* training_features) { - // Get index of learning feature and scale of learning rate - static void AppendTrainingFeatures( - IndexType base_index, std::vector* training_features) { - assert(base_index emplace_back(base_index); - } -}; + assert(base_index emplace_back(base_index); + } + }; -// Learning feature information -struct FeatureProperties { - bool active; - IndexType dimensions; -}; + // Learning feature information + struct FeatureProperties { + bool active; + IndexType dimensions; + }; -// Add the original input features to the learning features -template -IndexType AppendBaseFeature( - FeatureProperties properties, IndexType base_index, - std::vector* training_features) { - assert(properties.dimensions == FeatureType::kDimensions); - assert(base_index < FeatureType::kDimensions); - training_features->emplace_back(base_index); - return properties.dimensions; -} + // Add the original input features to the learning features + template + IndexType AppendBaseFeature( + FeatureProperties properties, IndexType base_index, + std::vector* training_features) { -// If the learning rate scale is not 0, inherit other types of learning features -template -IndexType InheritFeaturesIfRequired( - IndexType index_offset, FeatureProperties properties, IndexType base_index, - std::vector* training_features) { - if (!properties.active) { - return 0; - } - assert(properties.dimensions == Factorizer::GetDimensions()); - assert(base_index < FeatureType::kDimensions); - const auto start = training_features->size(); - Factorizer::AppendTrainingFeatures( - base_index, training_features); - for (auto i = start; i < training_features->size(); ++i) { - auto& feature = (*training_features)[i]; - assert(feature.GetIndex() < Factorizer::GetDimensions()); - feature.ShiftIndex(index_offset); - } - return properties.dimensions; -} - -// Return the index difference as needed, without adding learning features -// Call instead of InheritFeaturesIfRequired() if there are no corresponding features -IndexType SkipFeatures(FeatureProperties properties) { - if (!properties.active) { - return 0; - } - return properties.dimensions; -} - -// Get the dimensionality of the learning feature -template -constexpr IndexType GetActiveDimensions( - const FeatureProperties (&properties)[N]) { - static_assert(N > 0, ""); - IndexType dimensions = properties[0].dimensions; - for (std::size_t i = 1; i < N; ++i) { - if (properties[i].active) { - dimensions += properties[i].dimensions; + assert(properties.dimensions == FeatureType::kDimensions); + assert(base_index < FeatureType::kDimensions); + training_features->emplace_back(base_index); + return properties.dimensions; } - } - return dimensions; -} -// get the number of elements in the array -template -constexpr std::size_t GetArrayLength(const T (&/*array*/)[N]) { - return N; -} + // If the learning rate scale is not 0, inherit other types of learning features + template + IndexType InheritFeaturesIfRequired( + IndexType index_offset, FeatureProperties properties, IndexType base_index, + std::vector* training_features) { -} // namespace Features + if (!properties.active) { + return 0; + } -} // namespace NNUE + assert(properties.dimensions == Factorizer::GetDimensions()); + assert(base_index < FeatureType::kDimensions); -} // namespace Eval + const auto start = training_features->size(); + Factorizer::AppendTrainingFeatures( + base_index, training_features); + + for (auto i = start; i < training_features->size(); ++i) { + auto& feature = (*training_features)[i]; + assert(feature.GetIndex() < Factorizer::GetDimensions()); + feature.ShiftIndex(index_offset); + } + + return properties.dimensions; + } + + // Return the index difference as needed, without adding learning features + // Call instead of InheritFeaturesIfRequired() if there are no corresponding features + IndexType SkipFeatures(FeatureProperties properties) { + if (!properties.active) + return 0; + + return properties.dimensions; + } + + // Get the dimensionality of the learning feature + template + constexpr IndexType GetActiveDimensions( + const FeatureProperties (&properties)[N]) { + + static_assert(N > 0, ""); + + IndexType dimensions = properties[0].dimensions; + + for (std::size_t i = 1; i < N; ++i) { + if (properties[i].active) { + dimensions += properties[i].dimensions; + } + } + + return dimensions; + } + + // get the number of elements in the array + template + constexpr std::size_t GetArrayLength(const T (&/*array*/)[N]) { + return N; + } + +} // namespace Eval::NNUE::Features #endif diff --git a/src/nnue/trainer/features/factorizer_feature_set.h b/src/nnue/trainer/features/factorizer_feature_set.h index caf6608b..d272a453 100644 --- a/src/nnue/trainer/features/factorizer_feature_set.h +++ b/src/nnue/trainer/features/factorizer_feature_set.h @@ -1,100 +1,105 @@ -// Specialization for feature set of feature conversion class template of NNUE evaluation function - -#ifndef _NNUE_TRAINER_FEATURES_FACTORIZER_FEATURE_SET_H_ +#ifndef _NNUE_TRAINER_FEATURES_FACTORIZER_FEATURE_SET_H_ #define _NNUE_TRAINER_FEATURES_FACTORIZER_FEATURE_SET_H_ -#include "../../features/feature_set.h" #include "factorizer.h" -namespace Eval { +#include "nnue/features/feature_set.h" -namespace NNUE { +// Specialization for feature set of feature conversion class template of NNUE evaluation function +namespace Eval::NNUE::Features { -namespace Features { + // Class template that converts input features into learning features + // Specialization for FeatureSet + template + class Factorizer> { + private: + using Head = Factorizer>; + using Tail = Factorizer>; -// Class template that converts input features into learning features -// Specialization for FeatureSet -template -class Factorizer> { - private: - using Head = Factorizer>; - using Tail = Factorizer>; + public: + // number of dimensions of original input features + static constexpr IndexType kBaseDimensions = + FeatureSet::kDimensions; - public: - // number of dimensions of original input features - static constexpr IndexType kBaseDimensions = - FeatureSet::kDimensions; - - // Get the dimensionality of the learning feature - static constexpr IndexType GetDimensions() { - return Head::GetDimensions() + Tail::GetDimensions(); - } - - // Get index of learning feature and scale of learning rate - static void AppendTrainingFeatures( - IndexType base_index, std::vector* training_features, - IndexType base_dimensions = kBaseDimensions) { - assert(base_index < kBaseDimensions); - constexpr auto boundary = FeatureSet::kDimensions; - if (base_index < boundary) { - Tail::AppendTrainingFeatures( - base_index, training_features, base_dimensions); - } else { - const auto start = training_features->size(); - Head::AppendTrainingFeatures( - 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(); - assert(index < Head::GetDimensions() || - (index >= base_dimensions && - index < base_dimensions + - Head::GetDimensions() - Head::kBaseDimensions)); - if (index < Head::kBaseDimensions) { - feature.ShiftIndex(Tail::kBaseDimensions); - } else { - feature.ShiftIndex(Tail::GetDimensions() - Tail::kBaseDimensions); + // Get the dimensionality of the learning feature + static constexpr IndexType GetDimensions() { + return Head::GetDimensions() + Tail::GetDimensions(); } - } - } - } -}; -// Class template that converts input features into learning features -// Specialization when FeatureSet has one template argument -template -class Factorizer> { -public: - // number of dimensions of original input features - static constexpr IndexType kBaseDimensions = FeatureType::kDimensions; + // Get index of learning feature and scale of learning rate + static void AppendTrainingFeatures( + IndexType base_index, std::vector* training_features, + IndexType base_dimensions = kBaseDimensions) { - // Get the dimensionality of the learning feature - static constexpr IndexType GetDimensions() { - return Factorizer::GetDimensions(); - } + assert(base_index < kBaseDimensions); - // Get index of learning feature and scale of learning rate - static void AppendTrainingFeatures( - IndexType base_index, std::vector* training_features, - IndexType base_dimensions = kBaseDimensions) { - assert(base_index < kBaseDimensions); - const auto start = training_features->size(); - Factorizer::AppendTrainingFeatures( - base_index, training_features); - for (auto i = start; i < training_features->size(); ++i) { - auto& feature = (*training_features)[i]; - assert(feature.GetIndex() < Factorizer::GetDimensions()); - if (feature.GetIndex() >= kBaseDimensions) { - feature.ShiftIndex(base_dimensions - kBaseDimensions); - } - } - } -}; + constexpr auto boundary = FeatureSet::kDimensions; -} // namespace Features + if (base_index < boundary) { + Tail::AppendTrainingFeatures( + base_index, training_features, base_dimensions); + } + else { + const auto start = training_features->size(); -} // namespace NNUE + Head::AppendTrainingFeatures( + base_index - boundary, training_features, base_dimensions); -} // namespace Eval + for (auto i = start; i < training_features->size(); ++i) { + auto& feature = (*training_features)[i]; + const auto index = feature.GetIndex(); + + assert(index < Head::GetDimensions() || + (index >= base_dimensions && + index < base_dimensions + + Head::GetDimensions() - Head::kBaseDimensions)); + + if (index < Head::kBaseDimensions) { + feature.ShiftIndex(Tail::kBaseDimensions); + } + else { + feature.ShiftIndex(Tail::GetDimensions() - Tail::kBaseDimensions); + } + } + } + } + }; + + // Class template that converts input features into learning features + // Specialization when FeatureSet has one template argument + template + class Factorizer> { + public: + // number of dimensions of original input features + static constexpr IndexType kBaseDimensions = FeatureType::kDimensions; + + // Get the dimensionality of the learning feature + static constexpr IndexType GetDimensions() { + return Factorizer::GetDimensions(); + } + + // Get index of learning feature and scale of learning rate + static void AppendTrainingFeatures( + IndexType base_index, std::vector* training_features, + IndexType base_dimensions = kBaseDimensions) { + + assert(base_index < kBaseDimensions); + + const auto start = training_features->size(); + + Factorizer::AppendTrainingFeatures( + base_index, training_features); + + for (auto i = start; i < training_features->size(); ++i) { + auto& feature = (*training_features)[i]; + assert(feature.GetIndex() < Factorizer::GetDimensions()); + if (feature.GetIndex() >= kBaseDimensions) { + feature.ShiftIndex(base_dimensions - kBaseDimensions); + } + } + } + }; + +} // namespace Eval::NNUE::Features #endif diff --git a/src/nnue/trainer/features/factorizer_half_kp.h b/src/nnue/trainer/features/factorizer_half_kp.h index 70a6acca..1ed5bdd3 100644 --- a/src/nnue/trainer/features/factorizer_half_kp.h +++ b/src/nnue/trainer/features/factorizer_half_kp.h @@ -1,99 +1,96 @@ -// Specialization of NNUE evaluation function feature conversion class template for HalfKP - -#ifndef _NNUE_TRAINER_FEATURES_FACTORIZER_HALF_KP_H_ +#ifndef _NNUE_TRAINER_FEATURES_FACTORIZER_HALF_KP_H_ #define _NNUE_TRAINER_FEATURES_FACTORIZER_HALF_KP_H_ -#include "../../features/half_kp.h" -#include "../../features/p.h" -#include "../../features/half_relative_kp.h" #include "factorizer.h" -namespace Eval { +#include "nnue/features/half_kp.h" +#include "nnue/features/p.h" +#include "nnue/features/half_relative_kp.h" -namespace NNUE { +// Specialization of NNUE evaluation function feature conversion class template for HalfKP +namespace Eval::NNUE::Features { -namespace Features { + // Class template that converts input features into learning features + // Specialization for HalfKP + template + class Factorizer> { + private: + using FeatureType = HalfKP; -// Class template that converts input features into learning features -// Specialization for HalfKP -template -class Factorizer> { - private: - using FeatureType = HalfKP; + // The maximum value of the number of indexes whose value is 1 at the same time among the feature values + static constexpr IndexType kMaxActiveDimensions = + FeatureType::kMaxActiveDimensions; - // The maximum value of the number of indexes whose value is 1 at the same time among the feature values - static constexpr IndexType kMaxActiveDimensions = - FeatureType::kMaxActiveDimensions; + // Type of learning feature + enum TrainingFeatureType { + kFeaturesHalfKP, + kFeaturesHalfK, + kFeaturesP, + kFeaturesHalfRelativeKP, + kNumTrainingFeatureTypes, + }; - // Type of learning feature - enum TrainingFeatureType { - kFeaturesHalfKP, - kFeaturesHalfK, - kFeaturesP, - kFeaturesHalfRelativeKP, - kNumTrainingFeatureTypes, - }; + // Learning feature information + static constexpr FeatureProperties kProperties[] = { + // kFeaturesHalfKP + {true, FeatureType::kDimensions}, + // kFeaturesHalfK + {true, SQUARE_NB}, + // kFeaturesP + {true, Factorizer

::GetDimensions()}, + // kFeaturesHalfRelativeKP + {true, Factorizer>::GetDimensions()}, + }; - // Learning feature information - static constexpr FeatureProperties kProperties[] = { - // kFeaturesHalfKP - {true, FeatureType::kDimensions}, - // kFeaturesHalfK - {true, SQUARE_NB}, - // kFeaturesP - {true, Factorizer

::GetDimensions()}, - // kFeaturesHalfRelativeKP - {true, Factorizer>::GetDimensions()}, - }; - static_assert(GetArrayLength(kProperties) == kNumTrainingFeatureTypes, ""); + static_assert(GetArrayLength(kProperties) == kNumTrainingFeatureTypes, ""); - public: - // Get the dimensionality of the learning feature - static constexpr IndexType GetDimensions() { - return GetActiveDimensions(kProperties); - } + public: + // Get the dimensionality of the learning feature + static constexpr IndexType GetDimensions() { + return GetActiveDimensions(kProperties); + } - // Get index of learning feature and scale of learning rate - static void AppendTrainingFeatures( - IndexType base_index, std::vector* training_features) { - // kFeaturesHalfKP - IndexType index_offset = AppendBaseFeature( - kProperties[kFeaturesHalfKP], base_index, training_features); + // Get index of learning feature and scale of learning rate + static void AppendTrainingFeatures( + IndexType base_index, std::vector* training_features) { - const auto sq_k = static_cast(base_index / PS_END); - const auto p = static_cast(base_index % PS_END); - // kFeaturesHalfK - { - const auto& properties = kProperties[kFeaturesHalfK]; - if (properties.active) { - training_features->emplace_back(index_offset + sq_k); - index_offset += properties.dimensions; - } - } - // kFeaturesP - index_offset += InheritFeaturesIfRequired

( - index_offset, kProperties[kFeaturesP], p, training_features); - // kFeaturesHalfRelativeKP - if (p >= PS_W_PAWN) { - index_offset += InheritFeaturesIfRequired>( - index_offset, kProperties[kFeaturesHalfRelativeKP], - HalfRelativeKP::MakeIndex(sq_k, p), - training_features); - } else { - index_offset += SkipFeatures(kProperties[kFeaturesHalfRelativeKP]); - } + // kFeaturesHalfKP + IndexType index_offset = AppendBaseFeature( + kProperties[kFeaturesHalfKP], base_index, training_features); - assert(index_offset == GetDimensions()); - } -}; + const auto sq_k = static_cast(base_index / PS_END); + const auto p = static_cast(base_index % PS_END); -template -constexpr FeatureProperties Factorizer>::kProperties[]; + // kFeaturesHalfK + { + const auto& properties = kProperties[kFeaturesHalfK]; + if (properties.active) { + training_features->emplace_back(index_offset + sq_k); + index_offset += properties.dimensions; + } + } -} // namespace Features + // kFeaturesP + index_offset += InheritFeaturesIfRequired

( + index_offset, kProperties[kFeaturesP], p, training_features); + // kFeaturesHalfRelativeKP + if (p >= PS_W_PAWN) { + index_offset += InheritFeaturesIfRequired>( + index_offset, kProperties[kFeaturesHalfRelativeKP], + HalfRelativeKP::MakeIndex(sq_k, p), + training_features); + } + else { + index_offset += SkipFeatures(kProperties[kFeaturesHalfRelativeKP]); + } -} // namespace NNUE + assert(index_offset == GetDimensions()); + } + }; -} // namespace Eval + template + constexpr FeatureProperties Factorizer>::kProperties[]; + +} // namespace Eval::NNUE::Features #endif