mirror of
https://github.com/sockspls/badfish
synced 2025-04-30 16:53:09 +00:00
[NNUE] More cleanup in nnue folder
No functional change.
This commit is contained in:
parent
aa339506db
commit
122c78b521
15 changed files with 67 additions and 277 deletions
|
@ -21,7 +21,7 @@ constexpr IndexType kTransformedFeatureDimensions = 256;
|
||||||
|
|
||||||
namespace Layers {
|
namespace Layers {
|
||||||
|
|
||||||
// define network structure
|
// Define network structure
|
||||||
using InputLayer = InputSlice<kTransformedFeatureDimensions * 2>;
|
using InputLayer = InputSlice<kTransformedFeatureDimensions * 2>;
|
||||||
using HiddenLayer1 = ClippedReLU<AffineTransform<InputLayer, 32>>;
|
using HiddenLayer1 = ClippedReLU<AffineTransform<InputLayer, 32>>;
|
||||||
using HiddenLayer2 = ClippedReLU<AffineTransform<HiddenLayer1, 32>>;
|
using HiddenLayer2 = ClippedReLU<AffineTransform<HiddenLayer1, 32>>;
|
||||||
|
|
|
@ -44,13 +44,6 @@ namespace Eval::NNUE {
|
||||||
// Evaluation function file name
|
// Evaluation function file name
|
||||||
std::string fileName;
|
std::string fileName;
|
||||||
|
|
||||||
// Get a string that represents the structure of the evaluation function
|
|
||||||
std::string GetArchitectureString() {
|
|
||||||
|
|
||||||
return "Features=" + FeatureTransformer::GetStructureString() +
|
|
||||||
",Network=" + Network::GetStructureString();
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace Detail {
|
namespace Detail {
|
||||||
|
|
||||||
// Initialize the evaluation function parameters
|
// Initialize the evaluation function parameters
|
||||||
|
@ -61,7 +54,7 @@ namespace Eval::NNUE {
|
||||||
std::memset(pointer.get(), 0, sizeof(T));
|
std::memset(pointer.get(), 0, sizeof(T));
|
||||||
}
|
}
|
||||||
|
|
||||||
// read evaluation function parameters
|
// Read evaluation function parameters
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool ReadParameters(std::istream& stream, const AlignedPtr<T>& pointer) {
|
bool ReadParameters(std::istream& stream, const AlignedPtr<T>& pointer) {
|
||||||
|
|
||||||
|
@ -80,7 +73,7 @@ namespace Eval::NNUE {
|
||||||
Detail::Initialize(network);
|
Detail::Initialize(network);
|
||||||
}
|
}
|
||||||
|
|
||||||
// read the header
|
// Read network header
|
||||||
bool ReadHeader(std::istream& stream,
|
bool ReadHeader(std::istream& stream,
|
||||||
std::uint32_t* hash_value, std::string* architecture) {
|
std::uint32_t* hash_value, std::string* architecture) {
|
||||||
|
|
||||||
|
@ -94,7 +87,7 @@ namespace Eval::NNUE {
|
||||||
return !stream.fail();
|
return !stream.fail();
|
||||||
}
|
}
|
||||||
|
|
||||||
// read evaluation function parameters
|
// Read network parameters
|
||||||
bool ReadParameters(std::istream& stream) {
|
bool ReadParameters(std::istream& stream) {
|
||||||
|
|
||||||
std::uint32_t hash_value;
|
std::uint32_t hash_value;
|
||||||
|
@ -106,7 +99,7 @@ namespace Eval::NNUE {
|
||||||
return stream && stream.peek() == std::ios::traits_type::eof();
|
return stream && stream.peek() == std::ios::traits_type::eof();
|
||||||
}
|
}
|
||||||
|
|
||||||
// proceed if you can calculate the difference
|
// Proceed with the difference calculation if possible
|
||||||
static void UpdateAccumulatorIfPossible(const Position& pos) {
|
static void UpdateAccumulatorIfPossible(const Position& pos) {
|
||||||
|
|
||||||
feature_transformer->UpdateAccumulatorIfPossible(pos);
|
feature_transformer->UpdateAccumulatorIfPossible(pos);
|
||||||
|
@ -133,9 +126,7 @@ namespace Eval::NNUE {
|
||||||
return accumulator.score;
|
return accumulator.score;
|
||||||
}
|
}
|
||||||
|
|
||||||
// read the evaluation function file
|
// Load the evaluation function file
|
||||||
// Save and restore Options with bench command etc., so EvalFile is changed at this time,
|
|
||||||
// This function may be called twice to flag that the evaluation function needs to be reloaded.
|
|
||||||
void load_eval(const std::string& evalFile) {
|
void load_eval(const std::string& evalFile) {
|
||||||
|
|
||||||
Initialize();
|
Initialize();
|
||||||
|
@ -163,7 +154,7 @@ namespace Eval::NNUE {
|
||||||
return ComputeScore(pos, true);
|
return ComputeScore(pos, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// proceed if you can calculate the difference
|
// Proceed with the difference calculation if possible
|
||||||
void update_eval(const Position& pos) {
|
void update_eval(const Position& pos) {
|
||||||
UpdateAccumulatorIfPossible(pos);
|
UpdateAccumulatorIfPossible(pos);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
namespace Eval::NNUE {
|
namespace Eval::NNUE {
|
||||||
|
|
||||||
// hash value of evaluation function structure
|
// Hash value of evaluation function structure
|
||||||
constexpr std::uint32_t kHashValue =
|
constexpr std::uint32_t kHashValue =
|
||||||
FeatureTransformer::GetHashValue() ^ Network::GetHashValue();
|
FeatureTransformer::GetHashValue() ^ Network::GetHashValue();
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
namespace Eval::NNUE::Features {
|
namespace Eval::NNUE::Features {
|
||||||
|
|
||||||
// A class template that represents a list of values
|
// Class template that represents a list of values
|
||||||
template <typename T, T... Values>
|
template <typename T, T... Values>
|
||||||
struct CompileTimeList;
|
struct CompileTimeList;
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ namespace Eval::NNUE::Features {
|
||||||
class FeatureSetBase {
|
class FeatureSetBase {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Get a list of indices with a value of 1 among the features
|
// Get a list of indices for active features
|
||||||
template <typename IndexListType>
|
template <typename IndexListType>
|
||||||
static void AppendActiveIndices(
|
static void AppendActiveIndices(
|
||||||
const Position& pos, TriggerEvent trigger, IndexListType active[2]) {
|
const Position& pos, TriggerEvent trigger, IndexListType active[2]) {
|
||||||
|
@ -37,7 +37,7 @@ namespace Eval::NNUE::Features {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get a list of indices whose values have changed from the previous one in the feature quantity
|
// Get a list of indices for recently changed features
|
||||||
template <typename PositionType, typename IndexListType>
|
template <typename PositionType, typename IndexListType>
|
||||||
static void AppendChangedIndices(
|
static void AppendChangedIndices(
|
||||||
const PositionType& pos, TriggerEvent trigger,
|
const PositionType& pos, TriggerEvent trigger,
|
||||||
|
@ -70,30 +70,24 @@ namespace Eval::NNUE::Features {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Class template that represents the feature set
|
// Class template that represents the feature set
|
||||||
// Specialization with one template argument
|
|
||||||
template <typename FeatureType>
|
template <typename FeatureType>
|
||||||
class FeatureSet<FeatureType> : public FeatureSetBase<FeatureSet<FeatureType>> {
|
class FeatureSet<FeatureType> : public FeatureSetBase<FeatureSet<FeatureType>> {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Hash value embedded in the evaluation function file
|
// Hash value embedded in the evaluation file
|
||||||
static constexpr std::uint32_t kHashValue = FeatureType::kHashValue;
|
static constexpr std::uint32_t kHashValue = FeatureType::kHashValue;
|
||||||
// number of feature dimensions
|
// Number of feature dimensions
|
||||||
static constexpr IndexType kDimensions = FeatureType::kDimensions;
|
static constexpr IndexType kDimensions = FeatureType::kDimensions;
|
||||||
// The maximum value of the number of indexes whose value is 1 at the same time among the feature values
|
// Maximum number of simultaneously active features
|
||||||
static constexpr IndexType kMaxActiveDimensions =
|
static constexpr IndexType kMaxActiveDimensions =
|
||||||
FeatureType::kMaxActiveDimensions;
|
FeatureType::kMaxActiveDimensions;
|
||||||
// List of timings to perform all calculations instead of difference calculation
|
// Trigger for full calculation instead of difference calculation
|
||||||
using SortedTriggerSet =
|
using SortedTriggerSet =
|
||||||
CompileTimeList<TriggerEvent, FeatureType::kRefreshTrigger>;
|
CompileTimeList<TriggerEvent, FeatureType::kRefreshTrigger>;
|
||||||
static constexpr auto kRefreshTriggers = SortedTriggerSet::kValues;
|
static constexpr auto kRefreshTriggers = SortedTriggerSet::kValues;
|
||||||
|
|
||||||
// Get the feature quantity name
|
|
||||||
static std::string GetName() {
|
|
||||||
return FeatureType::kName;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Get a list of indices with a value of 1 among the features
|
// Get a list of indices for active features
|
||||||
static void CollectActiveIndices(
|
static void CollectActiveIndices(
|
||||||
const Position& pos, const TriggerEvent trigger, const Color perspective,
|
const Position& pos, const TriggerEvent trigger, const Color perspective,
|
||||||
IndexList* const active) {
|
IndexList* const active) {
|
||||||
|
@ -102,7 +96,7 @@ namespace Eval::NNUE::Features {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get a list of indices whose values have changed from the previous one in the feature quantity
|
// Get a list of indices for recently changed features
|
||||||
static void CollectChangedIndices(
|
static void CollectChangedIndices(
|
||||||
const Position& pos, const TriggerEvent trigger, const Color perspective,
|
const Position& pos, const TriggerEvent trigger, const Color perspective,
|
||||||
IndexList* const removed, IndexList* const added) {
|
IndexList* const removed, IndexList* const added) {
|
||||||
|
|
|
@ -8,21 +8,18 @@
|
||||||
|
|
||||||
namespace Eval::NNUE::Features {
|
namespace Eval::NNUE::Features {
|
||||||
|
|
||||||
// Index list type
|
|
||||||
class IndexList;
|
class IndexList;
|
||||||
|
|
||||||
// Class template that represents the feature set
|
|
||||||
template <typename... FeatureTypes>
|
template <typename... FeatureTypes>
|
||||||
class FeatureSet;
|
class FeatureSet;
|
||||||
|
|
||||||
// Type of timing to perform all calculations instead of difference calculation
|
// Trigger to perform full calculations instead of difference only
|
||||||
enum class TriggerEvent {
|
enum class TriggerEvent {
|
||||||
kFriendKingMoved // calculate all when own king moves
|
kFriendKingMoved // calculate full evaluation when own king moves
|
||||||
};
|
};
|
||||||
|
|
||||||
// turn side or other side
|
|
||||||
enum class Side {
|
enum class Side {
|
||||||
kFriend // turn side
|
kFriend // side to move
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Eval::NNUE::Features
|
} // namespace Eval::NNUE::Features
|
||||||
|
|
|
@ -11,7 +11,7 @@ namespace Eval::NNUE::Features {
|
||||||
return static_cast<IndexType>(PS_END) * static_cast<IndexType>(sq_k) + p;
|
return static_cast<IndexType>(PS_END) * static_cast<IndexType>(sq_k) + p;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the piece information
|
// Get pieces information
|
||||||
template <Side AssociatedKing>
|
template <Side AssociatedKing>
|
||||||
inline void HalfKP<AssociatedKing>::GetPieces(
|
inline void HalfKP<AssociatedKing>::GetPieces(
|
||||||
const Position& pos, Color perspective,
|
const Position& pos, Color perspective,
|
||||||
|
@ -26,12 +26,12 @@ namespace Eval::NNUE::Features {
|
||||||
*sq_target_k = static_cast<Square>(((*pieces)[target] - PS_W_KING) % SQUARE_NB);
|
*sq_target_k = static_cast<Square>(((*pieces)[target] - PS_W_KING) % SQUARE_NB);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get a list of indices with a value of 1 among the features
|
// Get a list of indices for active features
|
||||||
template <Side AssociatedKing>
|
template <Side AssociatedKing>
|
||||||
void HalfKP<AssociatedKing>::AppendActiveIndices(
|
void HalfKP<AssociatedKing>::AppendActiveIndices(
|
||||||
const Position& pos, Color perspective, IndexList* active) {
|
const Position& pos, Color perspective, IndexList* active) {
|
||||||
|
|
||||||
// do nothing if array size is small to avoid compiler warning
|
// Do nothing if array size is small to avoid compiler warning
|
||||||
if (RawFeatures::kMaxActiveDimensions < kMaxActiveDimensions) return;
|
if (RawFeatures::kMaxActiveDimensions < kMaxActiveDimensions) return;
|
||||||
|
|
||||||
PieceSquare* pieces;
|
PieceSquare* pieces;
|
||||||
|
@ -44,7 +44,7 @@ namespace Eval::NNUE::Features {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get a list of indices whose values have changed from the previous one in the feature quantity
|
// Get a list of indices for recently changed features
|
||||||
template <Side AssociatedKing>
|
template <Side AssociatedKing>
|
||||||
void HalfKP<AssociatedKing>::AppendChangedIndices(
|
void HalfKP<AssociatedKing>::AppendChangedIndices(
|
||||||
const Position& pos, Color perspective,
|
const Position& pos, Color perspective,
|
||||||
|
|
|
@ -8,39 +8,38 @@
|
||||||
|
|
||||||
namespace Eval::NNUE::Features {
|
namespace Eval::NNUE::Features {
|
||||||
|
|
||||||
// Feature HalfKP: Combination of the position of own king or enemy king
|
// Feature HalfKP: Combination of the position of own king
|
||||||
// and the position of pieces other than kings
|
// and the position of pieces other than kings
|
||||||
template <Side AssociatedKing>
|
template <Side AssociatedKing>
|
||||||
class HalfKP {
|
class HalfKP {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// feature quantity name
|
// Feature name
|
||||||
static constexpr const char* kName =
|
static constexpr const char* kName = "HalfKP(Friend)";
|
||||||
(AssociatedKing == Side::kFriend) ? "HalfKP(Friend)" : "HalfKP(Enemy)";
|
// Hash value embedded in the evaluation file
|
||||||
// Hash value embedded in the evaluation function file
|
|
||||||
static constexpr std::uint32_t kHashValue =
|
static constexpr std::uint32_t kHashValue =
|
||||||
0x5D69D5B9u ^ (AssociatedKing == Side::kFriend);
|
0x5D69D5B9u ^ (AssociatedKing == Side::kFriend);
|
||||||
// number of feature dimensions
|
// Number of feature dimensions
|
||||||
static constexpr IndexType kDimensions =
|
static constexpr IndexType kDimensions =
|
||||||
static_cast<IndexType>(SQUARE_NB) * static_cast<IndexType>(PS_END);
|
static_cast<IndexType>(SQUARE_NB) * static_cast<IndexType>(PS_END);
|
||||||
// The maximum value of the number of indexes whose value is 1 at the same time among the feature values
|
// Maximum number of simultaneously active features
|
||||||
static constexpr IndexType kMaxActiveDimensions = PIECE_ID_KING;
|
static constexpr IndexType kMaxActiveDimensions = PIECE_ID_KING;
|
||||||
// Timing of full calculation instead of difference calculation
|
// Trigger for full calculation instead of difference calculation
|
||||||
static constexpr TriggerEvent kRefreshTrigger = TriggerEvent::kFriendKingMoved;
|
static constexpr TriggerEvent kRefreshTrigger = TriggerEvent::kFriendKingMoved;
|
||||||
|
|
||||||
// Get a list of indices with a value of 1 among the features
|
// Get a list of indices for active features
|
||||||
static void AppendActiveIndices(const Position& pos, Color perspective,
|
static void AppendActiveIndices(const Position& pos, Color perspective,
|
||||||
IndexList* active);
|
IndexList* active);
|
||||||
|
|
||||||
// Get a list of indices whose values have changed from the previous one in the feature quantity
|
// Get a list of indices for recently changed features
|
||||||
static void AppendChangedIndices(const Position& pos, Color perspective,
|
static void AppendChangedIndices(const Position& pos, Color perspective,
|
||||||
IndexList* removed, IndexList* added);
|
IndexList* removed, IndexList* added);
|
||||||
|
|
||||||
// Find the index of the feature quantity from the king position and PieceSquare
|
// Index of a feature for a given king position and another piece on some square
|
||||||
static IndexType MakeIndex(Square sq_k, PieceSquare p);
|
static IndexType MakeIndex(Square sq_k, PieceSquare p);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Get the piece information
|
// Get pieces information
|
||||||
static void GetPieces(const Position& pos, Color perspective,
|
static void GetPieces(const Position& pos, Color perspective,
|
||||||
PieceSquare** pieces, Square* sq_target_k);
|
PieceSquare** pieces, Square* sq_target_k);
|
||||||
};
|
};
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
namespace Eval::NNUE::Layers {
|
namespace Eval::NNUE::Layers {
|
||||||
|
|
||||||
// affine transformation layer
|
// Affine transformation layer
|
||||||
template <typename PreviousLayer, IndexType OutputDimensions>
|
template <typename PreviousLayer, IndexType OutputDimensions>
|
||||||
class AffineTransform {
|
class AffineTransform {
|
||||||
public:
|
public:
|
||||||
|
@ -17,7 +17,7 @@ namespace Eval::NNUE::Layers {
|
||||||
using OutputType = std::int32_t;
|
using OutputType = std::int32_t;
|
||||||
static_assert(std::is_same<InputType, std::uint8_t>::value, "");
|
static_assert(std::is_same<InputType, std::uint8_t>::value, "");
|
||||||
|
|
||||||
// number of input/output dimensions
|
// Number of input/output dimensions
|
||||||
static constexpr IndexType kInputDimensions =
|
static constexpr IndexType kInputDimensions =
|
||||||
PreviousLayer::kOutputDimensions;
|
PreviousLayer::kOutputDimensions;
|
||||||
static constexpr IndexType kOutputDimensions = OutputDimensions;
|
static constexpr IndexType kOutputDimensions = OutputDimensions;
|
||||||
|
@ -32,7 +32,7 @@ namespace Eval::NNUE::Layers {
|
||||||
static constexpr std::size_t kBufferSize =
|
static constexpr std::size_t kBufferSize =
|
||||||
PreviousLayer::kBufferSize + kSelfBufferSize;
|
PreviousLayer::kBufferSize + kSelfBufferSize;
|
||||||
|
|
||||||
// Hash value embedded in the evaluation function file
|
// Hash value embedded in the evaluation file
|
||||||
static constexpr std::uint32_t GetHashValue() {
|
static constexpr std::uint32_t GetHashValue() {
|
||||||
std::uint32_t hash_value = 0xCC03DAE4u;
|
std::uint32_t hash_value = 0xCC03DAE4u;
|
||||||
hash_value += kOutputDimensions;
|
hash_value += kOutputDimensions;
|
||||||
|
@ -41,15 +41,7 @@ namespace Eval::NNUE::Layers {
|
||||||
return hash_value;
|
return hash_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// A string that represents the structure from the input layer to this layer
|
// Read network parameters
|
||||||
static std::string GetStructureString() {
|
|
||||||
return "AffineTransform[" +
|
|
||||||
std::to_string(kOutputDimensions) + "<-" +
|
|
||||||
std::to_string(kInputDimensions) + "](" +
|
|
||||||
PreviousLayer::GetStructureString() + ")";
|
|
||||||
}
|
|
||||||
|
|
||||||
// read parameters
|
|
||||||
bool ReadParameters(std::istream& stream) {
|
bool ReadParameters(std::istream& stream) {
|
||||||
if (!previous_layer_.ReadParameters(stream)) return false;
|
if (!previous_layer_.ReadParameters(stream)) return false;
|
||||||
stream.read(reinterpret_cast<char*>(biases_),
|
stream.read(reinterpret_cast<char*>(biases_),
|
||||||
|
@ -60,7 +52,7 @@ namespace Eval::NNUE::Layers {
|
||||||
return !stream.fail();
|
return !stream.fail();
|
||||||
}
|
}
|
||||||
|
|
||||||
// forward propagation
|
// Forward propagation
|
||||||
const OutputType* Propagate(
|
const OutputType* Propagate(
|
||||||
const TransformedFeatureType* transformed_features, char* buffer) const {
|
const TransformedFeatureType* transformed_features, char* buffer) const {
|
||||||
const auto input = previous_layer_.Propagate(
|
const auto input = previous_layer_.Propagate(
|
||||||
|
@ -190,17 +182,11 @@ namespace Eval::NNUE::Layers {
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// parameter type
|
|
||||||
using BiasType = OutputType;
|
using BiasType = OutputType;
|
||||||
using WeightType = std::int8_t;
|
using WeightType = std::int8_t;
|
||||||
|
|
||||||
// Make the learning class a friend
|
|
||||||
friend class Trainer<AffineTransform>;
|
|
||||||
|
|
||||||
// the layer immediately before this layer
|
|
||||||
PreviousLayer previous_layer_;
|
PreviousLayer previous_layer_;
|
||||||
|
|
||||||
// parameter
|
|
||||||
alignas(kCacheLineSize) BiasType biases_[kOutputDimensions];
|
alignas(kCacheLineSize) BiasType biases_[kOutputDimensions];
|
||||||
alignas(kCacheLineSize)
|
alignas(kCacheLineSize)
|
||||||
WeightType weights_[kOutputDimensions * kPaddedInputDimensions];
|
WeightType weights_[kOutputDimensions * kPaddedInputDimensions];
|
||||||
|
|
|
@ -16,7 +16,7 @@ namespace Eval::NNUE::Layers {
|
||||||
using OutputType = std::uint8_t;
|
using OutputType = std::uint8_t;
|
||||||
static_assert(std::is_same<InputType, std::int32_t>::value, "");
|
static_assert(std::is_same<InputType, std::int32_t>::value, "");
|
||||||
|
|
||||||
// number of input/output dimensions
|
// Number of input/output dimensions
|
||||||
static constexpr IndexType kInputDimensions =
|
static constexpr IndexType kInputDimensions =
|
||||||
PreviousLayer::kOutputDimensions;
|
PreviousLayer::kOutputDimensions;
|
||||||
static constexpr IndexType kOutputDimensions = kInputDimensions;
|
static constexpr IndexType kOutputDimensions = kInputDimensions;
|
||||||
|
@ -29,26 +29,19 @@ namespace Eval::NNUE::Layers {
|
||||||
static constexpr std::size_t kBufferSize =
|
static constexpr std::size_t kBufferSize =
|
||||||
PreviousLayer::kBufferSize + kSelfBufferSize;
|
PreviousLayer::kBufferSize + kSelfBufferSize;
|
||||||
|
|
||||||
// Hash value embedded in the evaluation function file
|
// Hash value embedded in the evaluation file
|
||||||
static constexpr std::uint32_t GetHashValue() {
|
static constexpr std::uint32_t GetHashValue() {
|
||||||
std::uint32_t hash_value = 0x538D24C7u;
|
std::uint32_t hash_value = 0x538D24C7u;
|
||||||
hash_value += PreviousLayer::GetHashValue();
|
hash_value += PreviousLayer::GetHashValue();
|
||||||
return hash_value;
|
return hash_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// A string that represents the structure from the input layer to this layer
|
// Read network parameters
|
||||||
static std::string GetStructureString() {
|
|
||||||
return "ClippedReLU[" +
|
|
||||||
std::to_string(kOutputDimensions) + "](" +
|
|
||||||
PreviousLayer::GetStructureString() + ")";
|
|
||||||
}
|
|
||||||
|
|
||||||
// read parameters
|
|
||||||
bool ReadParameters(std::istream& stream) {
|
bool ReadParameters(std::istream& stream) {
|
||||||
return previous_layer_.ReadParameters(stream);
|
return previous_layer_.ReadParameters(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
// forward propagation
|
// Forward propagation
|
||||||
const OutputType* Propagate(
|
const OutputType* Propagate(
|
||||||
const TransformedFeatureType* transformed_features, char* buffer) const {
|
const TransformedFeatureType* transformed_features, char* buffer) const {
|
||||||
const auto input = previous_layer_.Propagate(
|
const auto input = previous_layer_.Propagate(
|
||||||
|
@ -167,10 +160,6 @@ namespace Eval::NNUE::Layers {
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Make the learning class a friend
|
|
||||||
friend class Trainer<ClippedReLU>;
|
|
||||||
|
|
||||||
// the layer immediately before this layer
|
|
||||||
PreviousLayer previous_layer_;
|
PreviousLayer previous_layer_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -7,42 +7,35 @@
|
||||||
|
|
||||||
namespace Eval::NNUE::Layers {
|
namespace Eval::NNUE::Layers {
|
||||||
|
|
||||||
// input layer
|
// Input layer
|
||||||
template <IndexType OutputDimensions, IndexType Offset = 0>
|
template <IndexType OutputDimensions, IndexType Offset = 0>
|
||||||
class InputSlice {
|
class InputSlice {
|
||||||
public:
|
public:
|
||||||
// need to maintain alignment
|
// Need to maintain alignment
|
||||||
static_assert(Offset % kMaxSimdWidth == 0, "");
|
static_assert(Offset % kMaxSimdWidth == 0, "");
|
||||||
|
|
||||||
// output type
|
// Output type
|
||||||
using OutputType = TransformedFeatureType;
|
using OutputType = TransformedFeatureType;
|
||||||
|
|
||||||
// output dimensionality
|
// Output dimensionality
|
||||||
static constexpr IndexType kOutputDimensions = OutputDimensions;
|
static constexpr IndexType kOutputDimensions = OutputDimensions;
|
||||||
|
|
||||||
// Size of the forward propagation buffer used from the input layer to this layer
|
// Size of forward propagation buffer used from the input layer to this layer
|
||||||
static constexpr std::size_t kBufferSize = 0;
|
static constexpr std::size_t kBufferSize = 0;
|
||||||
|
|
||||||
// Hash value embedded in the evaluation function file
|
// Hash value embedded in the evaluation file
|
||||||
static constexpr std::uint32_t GetHashValue() {
|
static constexpr std::uint32_t GetHashValue() {
|
||||||
std::uint32_t hash_value = 0xEC42E90Du;
|
std::uint32_t hash_value = 0xEC42E90Du;
|
||||||
hash_value ^= kOutputDimensions ^ (Offset << 10);
|
hash_value ^= kOutputDimensions ^ (Offset << 10);
|
||||||
return hash_value;
|
return hash_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// A string that represents the structure from the input layer to this layer
|
// Read network parameters
|
||||||
static std::string GetStructureString() {
|
|
||||||
return "InputSlice[" + std::to_string(kOutputDimensions) + "(" +
|
|
||||||
std::to_string(Offset) + ":" +
|
|
||||||
std::to_string(Offset + kOutputDimensions) + ")]";
|
|
||||||
}
|
|
||||||
|
|
||||||
// read parameters
|
|
||||||
bool ReadParameters(std::istream& /*stream*/) {
|
bool ReadParameters(std::istream& /*stream*/) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// forward propagation
|
// Forward propagation
|
||||||
const OutputType* Propagate(
|
const OutputType* Propagate(
|
||||||
const TransformedFeatureType* transformed_features,
|
const TransformedFeatureType* transformed_features,
|
||||||
char* /*buffer*/) const {
|
char* /*buffer*/) const {
|
||||||
|
|
|
@ -1,141 +0,0 @@
|
||||||
// Definition of layer Sum of NNUE evaluation function
|
|
||||||
|
|
||||||
#ifndef NNUE_LAYERS_SUM_H_INCLUDED
|
|
||||||
#define NNUE_LAYERS_SUM_H_INCLUDED
|
|
||||||
|
|
||||||
#include "../nnue_common.h"
|
|
||||||
|
|
||||||
namespace Eval::NNUE::Layers {
|
|
||||||
|
|
||||||
// Layer that sums the output of multiple layers
|
|
||||||
template <typename FirstPreviousLayer, typename... RemainingPreviousLayers>
|
|
||||||
class Sum : public Sum<RemainingPreviousLayers...> {
|
|
||||||
|
|
||||||
private:
|
|
||||||
using Head = FirstPreviousLayer;
|
|
||||||
using Tail = Sum<RemainingPreviousLayers...>;
|
|
||||||
|
|
||||||
public:
|
|
||||||
// Input/output type
|
|
||||||
using InputType = typename Head::OutputType;
|
|
||||||
using OutputType = InputType;
|
|
||||||
static_assert(std::is_same<InputType, typename Tail::InputType>::value, "");
|
|
||||||
|
|
||||||
// number of input/output dimensions
|
|
||||||
static constexpr IndexType kInputDimensions = Head::kOutputDimensions;
|
|
||||||
static constexpr IndexType kOutputDimensions = kInputDimensions;
|
|
||||||
static_assert(kInputDimensions == Tail::kInputDimensions ,"");
|
|
||||||
|
|
||||||
// Size of forward propagation buffer used in this layer
|
|
||||||
static constexpr std::size_t kSelfBufferSize =
|
|
||||||
CeilToMultiple(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() {
|
|
||||||
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;
|
|
||||||
return hash_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
// A string that represents the structure from the input layer to this layer
|
|
||||||
static std::string GetStructureString() {
|
|
||||||
return "Sum[" +
|
|
||||||
std::to_string(kOutputDimensions) + "](" + GetSummandsString() + ")";
|
|
||||||
}
|
|
||||||
|
|
||||||
// read parameters
|
|
||||||
bool ReadParameters(std::istream& stream) {
|
|
||||||
if (!Tail::ReadParameters(stream)) return false;
|
|
||||||
return previous_layer_.ReadParameters(stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
// forward propagation
|
|
||||||
const OutputType* Propagate(
|
|
||||||
const TransformedFeatureType* transformed_features, char* buffer) const {
|
|
||||||
Tail::Propagate(transformed_features, buffer);
|
|
||||||
const auto head_output = previous_layer_.Propagate(
|
|
||||||
transformed_features, buffer + kSelfBufferSize);
|
|
||||||
const auto output = reinterpret_cast<OutputType*>(buffer);
|
|
||||||
for (IndexType i = 0; i <kOutputDimensions; ++i) {
|
|
||||||
output[i] += head_output[i];
|
|
||||||
}
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
// A string that represents the list of layers to be summed
|
|
||||||
static std::string GetSummandsString() {
|
|
||||||
return Head::GetStructureString() + "," + Tail::GetSummandsString();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make the learning class a friend
|
|
||||||
friend class Trainer<Sum>;
|
|
||||||
|
|
||||||
// the layer immediately before this layer
|
|
||||||
FirstPreviousLayer previous_layer_;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Layer that sums the output of multiple layers (when there is one template argument)
|
|
||||||
template <typename PreviousLayer>
|
|
||||||
class Sum<PreviousLayer> {
|
|
||||||
public:
|
|
||||||
// Input/output type
|
|
||||||
using InputType = typename PreviousLayer::OutputType;
|
|
||||||
using OutputType = InputType;
|
|
||||||
|
|
||||||
// number of input/output dimensions
|
|
||||||
static constexpr IndexType kInputDimensions =
|
|
||||||
PreviousLayer::kOutputDimensions;
|
|
||||||
static constexpr IndexType kOutputDimensions = kInputDimensions;
|
|
||||||
|
|
||||||
// Size of the forward propagation buffer used from the input layer to this layer
|
|
||||||
static constexpr std::size_t kBufferSize = PreviousLayer::kBufferSize;
|
|
||||||
|
|
||||||
// Hash value embedded in the evaluation function file
|
|
||||||
static constexpr std::uint32_t GetHashValue() {
|
|
||||||
std::uint32_t hash_value = 0xBCE400B4u;
|
|
||||||
hash_value ^= PreviousLayer::GetHashValue() >> 1;
|
|
||||||
hash_value ^= PreviousLayer::GetHashValue() << 31;
|
|
||||||
return hash_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
// A string that represents the structure from the input layer to this layer
|
|
||||||
static std::string GetStructureString() {
|
|
||||||
return "Sum[" +
|
|
||||||
std::to_string(kOutputDimensions) + "](" + GetSummandsString() + ")";
|
|
||||||
}
|
|
||||||
|
|
||||||
// read parameters
|
|
||||||
bool ReadParameters(std::istream& stream) {
|
|
||||||
return previous_layer_.ReadParameters(stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
// forward propagation
|
|
||||||
const OutputType* Propagate(
|
|
||||||
const TransformedFeatureType* transformed_features, char* buffer) const {
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make the learning class a friend
|
|
||||||
friend class Trainer<Sum>;
|
|
||||||
|
|
||||||
// the layer immediately before this layer
|
|
||||||
PreviousLayer previous_layer_;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Eval::NNUE::Layers
|
|
||||||
|
|
||||||
#endif // #ifndef NNUE_LAYERS_SUM_H_INCLUDED
|
|
|
@ -8,7 +8,6 @@
|
||||||
namespace Eval::NNUE {
|
namespace Eval::NNUE {
|
||||||
|
|
||||||
// Class that holds the result of affine transformation of input features
|
// Class that holds the result of affine transformation of input features
|
||||||
// Keep the evaluation value that is the final output together
|
|
||||||
struct alignas(32) Accumulator {
|
struct alignas(32) Accumulator {
|
||||||
std::int16_t
|
std::int16_t
|
||||||
accumulation[2][kRefreshTriggers.size()][kTransformedFeatureDimensions];
|
accumulation[2][kRefreshTriggers.size()][kTransformedFeatureDimensions];
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
#ifndef NNUE_ARCHITECTURE_H_INCLUDED
|
#ifndef NNUE_ARCHITECTURE_H_INCLUDED
|
||||||
#define NNUE_ARCHITECTURE_H_INCLUDED
|
#define NNUE_ARCHITECTURE_H_INCLUDED
|
||||||
|
|
||||||
// include a header that defines the input features and network structure
|
// Defines the network structure
|
||||||
#include "architectures/halfkp_256x2-32-32.h"
|
#include "architectures/halfkp_256x2-32-32.h"
|
||||||
|
|
||||||
namespace Eval::NNUE {
|
namespace Eval::NNUE {
|
||||||
|
@ -12,7 +12,7 @@ namespace Eval::NNUE {
|
||||||
static_assert(Network::kOutputDimensions == 1, "");
|
static_assert(Network::kOutputDimensions == 1, "");
|
||||||
static_assert(std::is_same<Network::OutputType, std::int32_t>::value, "");
|
static_assert(std::is_same<Network::OutputType, std::int32_t>::value, "");
|
||||||
|
|
||||||
// List of timings to perform all calculations instead of difference calculation
|
// Trigger for full calculation instead of difference calculation
|
||||||
constexpr auto kRefreshTriggers = RawFeatures::kRefreshTriggers;
|
constexpr auto kRefreshTriggers = RawFeatures::kRefreshTriggers;
|
||||||
|
|
||||||
} // namespace Eval::NNUE
|
} // namespace Eval::NNUE
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
namespace Eval::NNUE {
|
namespace Eval::NNUE {
|
||||||
|
|
||||||
// A constant that represents the version of the evaluation function file
|
// Version of the evaluation file
|
||||||
constexpr std::uint32_t kVersion = 0x7AF32F16u;
|
constexpr std::uint32_t kVersion = 0x7AF32F16u;
|
||||||
|
|
||||||
// Constant used in evaluation value calculation
|
// Constant used in evaluation value calculation
|
||||||
|
@ -43,15 +43,9 @@ namespace Eval::NNUE {
|
||||||
|
|
||||||
// Type of input feature after conversion
|
// Type of input feature after conversion
|
||||||
using TransformedFeatureType = std::uint8_t;
|
using TransformedFeatureType = std::uint8_t;
|
||||||
|
|
||||||
// index type
|
|
||||||
using IndexType = std::uint32_t;
|
using IndexType = std::uint32_t;
|
||||||
|
|
||||||
// Forward declaration of learning class template
|
// Round n up to be a multiple of base
|
||||||
template <typename Layer>
|
|
||||||
class Trainer;
|
|
||||||
|
|
||||||
// find the smallest multiple of n and above
|
|
||||||
template <typename IntType>
|
template <typename IntType>
|
||||||
constexpr IntType CeilToMultiple(IntType n, IntType base) {
|
constexpr IntType CeilToMultiple(IntType n, IntType base) {
|
||||||
return (n + base - 1) / base * base;
|
return (n + base - 1) / base * base;
|
||||||
|
|
|
@ -15,34 +15,27 @@ namespace Eval::NNUE {
|
||||||
class FeatureTransformer {
|
class FeatureTransformer {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// number of output dimensions for one side
|
// Number of output dimensions for one side
|
||||||
static constexpr IndexType kHalfDimensions = kTransformedFeatureDimensions;
|
static constexpr IndexType kHalfDimensions = kTransformedFeatureDimensions;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// output type
|
// Output type
|
||||||
using OutputType = TransformedFeatureType;
|
using OutputType = TransformedFeatureType;
|
||||||
|
|
||||||
// number of input/output dimensions
|
// Number of input/output dimensions
|
||||||
static constexpr IndexType kInputDimensions = RawFeatures::kDimensions;
|
static constexpr IndexType kInputDimensions = RawFeatures::kDimensions;
|
||||||
static constexpr IndexType kOutputDimensions = kHalfDimensions * 2;
|
static constexpr IndexType kOutputDimensions = kHalfDimensions * 2;
|
||||||
|
|
||||||
// size of forward propagation buffer
|
// Size of forward propagation buffer
|
||||||
static constexpr std::size_t kBufferSize =
|
static constexpr std::size_t kBufferSize =
|
||||||
kOutputDimensions * sizeof(OutputType);
|
kOutputDimensions * sizeof(OutputType);
|
||||||
|
|
||||||
// Hash value embedded in the evaluation function file
|
// Hash value embedded in the evaluation file
|
||||||
static constexpr std::uint32_t GetHashValue() {
|
static constexpr std::uint32_t GetHashValue() {
|
||||||
return RawFeatures::kHashValue ^ kOutputDimensions;
|
return RawFeatures::kHashValue ^ kOutputDimensions;
|
||||||
}
|
}
|
||||||
|
|
||||||
// a string representing the structure
|
// Read network parameters
|
||||||
static std::string GetStructureString() {
|
|
||||||
return RawFeatures::GetName() + "[" +
|
|
||||||
std::to_string(kInputDimensions) + "->" +
|
|
||||||
std::to_string(kHalfDimensions) + "x2]";
|
|
||||||
}
|
|
||||||
|
|
||||||
// read parameters
|
|
||||||
bool ReadParameters(std::istream& stream) {
|
bool ReadParameters(std::istream& stream) {
|
||||||
stream.read(reinterpret_cast<char*>(biases_),
|
stream.read(reinterpret_cast<char*>(biases_),
|
||||||
kHalfDimensions * sizeof(BiasType));
|
kHalfDimensions * sizeof(BiasType));
|
||||||
|
@ -51,7 +44,7 @@ namespace Eval::NNUE {
|
||||||
return !stream.fail();
|
return !stream.fail();
|
||||||
}
|
}
|
||||||
|
|
||||||
// proceed with the difference calculation if possible
|
// Proceed with the difference calculation if possible
|
||||||
bool UpdateAccumulatorIfPossible(const Position& pos) const {
|
bool UpdateAccumulatorIfPossible(const Position& pos) const {
|
||||||
const auto now = pos.state();
|
const auto now = pos.state();
|
||||||
if (now->accumulator.computed_accumulation) {
|
if (now->accumulator.computed_accumulation) {
|
||||||
|
@ -65,7 +58,7 @@ namespace Eval::NNUE {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// convert input features
|
// Convert input features
|
||||||
void Transform(const Position& pos, OutputType* output, bool refresh) const {
|
void Transform(const Position& pos, OutputType* output, bool refresh) const {
|
||||||
if (refresh || !UpdateAccumulatorIfPossible(pos)) {
|
if (refresh || !UpdateAccumulatorIfPossible(pos)) {
|
||||||
RefreshAccumulator(pos);
|
RefreshAccumulator(pos);
|
||||||
|
@ -259,10 +252,11 @@ namespace Eval::NNUE {
|
||||||
if (reset[perspective]) {
|
if (reset[perspective]) {
|
||||||
std::memcpy(accumulator.accumulation[perspective][i], biases_,
|
std::memcpy(accumulator.accumulation[perspective][i], biases_,
|
||||||
kHalfDimensions * sizeof(BiasType));
|
kHalfDimensions * sizeof(BiasType));
|
||||||
} else {// Difference calculation for the feature amount changed from 1 to 0
|
} else {
|
||||||
std::memcpy(accumulator.accumulation[perspective][i],
|
std::memcpy(accumulator.accumulation[perspective][i],
|
||||||
prev_accumulator.accumulation[perspective][i],
|
prev_accumulator.accumulation[perspective][i],
|
||||||
kHalfDimensions * sizeof(BiasType));
|
kHalfDimensions * sizeof(BiasType));
|
||||||
|
// Difference calculation for the deactivated features
|
||||||
for (const auto index : removed_indices[perspective]) {
|
for (const auto index : removed_indices[perspective]) {
|
||||||
const IndexType offset = kHalfDimensions * index;
|
const IndexType offset = kHalfDimensions * index;
|
||||||
|
|
||||||
|
@ -293,7 +287,7 @@ namespace Eval::NNUE {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
{// Difference calculation for features that changed from 0 to 1
|
{ // Difference calculation for the activated features
|
||||||
for (const auto index : added_indices[perspective]) {
|
for (const auto index : added_indices[perspective]) {
|
||||||
const IndexType offset = kHalfDimensions * index;
|
const IndexType offset = kHalfDimensions * index;
|
||||||
|
|
||||||
|
@ -330,14 +324,9 @@ namespace Eval::NNUE {
|
||||||
accumulator.computed_score = false;
|
accumulator.computed_score = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// parameter type
|
|
||||||
using BiasType = std::int16_t;
|
using BiasType = std::int16_t;
|
||||||
using WeightType = std::int16_t;
|
using WeightType = std::int16_t;
|
||||||
|
|
||||||
// Make the learning class a friend
|
|
||||||
friend class Trainer<FeatureTransformer>;
|
|
||||||
|
|
||||||
// parameter
|
|
||||||
alignas(kCacheLineSize) BiasType biases_[kHalfDimensions];
|
alignas(kCacheLineSize) BiasType biases_[kHalfDimensions];
|
||||||
alignas(kCacheLineSize)
|
alignas(kCacheLineSize)
|
||||||
WeightType weights_[kHalfDimensions * kInputDimensions];
|
WeightType weights_[kHalfDimensions * kInputDimensions];
|
||||||
|
|
Loading…
Add table
Reference in a new issue