1
0
Fork 0
mirror of https://github.com/sockspls/badfish synced 2025-05-01 01:03:09 +00:00

Merge pull request #24 from FireFather/master

Comment translation
This commit is contained in:
nodchip 2020-06-28 11:43:53 +09:00 committed by GitHub
commit 9dc62809c8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
54 changed files with 1903 additions and 1905 deletions

View file

@ -1,75 +1,75 @@
#ifndef _EVALUATE_COMMON_H_
#define _EVALUATE_COMMON_H_
// いまどきの手番つき評価関数(EVAL_KPPTとEVAL_KPP_KKPT)の共用header的なもの。
// A common header-like function for modern evaluation functions (EVAL_KPPT and EVAL_KPP_KKPT).
#if defined(EVAL_NNUE) || defined(EVAL_LEARN)
#include <functional>
// KKファイル名
// KK file name
#define KK_BIN "KK_synthesized.bin"
// KKPファイル名
// KKP file name
#define KKP_BIN "KKP_synthesized.bin"
// KPPファイル名
// KPP file name
#define KPP_BIN "KPP_synthesized.bin"
namespace Eval
{
#if defined(USE_EVAL_HASH)
// prefetchする関数
// prefetch function
void prefetch_evalhash(const Key key);
#endif
// 評価関数のそれぞれのパラメーターに対して関数fを適用してくれるoperator。
// パラメーターの分析などに用いる。
// typeは調査対象を表す。
// type = -1 : KK,KKP,KPPすべて
// type = 0 : KK のみ
// type = 1 : KKPのみ
// type = 2 : KPPのみ
// An operator that applies the function f to each parameter of the evaluation function.
// Used for parameter analysis etc.
// type indicates the survey target.
// type = -1 :KK,KKP,KPP all
// type = 0: KK only
// type = 1: KKP only
// type = 2: KPP only
void foreach_eval_param(std::function<void(int32_t, int32_t)>f, int type = -1);
// --------------------------
// 学習用
// for learning
// --------------------------
#if defined(EVAL_LEARN)
// 学習のときの勾配配列の初期化
// 学習率を引数に渡しておく。0.0なら、defaultの値を採用する。
// update_weights()のepochが、eta_epochまでetaから徐々にeta2に変化する。
// eta2_epoch以降は、eta2から徐々にeta3に変化する。
// Initialize the gradient array during learning
// Pass the learning rate as an argument. If 0.0, the default value is used.
// The epoch of update_weights() gradually changes from eta to eta2 until eta_epoch.
// After eta2_epoch, gradually change from eta2 to eta3.
void init_grad(double eta1, uint64_t eta_epoch, double eta2, uint64_t eta2_epoch, double eta3);
// 現在の局面で出現している特徴すべてに対して、勾配の差分値を勾配配列に加算する。
// freeze[0] : kkは学習させないフラグ
// freeze[1] : kkpは学習させないフラグ
// freeze[2] : kppは学習させないフラグ
// freeze[3] : kpppは学習させないフラグ
// Add the gradient difference value to the gradient array for all features that appear in the current phase.
// freeze[0]: Flag that kk does not learn
// freeze[1]: Flag that kkp does not learn
// freeze[2]: Flag that kpp does not learn
// freeze[3]: Flag that kppp does not learn
void add_grad(Position& pos, Color rootColor, double delt_grad, const std::array<bool, 4>& freeze);
// 現在の勾配をもとにSGDかAdaGradか何かする。
// epoch : 世代カウンター(0から始まる)
// freeze[0] : kkは学習させないフラグ
// freeze[1] : kkpは学習させないフラグ
// freeze[2] : kppは学習させないフラグ
// freeze[3] : kpppは学習させないフラグ
void update_weights(uint64_t epoch, const std::array<bool,4>& freeze);
// Do SGD or AdaGrad or something based on the current gradient.
// epoch: Generation counter (starting from 0)
// freeze[0]: Flag that kk does not learn
// freeze[1]: Flag that kkp does not learn
// freeze[2]: Flag that kpp does not learn
// freeze[3]: Flag that kppp does not learn
void update_weights(uint64_t epoch, const std::array<bool, 4>& freeze);
// 評価関数パラメーターをファイルに保存する。
// ファイルの末尾につける拡張子を指定できる。
// Save the evaluation function parameters to a file.
// You can specify the extension added to the end of the file.
void save_eval(std::string suffix);
// 現在のetaを取得する。
// Get the current eta.
double get_eta();
// -- 学習に関連したコマンド
// --learning related commands
// KKを正規化する関数。元の評価関数と完全に等価にはならないので注意。
// kkp,kppの値をなるべくゼロに近づけることで、学習中に出現しなかった特徴因子の値(ゼロになっている)が
// 妥当であることを保証しようという考え。
// A function that normalizes KK. Note that it is not completely equivalent to the original evaluation function.
// By making the values of kkp and kpp as close to zero as possible, the value of the feature factor (which is zero) that did not appear during learning
// The idea of ensuring it is valid.
void regularize_kk();
#endif

View file

@ -7,35 +7,35 @@ namespace Eval
// --- tables
// あるBonaPieceを相手側から見たときの値
// BONA_PIECE_INITが-1なので符号型で持つ必要がある。
// KPPTを拡張しても当面、BonaPieceが2^15を超えることはないのでint16_tで良しとする。
// Value when a certain BonaPiece is seen from the other side
// BONA_PIECE_INIT is -1, so it must be a signed type.
// Even if KPPT is expanded, BonaPiece will not exceed 2^15 for the time being, so int16_t is good.
int16_t inv_piece_[Eval::fe_end];
// 盤面上のあるBonaPieceをミラーした位置にあるものを返す。
// Returns the one at the position where a BonaPiece on the board is mirrored.
int16_t mir_piece_[Eval::fe_end];
// --- methods
// あるBonaPieceを相手側から見たときの値を返す
// Returns the value when a certain BonaPiece is seen from the other side
Eval::BonaPiece inv_piece(Eval::BonaPiece p) { return (Eval::BonaPiece)inv_piece_[p]; }
// 盤面上のあるBonaPieceをミラーした位置にあるものを返す。
// Returns the one at the position where a BonaPiece on the board is mirrored.
Eval::BonaPiece mir_piece(Eval::BonaPiece p) { return (Eval::BonaPiece)mir_piece_[p]; }
std::function<void()> mir_piece_init_function;
void init_mir_inv_tables()
{
// mirrorとinverseのテーブルの初期化。
// Initialize the mirror and inverse tables.
// 初期化は1回に限る。
// Initialization is limited to once.
static bool first = true;
if (!first) return;
first = false;
// fとeとの交換
// exchange f and e
int t[] = {
f_pawn , e_pawn ,
f_knight , e_knight ,
@ -44,12 +44,12 @@ namespace Eval
f_queen , e_queen ,
};
// 未初期化の値を突っ込んでおく。
// Insert uninitialized value.
for (BonaPiece p = BONA_PIECE_ZERO; p < fe_end; ++p)
{
inv_piece_[p] = BONA_PIECE_NOT_INIT;
// mirrorは手駒に対しては機能しない。元の値を返すだけ。
// mirror does not work for hand pieces. Just return the original value.
mir_piece_[p] = (p < f_pawn) ? p : BONA_PIECE_NOT_INIT;
}
@ -61,26 +61,26 @@ namespace Eval
{
Square sq = (Square)(p - t[i]);
// 見つかった!!
// found!!
BonaPiece q = (p < fe_hand_end) ? BonaPiece(sq + t[i + 1]) : (BonaPiece)(Inv(sq) + t[i + 1]);
inv_piece_[p] = q;
inv_piece_[q] = p;
/*
pに関して盤上の駒は
p >= fe_hand_end
It's a bit tricky, but regarding p
p >= fe_hand_end
When.
pに対してnを整数として(iは偶数しかとらない)
a) t[2n + 0] <= p < t[2n + 1]
b) t[2n + 1] <= p < t[2n + 2]
 
For this p, let n be an integer (i in the above code can only be an even number),
a) When t[2n + 0] <= p <t[2n + 1], the first piece
b) When t[2n + 1] <= p <t[2n + 2], the back piece
Is.
a)pをq = Inv(p-t[2n+0]) + t[2n+1] 180
pとqをswapさせてinv_piece[ ]
*/
Therefore, if p in the range of a) is set to q = Inv(p-t[2n+0]) + t[2n+1], it becomes the back piece in the box rotated 180 degrees.
So inv_piece[] is initialized by swapping p and q.
*/
// 手駒に関してはmirrorなど存在しない。
// There is no mirror for hand pieces.
if (p < fe_hand_end)
continue;
@ -103,28 +103,28 @@ namespace Eval
for (BonaPiece p = BONA_PIECE_ZERO; p < fe_end; ++p)
{
// 未初期化のままになっている。上のテーブルの初期化コードがおかしい。
// It remains uninitialized. The initialization code in the table above is incorrect.
assert(mir_piece_[p] != BONA_PIECE_NOT_INIT && mir_piece_[p] < fe_end);
assert(inv_piece_[p] != BONA_PIECE_NOT_INIT && inv_piece_[p] < fe_end);
// mirとinvは、2回適用したら元の座標に戻る。
// mir and inv return to their original coordinates after being applied twice.
assert(mir_piece_[mir_piece_[p]] == p);
assert(inv_piece_[inv_piece_[p]] == p);
// mir->inv->mir->invは元の場所でなければならない。
// mir->inv->mir->inv must be the original location.
assert(p == inv_piece(mir_piece(inv_piece(mir_piece(p)))));
// inv->mir->inv->mirは元の場所でなければならない。
// inv->mir->inv->mir must be the original location.
assert(p == mir_piece(inv_piece(mir_piece(inv_piece(p)))));
}
#if 0
// 評価関数のミラーをしても大丈夫であるかの事前検証
// 値を書き込んだときにassertionがあるので、ミラーしてダメである場合、
// そのassertに引っかかるはず。
// Pre-verification that it is okay to mirror the evaluation function
// When writing a value, there is an assertion, so if you can't mirror it,
// Should get caught in the assert.
// AperyのWCSC26の評価関数、kppのp1==0とかp1==20(後手の0枚目の歩)とかの
// ところにゴミが入っていて、これを回避しないとassertに引っかかる。
// Apery's WCSC26 evaluation function, kpp p1==0 or p1==20 (0th step on the back)
// There is dust in it, and if you don't avoid it, it will get caught in the assert.
std::unordered_set<BonaPiece> s;
vector<int> a = {
@ -139,24 +139,24 @@ namespace Eval
for (auto b : a)
s.insert((BonaPiece)b);
// さらに出現しない升の盤上の歩、香、桂も除外(Aperyはここにもゴミが入っている)
// Excludes walks, incense, and katsura on the board that do not appear further (Apery also contains garbage here)
for (Rank r = RANK_1; r <= RANK_2; ++r)
for (File f = FILE_1; f <= FILE_9; ++f)
{
if (r == RANK_1)
{
// 1段目の歩
// first step
BonaPiece b1 = BonaPiece(f_pawn + (f | r));
s.insert(b1);
s.insert(inv_piece[b1]);
// 1段目の香
// 1st stage incense
BonaPiece b2 = BonaPiece(f_lance + (f | r));
s.insert(b2);
s.insert(inv_piece[b2]);
}
// 1,2段目の桂
// Katsura on the 1st and 2nd steps
BonaPiece b = BonaPiece(f_knight + (f | r));
s.insert(b);
s.insert(inv_piece[b]);

View file

@ -3,7 +3,7 @@
#if defined(EVAL_NNUE) || defined(EVAL_LEARN)
// BonaPieceのmirror(左右反転)やinverse(盤上の180度回転)させた駒を得るためのツール類。
// BonaPiece's mirror (horizontal flip) and inverse (180° on the board) tools to get pieces.
#include "../types.h"
#include "../evaluate.h"
@ -15,33 +15,33 @@ namespace Eval
// tables
// -------------------------------------------------
// --- BonaPieceに対してMirrorとInverseを提供する。
// --- Provide Mirror and Inverse to BonaPiece.
// これらの配列は、init()かinit_mir_inv_tables();を呼び出すと初期化される。
// このテーブルのみを評価関数のほうから使いたいときは、評価関数の初期化のときに
// init_mir_inv_tables()を呼び出すと良い。
// これらの配列は、以下のKK/KKP/KPPクラスから参照される。
// These arrays are initialized by calling init() or init_mir_inv_tables();.
// If you want to use only this table from the evaluation function,
// Call init_mir_inv_tables().
// These arrays are referenced from the KK/KKP/KPP classes below.
// あるBonaPieceを相手側から見たときの値を返す
// Returns the value when a certain BonaPiece is seen from the other side
extern Eval::BonaPiece inv_piece(Eval::BonaPiece p);
// 盤面上のあるBonaPieceをミラーした位置にあるものを返す。
// Returns the one at the position where a BonaPiece on the board is mirrored.
extern Eval::BonaPiece mir_piece(Eval::BonaPiece p);
// mir_piece/inv_pieceの初期化のときに呼び出されるcallback
// fe_endをユーザー側で拡張するときに用いる。
// この初期化のときに必要なのでinv_piece_とinv_piece_を公開している。
// mir_piece_init_functionが呼び出されたタイミングで、fe_old_endまでは
// これらのテーブルの初期化が完了していることが保証されている。
// callback called when initializing mir_piece/inv_piece
// Used when extending fe_end on the user side.
// Inv_piece_ and inv_piece_ are exposed because they are necessary for this initialization.
// At the timing when mir_piece_init_function is called, until fe_old_end
// It is guaranteed that these tables have been initialized.
extern std::function<void()> mir_piece_init_function;
extern int16_t mir_piece_[Eval::fe_end];
extern int16_t inv_piece_[Eval::fe_end];
// この関数を明示的に呼び出すか、init()を呼び出すかしたときに、上のテーブルが初期化される。
// The table above will be initialized when you call this function explicitly or call init().
extern void init_mir_inv_tables();
}
#endif // defined(EVAL_NNUE) || defined(EVAL_LEARN)
#endif
#endif

View file

@ -1,4 +1,4 @@
// NNUE評価関数で用いる入力特徴量とネットワーク構造の定義
// Definition of input features and network structure used in NNUE evaluation function
#ifndef HALFKP_CR_EP_256X2_32_32_H
#define HALFKP_CR_EP_256X2_32_32_H
@ -16,17 +16,17 @@ namespace Eval {
namespace NNUE {
// 評価関数で用いる入力特徴量
// Input features used in evaluation function
using RawFeatures = Features::FeatureSet<
Features::HalfKP<Features::Side::kFriend>, Features::CastlingRight,
Features::EnPassant>;
// 変換後の入力特徴量の次元数
// Number of input feature dimensions after conversion
constexpr IndexType kTransformedFeatureDimensions = 256;
namespace Layers {
// ネットワーク構造の定義
// define network structure
using InputLayer = InputSlice<kTransformedFeatureDimensions * 2>;
using HiddenLayer1 = ClippedReLU<AffineTransform<InputLayer, 32>>;
using HiddenLayer2 = ClippedReLU<AffineTransform<HiddenLayer1, 32>>;

View file

@ -1,4 +1,4 @@
// NNUE評価関数で用いる入力特徴量とネットワーク構造の定義
// Definition of input features and network structure used in NNUE evaluation function
#ifndef HALFKP_256X2_32_32_H
#define HALFKP_256X2_32_32_H
@ -14,16 +14,16 @@ namespace Eval {
namespace NNUE {
// 評価関数で用いる入力特徴量
// Input features used in evaluation function
using RawFeatures = Features::FeatureSet<
Features::HalfKP<Features::Side::kFriend>>;
// 変換後の入力特徴量の次元数
// Number of input feature dimensions after conversion
constexpr IndexType kTransformedFeatureDimensions = 256;
namespace Layers {
// ネットワーク構造の定義
// define network structure
using InputLayer = InputSlice<kTransformedFeatureDimensions * 2>;
using HiddenLayer1 = ClippedReLU<AffineTransform<InputLayer, 32>>;
using HiddenLayer2 = ClippedReLU<AffineTransform<HiddenLayer1, 32>>;

View file

@ -1,4 +1,4 @@
// NNUE評価関数で用いる入力特徴量とネットワーク構造の定義
// Definition of input features and network structure used in NNUE evaluation function
#ifndef K_P_CR_EP_256X2_32_32_H
#define K_P_CR_EP_256X2_32_32_H
@ -17,16 +17,16 @@ namespace Eval {
namespace NNUE {
// 評価関数で用いる入力特徴量
// Input features used in evaluation function
using RawFeatures = Features::FeatureSet<Features::K, Features::P,
Features::CastlingRight, Features::EnPassant>;
// 変換後の入力特徴量の次元数
// Number of input feature dimensions after conversion
constexpr IndexType kTransformedFeatureDimensions = 256;
namespace Layers {
// ネットワーク構造の定義
// define network structure
using InputLayer = InputSlice<kTransformedFeatureDimensions * 2>;
using HiddenLayer1 = ClippedReLU<AffineTransform<InputLayer, 32>>;
using HiddenLayer2 = ClippedReLU<AffineTransform<HiddenLayer1, 32>>;

View file

@ -1,4 +1,4 @@
// NNUE評価関数で用いる入力特徴量とネットワーク構造の定義
// Definition of input features and network structure used in NNUE evaluation function
#ifndef K_P_CR_256X2_32_32_H
#define K_P_CR_256X2_32_32_H
@ -16,16 +16,16 @@ namespace Eval {
namespace NNUE {
// 評価関数で用いる入力特徴量
// Input features used in evaluation function
using RawFeatures = Features::FeatureSet<Features::K, Features::P,
Features::CastlingRight>;
// 変換後の入力特徴量の次元数
// Number of input feature dimensions after conversion
constexpr IndexType kTransformedFeatureDimensions = 256;
namespace Layers {
// ネットワーク構造の定義
// define network structure
using InputLayer = InputSlice<kTransformedFeatureDimensions * 2>;
using HiddenLayer1 = ClippedReLU<AffineTransform<InputLayer, 32>>;
using HiddenLayer2 = ClippedReLU<AffineTransform<HiddenLayer1, 32>>;

View file

@ -1,4 +1,4 @@
// NNUE評価関数で用いる入力特徴量とネットワーク構造の定義
// Definition of input features and network structure used in NNUE evaluation function
#ifndef K_P_256X2_32_32_H
#define K_P_256X2_32_32_H
@ -14,15 +14,15 @@ namespace Eval {
namespace NNUE {
// 評価関数で用いる入力特徴量
// Input features used in evaluation function
using RawFeatures = Features::FeatureSet<Features::K, Features::P>;
// 変換後の入力特徴量の次元数
// Number of input feature dimensions after conversion
constexpr IndexType kTransformedFeatureDimensions = 256;
namespace Layers {
// ネットワーク構造の定義
// define network structure
using InputLayer = InputSlice<kTransformedFeatureDimensions * 2>;
using HiddenLayer1 = ClippedReLU<AffineTransform<InputLayer, 32>>;
using HiddenLayer2 = ClippedReLU<AffineTransform<HiddenLayer1, 32>>;

View file

@ -1,4 +1,4 @@
// NNUE評価関数の計算に関するコード
// Code for calculating NNUE evaluation function
#if defined(EVAL_NNUE)
@ -16,16 +16,16 @@ namespace Eval {
namespace NNUE {
// 入力特徴量変換器
// Input feature converter
AlignedPtr<FeatureTransformer> feature_transformer;
// 評価関数
// Evaluation function
AlignedPtr<Network> network;
// 評価関数ファイル名
// Evaluation function file name
const char* const kFileName = "nn.bin";
// 評価関数の構造を表す文字列を取得する
// Get a string that represents the structure of the evaluation function
std::string GetArchitectureString() {
return "Features=" + FeatureTransformer::GetStructureString() +
",Network=" + Network::GetStructureString();
@ -35,14 +35,14 @@ namespace {
namespace Detail {
// 評価関数パラメータを初期化する
// Initialize the evaluation function parameters
template <typename T>
void Initialize(AlignedPtr<T>& pointer) {
pointer.reset(reinterpret_cast<T*>(aligned_malloc(sizeof(T), alignof(T))));
std::memset(pointer.get(), 0, sizeof(T));
}
// 評価関数パラメータを読み込む
// read evaluation function parameters
template <typename T>
bool ReadParameters(std::istream& stream, const AlignedPtr<T>& pointer) {
std::uint32_t header;
@ -51,7 +51,7 @@ bool ReadParameters(std::istream& stream, const AlignedPtr<T>& pointer) {
return pointer->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();
@ -61,7 +61,7 @@ bool WriteParameters(std::ostream& stream, const AlignedPtr<T>& pointer) {
} // namespace Detail
// 評価関数パラメータを初期化する
// Initialize the evaluation function parameters
void Initialize() {
Detail::Initialize(feature_transformer);
Detail::Initialize(network);
@ -69,7 +69,7 @@ void Initialize() {
} // namespace
// ヘッダを読み込む
// read the header
bool ReadHeader(std::istream& stream,
std::uint32_t* hash_value, std::string* architecture) {
std::uint32_t version, size;
@ -82,7 +82,7 @@ bool ReadHeader(std::istream& stream,
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));
@ -93,7 +93,7 @@ bool WriteHeader(std::ostream& stream,
return !stream.fail();
}
// 評価関数パラメータを読み込む
// read evaluation function parameters
bool ReadParameters(std::istream& stream) {
std::uint32_t hash_value;
std::string architecture;
@ -104,7 +104,7 @@ bool ReadParameters(std::istream& stream) {
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;
@ -112,12 +112,12 @@ bool WriteParameters(std::ostream& stream) {
return !stream.fail();
}
// 差分計算ができるなら進める
// proceed if you can calculate the difference
static void UpdateAccumulatorIfPossible(const Position& pos) {
feature_transformer->UpdateAccumulatorIfPossible(pos);
}
// 評価値を計算する
// Calculate the evaluation value
static Value ComputeScore(const Position& pos, bool refresh = false) {
auto& accumulator = pos.state()->accumulator;
if (!refresh && accumulator.computed_score) {
@ -130,22 +130,22 @@ static Value ComputeScore(const Position& pos, bool refresh = false) {
alignas(kCacheLineSize) char buffer[Network::kBufferSize];
const auto output = network->Propagate(transformed_features, buffer);
// VALUE_MAX_EVALより大きな値が返ってくるとaspiration searchがfail highして
// 探索が終わらなくなるのでVALUE_MAX_EVAL以下であることを保証すべき。
// When a value larger than VALUE_MAX_EVAL is returned, aspiration search fails high
// It should be guaranteed that it is less than VALUE_MAX_EVAL because the search will not end.
// この現象が起きても、対局時に秒固定などだとそこで探索が打ち切られるので、
// 1つ前のiterationのときの最善手がbestmoveとして指されるので見かけ上、
// 問題ない。このVALUE_MAX_EVALが返ってくるような状況は、ほぼ詰みの局面であり、
// そのような詰みの局面が出現するのは終盤で形勢に大差がついていることが多いので
// 勝敗にはあまり影響しない。
// Even if this phenomenon occurs, if the seconds are fixed when playing, the search will be aborted there, so
// The best move in the previous iteration is pointed to as bestmove, so apparently
// no problem. The situation in which this VALUE_MAX_EVAL is returned is almost at a dead end,
// Since such a jamming phase often appears at the end, there is a big difference in the situation
// Doesn't really affect the outcome.
// しかし、教師生成時などdepth固定で探索するときに探索から戻ってこなくなるので
// そのスレッドの計算時間を無駄にする。またdepth固定対局でtime-outするようになる。
// However, when searching with a fixed depth such as when creating a teacher, it will not return from the search
// Waste the computation time for that thread. Also, it will be timed out with fixed depth game.
auto score = static_cast<Value>(output[0] / FV_SCALE);
// 1) ここ、下手にclipすると学習時には影響があるような気もするが…。
// 2) accumulator.scoreは、差分計算の時に用いないので書き換えて問題ない。
// 1) I feel that if I clip too poorly, it will have an effect on my learning...
// 2) Since accumulator.score is not used at the time of difference calculation, it can be rewritten without any problem.
score = Math::clamp(score , -VALUE_MAX_EVAL , VALUE_MAX_EVAL);
accumulator.score = score;
@ -153,10 +153,10 @@ static Value ComputeScore(const Position& pos, bool refresh = false) {
return accumulator.score;
}
} // namespace NNUE
} // namespace NNUE
#if defined(USE_EVAL_HASH)
// HashTableに評価値を保存するために利用するクラス
// Class used to store evaluation values in HashTable
struct alignas(16) ScoreKeyValue {
#if defined(USE_SSE2)
ScoreKeyValue() = default;
@ -171,15 +171,15 @@ struct alignas(16) ScoreKeyValue {
}
#endif
// evaluate hashでatomicに操作できる必要があるのでそのための操作子
// It is necessary to be able to operate atomically with evaluate hash, so the manipulator for that
void encode() {
#if defined(USE_SSE2)
// ScoreKeyValue は atomic にコピーされるので key が合っていればデータも合っている。
// ScoreKeyValue is copied to atomic, so if the key matches, the data matches.
#else
key ^= score;
#endif
}
// decode()はencode()の逆変換だが、xorなので逆変換も同じ変換。
// decode() is the reverse conversion of encode(), but since it is xor, the reverse conversion is the same.
void decode() { encode(); }
union {
@ -193,45 +193,45 @@ struct alignas(16) ScoreKeyValue {
};
};
// シンプルなHashTableの実装。
// Sizeは2のべき乗。
// Simple HashTable implementation.
// Size is a power of 2.
template <typename T, size_t Size>
struct HashTable {
HashTable() { clear(); }
T* operator [] (const Key k) { return entries_ + (static_cast<size_t>(k) & (Size - 1)); }
void clear() { memset(entries_, 0, sizeof(T)*Size); }
// Size が 2のべき乗であることのチェック
// Check that Size is a power of 2
static_assert((Size & (Size - 1)) == 0, "");
private:
T entries_[Size];
};
// evaluateしたものを保存しておくHashTable(俗にいうehash)
//HashTable to save the evaluated ones (following ehash)
#if !defined(USE_LARGE_EVAL_HASH)
// 134MB(魔女のAVX2以外の時の設定)
// 134MB (setting other than witch's AVX2)
struct EvaluateHashTable : HashTable<ScoreKeyValue, 0x800000> {};
#else
// prefetch有りなら大きいほうが良いのでは…。
// → あまり変わらないし、メモリもったいないのでデフォルトでは↑の設定で良いか…。
// 1GB(魔女のAVX2の時の設定)
// If you have prefetch, it's better to have a big one...
// → It doesn't change much and the memory is wasteful, so is it okay to set ↑ by default?
// 1GB (setting for witch's AVX2)
struct EvaluateHashTable : HashTable<ScoreKeyValue, 0x4000000> {};
#endif
EvaluateHashTable g_evalTable;
// prefetchする関数も用意しておく。
// Prepare a function to prefetch.
void prefetch_evalhash(const Key key) {
constexpr auto mask = ~((uint64_t)0x1f);
prefetch((void*)((uint64_t)g_evalTable[key] & mask));
}
#endif
// 評価関数ファイルを読み込む
// benchコマンドなどでOptionsを保存して復元するのでこのときEvalDirが変更されたことになって、
// 評価関数の再読込の必要があるというフラグを立てるため、この関数は2度呼び出されることがある。
// read the evaluation function file
// Save and restore Options with bench command etc., so EvalDir is changed at this time,
// This function may be called twice to flag that the evaluation function needs to be reloaded.
void load_eval() {
NNUE::Initialize();
@ -249,7 +249,7 @@ void load_eval() {
// ASSERT(result);
if (!result)
{
// 読み込みエラーのとき終了してくれないと困る。
// It's a problem if it doesn't finish when there is a read error.
std::cout << "Error! " << NNUE::kFileName << " not found or wrong format" << std::endl;
//my_exit();
}
@ -260,19 +260,19 @@ void load_eval() {
std::cout << "info string NNUE " << NNUE::kFileName << " not loaded" << std::endl;
}
// 初期化
// Initialization
void init() {
}
// 評価関数。差分計算ではなく全計算する。
// Position::set()で一度だけ呼び出される。(以降は差分計算)
// 手番側から見た評価値を返すので注意。(他の評価関数とは設計がこの点において異なる)
// なので、この関数の最適化は頑張らない。
// Evaluation function. Perform full calculation instead of difference calculation.
// Called only once with Position::set(). (The difference calculation after that)
// Note that the evaluation value seen from the turn side is returned. (Design differs from other evaluation functions in this respect)
// Since, we will not try to optimize this function.
Value compute_eval(const Position& pos) {
return NNUE::ComputeScore(pos, true);
}
// 評価関数
// Evaluation function
Value evaluate(const Position& pos) {
const auto& accumulator = pos.state()->accumulator;
if (accumulator.computed_score) {
@ -280,8 +280,8 @@ Value evaluate(const Position& pos) {
}
#if defined(USE_GLOBAL_OPTIONS)
// GlobalOptionsでeval hashを用いない設定になっているなら
// eval hashへの照会をskipする。
// If Global Options is set not to use eval hash
// Skip the query to the eval hash.
if (!GlobalOptions.use_eval_hash) {
ASSERT_LV5(pos.state()->materialValue == Eval::material(pos));
return NNUE::ComputeScore(pos);
@ -289,19 +289,19 @@ Value evaluate(const Position& pos) {
#endif
#if defined(USE_EVAL_HASH)
// evaluate hash tableにはあるかも。
// May be in the evaluate hash table.
const Key key = pos.key();
ScoreKeyValue entry = *g_evalTable[key];
entry.decode();
if (entry.key == key) {
// あった!
// there were!
return Value(entry.score);
}
#endif
Value score = NNUE::ComputeScore(pos);
#if defined(USE_EVAL_HASH)
// せっかく計算したのでevaluate hash tableに保存しておく。
// Since it was calculated carefully, save it in the evaluate hash table.
entry.key = key;
entry.score = score;
entry.encode();
@ -311,12 +311,12 @@ Value evaluate(const Position& pos) {
return score;
}
// 差分計算ができるなら進める
// proceed if you can calculate the difference
void evaluate_with_no_return(const Position& pos) {
NNUE::UpdateAccumulatorIfPossible(pos);
}
// 現在の局面の評価値の内訳を表示する
// display the breakdown of the evaluation value of the current phase
void print_eval_stat(Position& /*pos*/) {
std::cout << "--- EVAL STAT: not implemented" << std::endl;
}

View file

@ -1,4 +1,4 @@
// NNUE評価関数で用いるheader
// header used in NNUE evaluation function
#ifndef _EVALUATE_NNUE_H_
#define _EVALUATE_NNUE_H_
@ -14,11 +14,11 @@ namespace Eval {
namespace NNUE {
// 評価関数の構造のハッシュ値
// hash value of evaluation function structure
constexpr std::uint32_t kHashValue =
FeatureTransformer::GetHashValue() ^ Network::GetHashValue();
// メモリ領域の解放を自動化するためのデリータ
// Deleter for automating release of memory area
template <typename T>
struct AlignedDeleter {
void operator()(T* ptr) const {
@ -29,30 +29,30 @@ struct AlignedDeleter {
template <typename T>
using AlignedPtr = std::unique_ptr<T, AlignedDeleter<T>>;
// 入力特徴量変換器
// Input feature converter
extern AlignedPtr<FeatureTransformer> feature_transformer;
// 評価関数
// Evaluation function
extern AlignedPtr<Network> network;
// 評価関数ファイル名
// Evaluation function file name
extern const char* const kFileName;
// 評価関数の構造を表す文字列を取得する
// Get a string that represents the structure of the evaluation function
std::string GetArchitectureString();
// ヘッダを読み込む
// read the header
bool ReadHeader(std::istream& stream,
std::uint32_t* hash_value, std::string* architecture);
// ヘッダを書き込む
// write the header
bool WriteHeader(std::ostream& stream,
std::uint32_t hash_value, const std::string& architecture);
// 評価関数パラメータを読み込む
// read evaluation function parameters
bool ReadParameters(std::istream& stream);
// 評価関数パラメータを書き込む
// write evaluation function parameters
bool WriteParameters(std::ostream& stream);
} // namespace NNUE
@ -61,4 +61,4 @@ bool WriteParameters(std::ostream& stream);
#endif // defined(EVAL_NNUE)
#endif
#endif

View file

@ -1,4 +1,4 @@
// NNUE評価関数の学習時用のコード
// Code for learning NNUE evaluation function
#if defined(EVAL_LEARN) && defined(EVAL_NNUE)
@ -31,30 +31,30 @@ namespace NNUE {
namespace {
// 学習データ
// learning data
std::vector<Example> examples;
// examplesの排他制御をするMutex
// Mutex for exclusive control of examples
std::mutex examples_mutex;
// ミニバッチのサンプル数
// number of samples in mini-batch
uint64_t batch_size;
// 乱数生成器
// random number generator
std::mt19937 rng;
// 学習器
// learner
std::shared_ptr<Trainer<Network>> trainer;
// 学習率のスケール
// Learning rate scale
double global_learning_rate_scale;
// 学習率のスケールを取得する
// Get the learning rate scale
double GetGlobalLearningRateScale() {
return global_learning_rate_scale;
}
// ハイパーパラメータなどのオプションを学習器に伝える
// Tell the learner options such as hyperparameters
void SendMessages(std::vector<Message> messages) {
for (auto& message : messages) {
trainer->SendMessage(&message);
@ -64,7 +64,7 @@ void SendMessages(std::vector<Message> messages) {
} // namespace
// 学習の初期化を行う
// Initialize learning
void InitializeTraining(double eta1, uint64_t eta1_epoch,
double eta2, uint64_t eta2_epoch, double eta3) {
std::cout << "Initializing NN training for "
@ -82,18 +82,18 @@ void InitializeTraining(double eta1, uint64_t eta1_epoch,
EvalLearningTools::Weight::init_eta(eta1, eta2, eta3, eta1_epoch, eta2_epoch);
}
// ミニバッチのサンプル数を設定する
// set the number of samples in the mini-batch
void SetBatchSize(uint64_t size) {
assert(size > 0);
batch_size = size;
}
// 学習率のスケールを設定する
// set the learning rate scale
void SetGlobalLearningRateScale(double scale) {
global_learning_rate_scale = scale;
}
// ハイパーパラメータなどのオプションを設定する
// Set options such as hyperparameters
void SetOptions(const std::string& options) {
std::vector<Message> messages;
for (const auto& option : Split(options, ',')) {
@ -108,7 +108,7 @@ void SetOptions(const std::string& options) {
SendMessages(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::kFileName);
std::ifstream stream(file_name, std::ios::binary);
@ -118,7 +118,7 @@ void RestoreParameters(const std::string& dir_name) {
SendMessages({{"reset"}});
}
// 学習データを1サンプル追加する
// Add 1 sample of learning data
void AddExample(Position& pos, Color rootColor,
const Learner::PackedSfenValue& psv, double weight) {
Example example;
@ -162,7 +162,7 @@ void AddExample(Position& pos, Color rootColor,
examples.push_back(std::move(example));
}
// 評価関数パラメーターを更新する
// update the evaluation function parameters
void UpdateParameters(uint64_t epoch) {
assert(batch_size > 0);
@ -192,21 +192,21 @@ void UpdateParameters(uint64_t epoch) {
SendMessages({{"quantize_parameters"}});
}
// 学習に問題が生じていないかチェックする
// Check if there are any problems with learning
void CheckHealth() {
SendMessages({{"check_health"}});
}
} // namespace NNUE
// 評価関数パラメーターをファイルに保存する
// save merit function parameters to a file
void save_eval(std::string dir_name) {
auto eval_dir = Path::Combine(Options["EvalSaveDir"], dir_name);
std::cout << "save_eval() start. folder = " << eval_dir << std::endl;
// すでにこのフォルダがあるならmkdir()に失敗するが、
// 別にそれは構わない。なければ作って欲しいだけ。
// また、EvalSaveDirまでのフォルダは掘ってあるものとする。
// mkdir() will fail if this folder already exists, but
// Apart from that. If not, I just want you to make it.
// Also, assume that the folders up to EvalSaveDir have been dug.
Dependency::mkdir(eval_dir);
if (Options["SkipLoadingEval"] && NNUE::trainer) {
@ -221,7 +221,7 @@ void save_eval(std::string dir_name) {
std::cout << "save_eval() finished. folder = " << eval_dir << std::endl;
}
// 現在のetaを取得する
// get the current eta
double get_eta() {
return NNUE::GetGlobalLearningRateScale() * EvalLearningTools::Weight::eta;
}

View file

@ -1,4 +1,4 @@
// NNUE評価関数の学習で用いるインターフェイス
// Interface used for learning NNUE evaluation function
#ifndef _EVALUATE_NNUE_LEARNER_H_
#define _EVALUATE_NNUE_LEARNER_H_
@ -11,30 +11,30 @@ namespace Eval {
namespace NNUE {
// 学習の初期化を行う
// Initialize learning
void InitializeTraining(double eta1, uint64_t eta1_epoch,
double eta2, uint64_t eta2_epoch, double eta3);
// ミニバッチのサンプル数を設定する
// set the number of samples in the mini-batch
void SetBatchSize(uint64_t size);
// 学習率のスケールを設定する
// set the learning rate scale
void SetGlobalLearningRateScale(double scale);
// ハイパーパラメータなどのオプションを設定する
// Set options such as hyperparameters
void SetOptions(const std::string& options);
// 学習用評価関数パラメータをファイルから読み直す
// Reread the evaluation function parameters for learning from the file
void RestoreParameters(const std::string& dir_name);
// 学習データを1サンプル追加する
// Add 1 sample of learning data
void AddExample(Position& pos, Color rootColor,
const Learner::PackedSfenValue& psv, double weight);
// 評価関数パラメータを更新する
// update the evaluation function parameters
void UpdateParameters(uint64_t epoch);
// 学習に問題が生じていないかチェックする
// Check if there are any problems with learning
void CheckHealth();
} // namespace NNUE
@ -43,4 +43,4 @@ void CheckHealth();
#endif // defined(EVAL_LEARN) && defined(EVAL_NNUE)
#endif
#endif

View file

@ -1,4 +1,4 @@
// NNUE評価関数の入力特徴量Kの定義
//Definition of input feature quantity K of NNUE evaluation function
#if defined(EVAL_NNUE)
@ -11,10 +11,10 @@ namespace Eval {
namespace Features {
// 特徴量のうち、値が1であるインデックスのリストを取得する
// Get a list of indices with a value of 1 among the features
void CastlingRight::AppendActiveIndices(
const Position& pos, Color perspective, IndexList* active) {
// コンパイラの警告を回避するため、配列サイズが小さい場合は何もしない
// do nothing if array size is small to avoid compiler warning
if (RawFeatures::kMaxActiveDimensions < kMaxActiveDimensions) return;
int castling_rights = pos.state()->castlingRights;
@ -28,14 +28,14 @@ namespace Eval {
& ((castling_rights >> 2) & 3);
}
for (int i = 0; i < kDimensions; ++i) {
for (int i = 0; i <kDimensions; ++i) {
if (relative_castling_rights & (i << 1)) {
active->push_back(i);
}
}
}
// 特徴量のうち、一手前から値が変化したインデックスのリストを取得する
// 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) {

View file

@ -1,4 +1,4 @@
// NNUE評価関数の入力特徴量Kの定義
//Definition of input feature quantity K of NNUE evaluation function
#ifndef _NNUE_FEATURES_CASTLING_RIGHT_H_
#define _NNUE_FEATURES_CASTLING_RIGHT_H_
@ -14,25 +14,25 @@ namespace Eval {
namespace Features {
// 特徴量K玉の位置
// Feature K: Ball position
class CastlingRight {
public:
// 特徴量名
// feature quantity name
static constexpr const char* kName = "CastlingRight";
// 評価関数ファイルに埋め込むハッシュ値
// Hash value embedded in the evaluation function file
static constexpr std::uint32_t kHashValue = 0x913968AAu;
// 特徴量の次元数
// number of feature dimensions
static constexpr IndexType kDimensions = 4;
// 特徴量のうち、同時に値が1となるインデックスの数の最大値
// The maximum value of the number of indexes whose value is 1 at the same time among the feature values
static constexpr IndexType kMaxActiveDimensions = 4;
// 差分計算の代わりに全計算を行うタイミング
// Timing of full calculation instead of difference calculation
static constexpr TriggerEvent kRefreshTrigger = TriggerEvent::kNone;
// 特徴量のうち、値が1であるインデックスのリストを取得する
// 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 whose values ??have changed from the previous one in the feature quantity
static void AppendChangedIndices(const Position& pos, Color perspective,
IndexList* removed, IndexList* added);
};
@ -45,4 +45,4 @@ namespace Eval {
#endif // defined(EVAL_NNUE)
#endif
#endif

View file

@ -1,4 +1,4 @@
// NNUE評価関数の入力特徴量Kの定義
//Definition of input feature quantity K of NNUE evaluation function
#if defined(EVAL_NNUE)
@ -11,10 +11,10 @@ namespace Eval {
namespace Features {
// 特徴量のうち、値が1であるインデックスのリストを取得する
// Get a list of indices with a value of 1 among the features
void EnPassant::AppendActiveIndices(
const Position& pos, Color perspective, IndexList* active) {
// コンパイラの警告を回避するため、配列サイズが小さい場合は何もしない
// do nothing if array size is small to avoid compiler warning
if (RawFeatures::kMaxActiveDimensions < kMaxActiveDimensions) return;
auto epSquare = pos.state()->epSquare;
@ -30,7 +30,7 @@ namespace Eval {
active->push_back(file);
}
// 特徴量のうち、一手前から値が変化したインデックスのリストを取得する
// 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) {

View file

@ -1,4 +1,4 @@
// NNUE評価関数の入力特徴量Kの定義
//Definition of input feature quantity K of NNUE evaluation function
#ifndef _NNUE_FEATURES_ENPASSANT_H_
#define _NNUE_FEATURES_ENPASSANT_H_
@ -14,25 +14,25 @@ namespace Eval {
namespace Features {
// 特徴量K玉の位置
// Feature K: Ball position
class EnPassant {
public:
// 特徴量名
// feature quantity name
static constexpr const char* kName = "EnPassant";
// 評価関数ファイルに埋め込むハッシュ値
// Hash value embedded in the evaluation function file
static constexpr std::uint32_t kHashValue = 0x02924F91u;
// 特徴量の次元数
// number of feature dimensions
static constexpr IndexType kDimensions = 8;
// 特徴量のうち、同時に値が1となるインデックスの数の最大値
// The maximum value of the number of indexes whose value is 1 at the same time among the feature values
static constexpr IndexType kMaxActiveDimensions = 1;
// 差分計算の代わりに全計算を行うタイミング
// Timing of full calculation instead of difference calculation
static constexpr TriggerEvent kRefreshTrigger = TriggerEvent::kAnyPieceMoved;
// 特徴量のうち、値が1であるインデックスのリストを取得する
// 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 whose values ??have changed from the previous one in the feature quantity
static void AppendChangedIndices(const Position& pos, Color perspective,
IndexList* removed, IndexList* added);
};
@ -45,4 +45,4 @@ namespace Eval {
#endif // defined(EVAL_NNUE)
#endif
#endif

View file

@ -1,4 +1,4 @@
// NNUE評価関数の入力特徴量セットを表すクラステンプレート
// A class template that represents the input feature set of the NNUE evaluation function
#ifndef _NNUE_FEATURE_SET_H_
#define _NNUE_FEATURE_SET_H_
@ -14,7 +14,7 @@ namespace NNUE {
namespace Features {
// 値のリストを表すクラステンプレート
// A class template that represents a list of values
template <typename T, T... Values>
struct CompileTimeList;
template <typename T, T First, T... Remaining>
@ -36,7 +36,7 @@ struct CompileTimeList<T> {
static constexpr std::array<T, 0> kValues = {{}};
};
// リストの先頭への追加を行うクラステンプレート
// Class template that adds to the beginning of the list
template <typename T, typename ListType, T Value>
struct AppendToList;
template <typename T, T... Values, T AnotherValue>
@ -44,7 +44,7 @@ struct AppendToList<T, CompileTimeList<T, Values...>, AnotherValue> {
using Result = CompileTimeList<T, AnotherValue, Values...>;
};
// ソートされた重複のないリストへの追加を行うクラステンプレート
// Class template for adding to a sorted, unique list
template <typename T, typename ListType, T Value>
struct InsertToSet;
template <typename T, T First, T... Remaining, T AnotherValue>
@ -52,7 +52,7 @@ struct InsertToSet<T, CompileTimeList<T, First, Remaining...>, AnotherValue> {
using Result = std::conditional_t<
CompileTimeList<T, First, Remaining...>::Contains(AnotherValue),
CompileTimeList<T, First, Remaining...>,
std::conditional_t<(AnotherValue < First),
std::conditional_t<(AnotherValue <First),
CompileTimeList<T, AnotherValue, First, Remaining...>,
typename AppendToList<T, typename InsertToSet<
T, CompileTimeList<T, Remaining...>, AnotherValue>::Result,
@ -63,21 +63,21 @@ struct InsertToSet<T, CompileTimeList<T>, Value> {
using Result = CompileTimeList<T, Value>;
};
// 特徴量セットの基底クラス
// Base class of feature set
template <typename Derived>
class FeatureSetBase {
public:
// 特徴量のうち、値が1であるインデックスのリストを取得する
// Get a list of indices with a value of 1 among the features
template <typename IndexListType>
static void AppendActiveIndices(
const Position& pos, TriggerEvent trigger, IndexListType active[2]) {
for (const auto perspective : Colors) {
for (const auto perspective :Colors) {
Derived::CollectActiveIndices(
pos, trigger, perspective, &active[perspective]);
}
}
// 特徴量のうち、一手前から値が変化したインデックスのリストを取得する
// Get a list of indices whose values have changed from the previous one in the feature quantity
template <typename PositionType, typename IndexListType>
static void AppendChangedIndices(
const PositionType& pos, TriggerEvent trigger,
@ -85,7 +85,7 @@ class FeatureSetBase {
const auto& dp = pos.state()->dirtyPiece;
if (dp.dirty_num == 0) return;
for (const auto perspective : Colors) {
for (const auto perspective :Colors) {
reset[perspective] = false;
switch (trigger) {
case TriggerEvent::kNone:
@ -120,8 +120,8 @@ class FeatureSetBase {
}
};
// 特徴量セットを表すクラステンプレート
// 実行時の計算量を線形にするために、内部の処理はテンプレート引数の逆順に行う
// Class template that represents the feature set
// do internal processing in reverse order of template arguments in order to linearize the amount of calculation at runtime
template <typename FirstFeatureType, typename... RemainingFeatureTypes>
class FeatureSet<FirstFeatureType, RemainingFeatureTypes...> :
public FeatureSetBase<
@ -131,27 +131,27 @@ class FeatureSet<FirstFeatureType, RemainingFeatureTypes...> :
using Tail = FeatureSet<RemainingFeatureTypes...>;
public:
// 評価関数ファイルに埋め込むハッシュ値
// Hash value embedded in the evaluation function file
static constexpr std::uint32_t kHashValue =
Head::kHashValue ^ (Tail::kHashValue << 1) ^ (Tail::kHashValue >> 31);
// 特徴量の次元数
// number of feature dimensions
static constexpr IndexType kDimensions =
Head::kDimensions + Tail::kDimensions;
// 特徴量のうち、同時に値が1となるインデックスの数の最大値
// The maximum value of the number of indexes whose value is 1 at the same time among the feature values
static constexpr IndexType kMaxActiveDimensions =
Head::kMaxActiveDimensions + Tail::kMaxActiveDimensions;
// 差分計算の代わりに全計算を行うタイミングのリスト
// List of timings to perform all calculations instead of difference calculation
using SortedTriggerSet = typename InsertToSet<TriggerEvent,
typename Tail::SortedTriggerSet, Head::kRefreshTrigger>::Result;
static constexpr auto kRefreshTriggers = SortedTriggerSet::kValues;
// 特徴量名を取得する
// Get the feature quantity name
static std::string GetName() {
return std::string(Head::kName) + "+" + Tail::GetName();
}
private:
// 特徴量のうち、値が1であるインデックスのリストを取得する
// 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,
@ -166,7 +166,7 @@ class FeatureSet<FirstFeatureType, RemainingFeatureTypes...> :
}
}
// 特徴量のうち、一手前から値が変化したインデックスのリストを取得する
// 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,
@ -185,36 +185,36 @@ class FeatureSet<FirstFeatureType, RemainingFeatureTypes...> :
}
}
// 基底クラスと、自身を再帰的に利用するクラステンプレートをfriendにする
// Make the base class and the class template that recursively uses itself a friend
friend class FeatureSetBase<FeatureSet>;
template <typename... FeatureTypes>
friend class FeatureSet;
};
// 特徴量セットを表すクラステンプレート
// テンプレート引数が1つの場合の特殊化
// Class template that represents the feature set
// Specialization with one template argument
template <typename FeatureType>
class FeatureSet<FeatureType> : public FeatureSetBase<FeatureSet<FeatureType>> {
public:
// 評価関数ファイルに埋め込むハッシュ値
// Hash value embedded in the evaluation function file
static constexpr std::uint32_t kHashValue = FeatureType::kHashValue;
// 特徴量の次元数
// number of feature dimensions
static constexpr IndexType kDimensions = FeatureType::kDimensions;
// 特徴量のうち、同時に値が1となるインデックスの数の最大値
// 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;
// 差分計算の代わりに全計算を行うタイミングのリスト
// List of timings to perform all calculations instead of difference calculation
using SortedTriggerSet =
CompileTimeList<TriggerEvent, FeatureType::kRefreshTrigger>;
static constexpr auto kRefreshTriggers = SortedTriggerSet::kValues;
// 特徴量名を取得する
// Get the feature quantity name
static std::string GetName() {
return FeatureType::kName;
}
private:
// 特徴量のうち、値が1であるインデックスのリストを取得する
// Get a list of indices with a value of 1 among the features
static void CollectActiveIndices(
const Position& pos, const TriggerEvent trigger, const Color perspective,
IndexList* const active) {
@ -223,7 +223,7 @@ class FeatureSet<FeatureType> : public FeatureSetBase<FeatureSet<FeatureType>> {
}
}
// 特徴量のうち、一手前から値が変化したインデックスのリストを取得する
// Get a list of indices whose values have changed from the previous one in the feature quantity
static void CollectChangedIndices(
const Position& pos, const TriggerEvent trigger, const Color perspective,
IndexList* const removed, IndexList* const added) {
@ -232,7 +232,7 @@ class FeatureSet<FeatureType> : public FeatureSetBase<FeatureSet<FeatureType>> {
}
}
// 基底クラスと、自身を再帰的に利用するクラステンプレートをfriendにする
// Make the base class and the class template that recursively uses itself a friend
friend class FeatureSetBase<FeatureSet>;
template <typename... FeatureTypes>
friend class FeatureSet;
@ -246,4 +246,4 @@ class FeatureSet<FeatureType> : public FeatureSetBase<FeatureSet<FeatureType>> {
#endif // defined(EVAL_NNUE)
#endif
#endif

View file

@ -1,4 +1,4 @@
// NNUE評価関数の入力特徴量の共通ヘッダ
//Common header of input features of NNUE evaluation function
#ifndef _NNUE_FEATURES_COMMON_H_
#define _NNUE_FEATURES_COMMON_H_
@ -14,26 +14,26 @@ namespace NNUE {
namespace Features {
// インデックスリストの型
// Index list type
class IndexList;
// 特徴量セットを表すクラステンプレート
// Class template that represents the feature set
template <typename... FeatureTypes>
class FeatureSet;
// 差分計算の代わりに全計算を行うタイミングの種類
// Type of timing to perform all calculations instead of difference calculation
enum class TriggerEvent {
kNone, // 可能な場合は常に差分計算する
kFriendKingMoved, // 自玉が移動した場合に全計算する
kEnemyKingMoved, // 敵玉が移動した場合に全計算する
kAnyKingMoved, // どちらかの玉が移動した場合に全計算する
kAnyPieceMoved, // 常に全計算する
kNone, // Calculate the difference whenever possible
kFriendKingMoved, // calculate all when own ball moves
kEnemyKingMoved, // do all calculations when enemy balls move
kAnyKingMoved, // do all calculations if either ball moves
kAnyPieceMoved, // always do all calculations
};
// 手番側or相手側
// turn side or other side
enum class Side {
kFriend, // 手番側
kEnemy, // 相手側
kFriend, // turn side
kEnemy, // opponent
};
} // namespace Features
@ -44,4 +44,4 @@ enum class Side {
#endif // defined(EVAL_NNUE)
#endif
#endif

View file

@ -1,4 +1,4 @@
// NNUE評価関数の入力特徴量HalfKPの定義
//Definition of input features HalfKP of NNUE evaluation function
#if defined(EVAL_NNUE)
@ -11,13 +11,13 @@ namespace NNUE {
namespace Features {
// 玉の位置とBonaPieceから特徴量のインデックスを求める
// Find the index of the feature quantity from the ball position and BonaPiece
template <Side AssociatedKing>
inline IndexType HalfKP<AssociatedKing>::MakeIndex(Square sq_k, BonaPiece p) {
return static_cast<IndexType>(fe_end) * static_cast<IndexType>(sq_k) + p;
}
// 駒の情報を取得する
// Get the piece information
template <Side AssociatedKing>
inline void HalfKP<AssociatedKing>::GetPieces(
const Position& pos, Color perspective,
@ -31,7 +31,7 @@ inline void HalfKP<AssociatedKing>::GetPieces(
*sq_target_k = static_cast<Square>(((*pieces)[target] - f_king) % SQUARE_NB);
}
// 特徴量のうち、値が1であるインデックスのリストを取得する
// Get a list of indices with a value of 1 among the features
template <Side AssociatedKing>
void HalfKP<AssociatedKing>::AppendActiveIndices(
const Position& pos, Color perspective, IndexList* active) {
@ -48,7 +48,7 @@ void HalfKP<AssociatedKing>::AppendActiveIndices(
}
}
// 特徴量のうち、一手前から値が変化したインデックスのリストを取得する
// Get a list of indices whose values have changed from the previous one in the feature quantity
template <Side AssociatedKing>
void HalfKP<AssociatedKing>::AppendChangedIndices(
const Position& pos, Color perspective,

View file

@ -1,4 +1,4 @@
// NNUE評価関数の入力特徴量HalfKPの定義
//Definition of input features HalfKP of NNUE evaluation function
#ifndef _NNUE_FEATURES_HALF_KP_H_
#define _NNUE_FEATURES_HALF_KP_H_
@ -14,39 +14,39 @@ namespace NNUE {
namespace Features {
// 特徴量HalfKP自玉または敵玉の位置と、玉以外の駒の位置の組み合わせ
// Feature HalfKP: Combination of the position of own ball or enemy ball and the position of pieces other than balls
template <Side AssociatedKing>
class HalfKP {
public:
// 特徴量名
// feature quantity name
static constexpr const char* kName =
(AssociatedKing == Side::kFriend) ? "HalfKP(Friend)" : "HalfKP(Enemy)";
// 評価関数ファイルに埋め込むハッシュ値
// Hash value embedded in the evaluation function file
static constexpr std::uint32_t kHashValue =
0x5D69D5B9u ^ (AssociatedKing == Side::kFriend);
// 特徴量の次元数
// number of feature dimensions
static constexpr IndexType kDimensions =
static_cast<IndexType>(SQUARE_NB) * static_cast<IndexType>(fe_end);
// 特徴量のうち、同時に値が1となるインデックスの数の最大値
// The maximum value of the number of indexes whose value is 1 at the same time among the feature values
static constexpr IndexType kMaxActiveDimensions = PIECE_NUMBER_KING;
// 差分計算の代わりに全計算を行うタイミング
// Timing of full calculation instead of difference calculation
static constexpr TriggerEvent kRefreshTrigger =
(AssociatedKing == Side::kFriend) ?
TriggerEvent::kFriendKingMoved : TriggerEvent::kEnemyKingMoved;
// 特徴量のうち、値が1であるインデックスのリストを取得する
// 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 whose values have changed from the previous one in the feature quantity
static void AppendChangedIndices(const Position& pos, Color perspective,
IndexList* removed, IndexList* added);
// 玉の位置とBonaPieceから特徴量のインデックスを求める
// Find the index of the feature quantity from the ball position and BonaPiece
static IndexType MakeIndex(Square sq_k, BonaPiece p);
private:
// 駒の情報を取得する
// Get the piece information
static void GetPieces(const Position& pos, Color perspective,
BonaPiece** pieces, Square* sq_target_k);
};
@ -59,4 +59,4 @@ class HalfKP {
#endif // defined(EVAL_NNUE)
#endif
#endif

View file

@ -1,4 +1,4 @@
// NNUE評価関数の入力特徴量HalfRelativeKPの定義
//Definition of input features HalfRelativeKP of NNUE evaluation function
#if defined(EVAL_NNUE)
@ -11,7 +11,7 @@ namespace NNUE {
namespace Features {
// 玉の位置とBonaPieceから特徴量のインデックスを求める
// Find the index of the feature quantity from the ball position and BonaPiece
template <Side AssociatedKing>
inline IndexType HalfRelativeKP<AssociatedKing>::MakeIndex(
Square sq_k, BonaPiece p) {
@ -24,7 +24,7 @@ inline IndexType HalfRelativeKP<AssociatedKing>::MakeIndex(
return H * W * piece_index + H * relative_file + relative_rank;
}
// 駒の情報を取得する
// Get the piece information
template <Side AssociatedKing>
inline void HalfRelativeKP<AssociatedKing>::GetPieces(
const Position& pos, Color perspective,
@ -38,11 +38,11 @@ inline void HalfRelativeKP<AssociatedKing>::GetPieces(
*sq_target_k = static_cast<Square>(((*pieces)[target] - f_king) % SQUARE_NB);
}
// 特徴量のうち、値が1であるインデックスのリストを取得する
// 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) {
// コンパイラの警告を回避するため、配列サイズが小さい場合は何もしない
// do nothing if array size is small to avoid compiler warning
if (RawFeatures::kMaxActiveDimensions < kMaxActiveDimensions) return;
BonaPiece* pieces;
@ -57,7 +57,7 @@ void HalfRelativeKP<AssociatedKing>::AppendActiveIndices(
}
}
// 特徴量のうち、一手前から値が変化したインデックスのリストを取得する
// 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,

View file

@ -1,4 +1,4 @@
// NNUE評価関数の入力特徴量HalfRelativeKPの定義
//Definition of input features HalfRelativeKP of NNUE evaluation function
#ifndef _NNUE_FEATURES_HALF_RELATIVE_KP_H_
#define _NNUE_FEATURES_HALF_RELATIVE_KP_H_
@ -14,45 +14,45 @@ namespace NNUE {
namespace Features {
// 特徴量HalfRelativeKP自玉または敵玉を基準とした、玉以外の各駒の相対位置
// Feature HalfRelativeKP: Relative position of each piece other than the ball based on own ball or enemy ball
template <Side AssociatedKing>
class HalfRelativeKP {
public:
// 特徴量名
// feature quantity name
static constexpr const char* kName = (AssociatedKing == Side::kFriend) ?
"HalfRelativeKP(Friend)" : "HalfRelativeKP(Enemy)";
// 評価関数ファイルに埋め込むハッシュ値
// Hash value embedded in the evaluation function file
static constexpr std::uint32_t kHashValue =
0xF9180919u ^ (AssociatedKing == Side::kFriend);
// 玉を除いた駒種
// Piece type excluding balls
static constexpr IndexType kNumPieceKinds = (fe_end - fe_hand_end) / SQUARE_NB;
// 玉を中央に置いた仮想的な盤の幅
// width of the virtual board with the ball in the center
static constexpr IndexType kBoardWidth = FILE_NB * 2 - 1;
// 玉を中央に置いた仮想的な盤の高さ
// height of a virtual board with balls in the center
static constexpr IndexType kBoardHeight = RANK_NB * 2 - 1;
// 特徴量の次元数
// number of feature dimensions
static constexpr IndexType kDimensions =
kNumPieceKinds * kBoardHeight * kBoardWidth;
// 特徴量のうち、同時に値が1となるインデックスの数の最大値
// The maximum value of the number of indexes whose value is 1 at the same time among the feature values
static constexpr IndexType kMaxActiveDimensions = PIECE_NUMBER_KING;
// 差分計算の代わりに全計算を行うタイミング
// Timing of full calculation instead of difference calculation
static constexpr TriggerEvent kRefreshTrigger =
(AssociatedKing == Side::kFriend) ?
TriggerEvent::kFriendKingMoved : TriggerEvent::kEnemyKingMoved;
// 特徴量のうち、値が1であるインデックスのリストを取得する
// 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 whose values have changed from the previous one in the feature quantity
static void AppendChangedIndices(const Position& pos, Color perspective,
IndexList* removed, IndexList* added);
// 玉の位置とBonaPieceから特徴量のインデックスを求める
// Find the index of the feature quantity from the ball position and BonaPiece
static IndexType MakeIndex(Square sq_k, BonaPiece p);
private:
// 駒の情報を取得する
// Get the piece information
static void GetPieces(const Position& pos, Color perspective,
BonaPiece** pieces, Square* sq_target_k);
};
@ -65,4 +65,4 @@ class HalfRelativeKP {
#endif // defined(EVAL_NNUE)
#endif
#endif

View file

@ -1,4 +1,4 @@
// 入力特徴量のインデックスリストの定義
// Definition of index list of input features
#ifndef _NNUE_FEATURES_INDEX_LIST_H_
#define _NNUE_FEATURES_INDEX_LIST_H_
@ -14,7 +14,7 @@ namespace NNUE {
namespace Features {
// 特徴量のインデックスリストに使うクラステンプレート
// Class template used for feature index list
template <typename T, std::size_t MaxSize>
class ValueList {
public:
@ -39,7 +39,7 @@ class ValueList {
std::size_t size_ = 0;
};
// 特徴量のインデックスリストの型
//Type of feature index list
class IndexList
: public ValueList<IndexType, RawFeatures::kMaxActiveDimensions> {
};
@ -52,4 +52,4 @@ class IndexList
#endif // defined(EVAL_NNUE)
#endif
#endif

View file

@ -1,4 +1,4 @@
// NNUE評価関数の入力特徴量Kの定義
//Definition of input feature quantity K of NNUE evaluation function
#if defined(EVAL_NNUE)
@ -11,10 +11,10 @@ namespace NNUE {
namespace Features {
// 特徴量のうち、値が1であるインデックスのリストを取得する
// Get a list of indices with a value of 1 among the features
void K::AppendActiveIndices(
const Position& pos, Color perspective, IndexList* active) {
// コンパイラの警告を回避するため、配列サイズが小さい場合は何もしない
// do nothing if array size is small to avoid compiler warning
if (RawFeatures::kMaxActiveDimensions < kMaxActiveDimensions) return;
const BonaPiece* pieces = (perspective == BLACK) ?
@ -27,7 +27,7 @@ void K::AppendActiveIndices(
}
}
// 特徴量のうち、一手前から値が変化したインデックスのリストを取得する
// 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) {

View file

@ -1,4 +1,4 @@
// NNUE評価関数の入力特徴量Kの定義
//Definition of input feature quantity K of NNUE evaluation function
#ifndef _NNUE_FEATURES_K_H_
#define _NNUE_FEATURES_K_H_
@ -14,25 +14,25 @@ namespace NNUE {
namespace Features {
// 特徴量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;
// 特徴量の次元数
// number of feature dimensions
static constexpr IndexType kDimensions = SQUARE_NB * 2;
// 特徴量のうち、同時に値が1となるインデックスの数の最大値
// 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;
// 特徴量のうち、値が1であるインデックスのリストを取得する
// 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 whose values have changed from the previous one in the feature quantity
static void AppendChangedIndices(const Position& pos, Color perspective,
IndexList* removed, IndexList* added);
};
@ -45,4 +45,4 @@ class K {
#endif // defined(EVAL_NNUE)
#endif
#endif

View file

@ -1,4 +1,4 @@
// NNUE評価関数の入力特徴量Pの定義
//Definition of input feature P of NNUE evaluation function
#if defined(EVAL_NNUE)
@ -11,10 +11,10 @@ namespace NNUE {
namespace Features {
// 特徴量のうち、値が1であるインデックスのリストを取得する
// Get a list of indices with a value of 1 among the features
void P::AppendActiveIndices(
const Position& pos, Color perspective, IndexList* active) {
// コンパイラの警告を回避するため、配列サイズが小さい場合は何もしない
// do nothing if array size is small to avoid compiler warning
if (RawFeatures::kMaxActiveDimensions < kMaxActiveDimensions) return;
const BonaPiece* pieces = (perspective == BLACK) ?
@ -27,7 +27,7 @@ void P::AppendActiveIndices(
}
}
// 特徴量のうち、一手前から値が変化したインデックスのリストを取得する
// 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) {

View file

@ -1,4 +1,4 @@
// NNUE評価関数の入力特徴量Pの定義
//Definition of input feature P of NNUE evaluation function
#ifndef _NNUE_FEATURES_P_H_
#define _NNUE_FEATURES_P_H_
@ -14,25 +14,25 @@ namespace NNUE {
namespace Features {
// 特徴量P玉以外の駒のBonaPiece
// Feature P: BonaPiece 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;
// 特徴量の次元数
// number of feature dimensions
static constexpr IndexType kDimensions = fe_end;
// 特徴量のうち、同時に値が1となるインデックスの数の最大値
// The maximum value of the number of indexes whose value is 1 at the same time among the feature values
static constexpr IndexType kMaxActiveDimensions = PIECE_NUMBER_KING;
// 差分計算の代わりに全計算を行うタイミング
// Timing of full calculation instead of difference calculation
static constexpr TriggerEvent kRefreshTrigger = TriggerEvent::kNone;
// 特徴量のうち、値が1であるインデックスのリストを取得する
// 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 whose values have changed from the previous one in the feature quantity
static void AppendChangedIndices(const Position& pos, Color perspective,
IndexList* removed, IndexList* added);
};
@ -45,4 +45,4 @@ class P {
#endif // defined(EVAL_NNUE)
#endif
#endif

View file

@ -1,4 +1,4 @@
// NNUE評価関数の層AffineTransformの定義
// Definition of layer AffineTransform of NNUE evaluation function
#ifndef _NNUE_LAYERS_AFFINE_TRANSFORM_H_
#define _NNUE_LAYERS_AFFINE_TRANSFORM_H_
@ -13,31 +13,31 @@ namespace NNUE {
namespace Layers {
// アフィン変換層
// affine transformation layer
template <typename PreviousLayer, IndexType OutputDimensions>
class AffineTransform {
public:
// 入出力の型
// Input/output type
using InputType = typename PreviousLayer::OutputType;
using OutputType = std::int32_t;
static_assert(std::is_same<InputType, std::uint8_t>::value, "");
// 入出力の次元数
// number of input/output dimensions
static constexpr IndexType kInputDimensions =
PreviousLayer::kOutputDimensions;
static constexpr IndexType kOutputDimensions = OutputDimensions;
static constexpr IndexType kPaddedInputDimensions =
CeilToMultiple<IndexType>(kInputDimensions, kMaxSimdWidth);
// この層で使用する順伝播用バッファのサイズ
// 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 =
PreviousLayer::kBufferSize + kSelfBufferSize;
// 評価関数ファイルに埋め込むハッシュ値
// Hash value embedded in the evaluation function file
static constexpr std::uint32_t GetHashValue() {
std::uint32_t hash_value = 0xCC03DAE4u;
hash_value += kOutputDimensions;
@ -46,7 +46,7 @@ class AffineTransform {
return hash_value;
}
// 入力層からこの層までの構造を表す文字列
// A string that represents the structure from the input layer to this layer
static std::string GetStructureString() {
return "AffineTransform[" +
std::to_string(kOutputDimensions) + "<-" +
@ -54,7 +54,7 @@ class AffineTransform {
PreviousLayer::GetStructureString() + ")";
}
// パラメータを読み込む
// read parameters
bool ReadParameters(std::istream& stream) {
if (!previous_layer_.ReadParameters(stream)) return false;
stream.read(reinterpret_cast<char*>(biases_),
@ -65,7 +65,7 @@ class AffineTransform {
return !stream.fail();
}
// パラメータを書き込む
// write parameters
bool WriteParameters(std::ostream& stream) const {
if (!previous_layer_.WriteParameters(stream)) return false;
stream.write(reinterpret_cast<const char*>(biases_),
@ -76,7 +76,7 @@ class AffineTransform {
return !stream.fail();
}
// 順伝播
// forward propagation
const OutputType* Propagate(
const TransformedFeatureType* transformed_features, char* buffer) const {
const auto input = previous_layer_.Propagate(
@ -151,17 +151,17 @@ class AffineTransform {
}
private:
// パラメータの型
// parameter type
using BiasType = OutputType;
using WeightType = std::int8_t;
// 学習用クラスをfriendにする
// Make the learning class a friend
friend class Trainer<AffineTransform>;
// この層の直前の層
// the layer immediately before this layer
PreviousLayer previous_layer_;
// パラメータ
// parameter
alignas(kCacheLineSize) BiasType biases_[kOutputDimensions];
alignas(kCacheLineSize)
WeightType weights_[kOutputDimensions * kPaddedInputDimensions];
@ -175,4 +175,4 @@ class AffineTransform {
#endif // defined(EVAL_NNUE)
#endif
#endif

View file

@ -1,4 +1,4 @@
// NNUE評価関数の層ClippedReLUの定義
// Definition of layer ClippedReLU of NNUE evaluation function
#ifndef _NNUE_LAYERS_CLIPPED_RELU_H_
#define _NNUE_LAYERS_CLIPPED_RELU_H_
@ -17,49 +17,49 @@ namespace Layers {
template <typename PreviousLayer>
class ClippedReLU {
public:
// 入出力の型
// Input/output type
using InputType = typename PreviousLayer::OutputType;
using OutputType = std::uint8_t;
static_assert(std::is_same<InputType, std::int32_t>::value, "");
// 入出力の次元数
// number of input/output dimensions
static constexpr IndexType kInputDimensions =
PreviousLayer::kOutputDimensions;
static constexpr IndexType kOutputDimensions = 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 =
PreviousLayer::kBufferSize + kSelfBufferSize;
// 評価関数ファイルに埋め込むハッシュ値
// Hash value embedded in the evaluation function file
static constexpr std::uint32_t GetHashValue() {
std::uint32_t hash_value = 0x538D24C7u;
hash_value += PreviousLayer::GetHashValue();
return hash_value;
}
// 入力層からこの層までの構造を表す文字列
// A string that represents the structure from the input layer to this layer
static std::string GetStructureString() {
return "ClippedReLU[" +
std::to_string(kOutputDimensions) + "](" +
PreviousLayer::GetStructureString() + ")";
}
// パラメータを読み込む
// read parameters
bool ReadParameters(std::istream& stream) {
return previous_layer_.ReadParameters(stream);
}
// パラメータを書き込む
// write parameters
bool WriteParameters(std::ostream& stream) const {
return previous_layer_.WriteParameters(stream);
}
// 順伝播
// forward propagation
const OutputType* Propagate(
const TransformedFeatureType* transformed_features, char* buffer) const {
const auto input = previous_layer_.Propagate(
@ -150,10 +150,10 @@ class ClippedReLU {
}
private:
// 学習用クラスをfriendにする
// Make the learning class a friend
friend class Trainer<ClippedReLU>;
// この層の直前の層
// the layer immediately before this layer
PreviousLayer previous_layer_;
};
@ -165,4 +165,4 @@ class ClippedReLU {
#endif // defined(EVAL_NNUE)
#endif
#endif

View file

@ -1,4 +1,4 @@
// NNUE評価関数の層InputSliceの定義
// NNUE evaluation function layer InputSlice definition
#ifndef _NNUE_LAYERS_INPUT_SLICE_H_
#define _NNUE_LAYERS_INPUT_SLICE_H_
@ -13,47 +13,47 @@ namespace NNUE {
namespace Layers {
// 入力層
// input layer
template <IndexType OutputDimensions, IndexType Offset = 0>
class InputSlice {
public:
// アライメントを維持する必要がある
// need to maintain alignment
static_assert(Offset % kMaxSimdWidth == 0, "");
// 出力の型
// output type
using OutputType = TransformedFeatureType;
// 出力の次元数
// output dimensionality
static constexpr IndexType kOutputDimensions = OutputDimensions;
// 入力層からこの層までで使用する順伝播用バッファのサイズ
// Size of the forward propagation buffer used from the input layer to this layer
static constexpr std::size_t kBufferSize = 0;
// 評価関数ファイルに埋め込むハッシュ値
// Hash value embedded in the evaluation function file
static constexpr std::uint32_t GetHashValue() {
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() {
return "InputSlice[" + std::to_string(kOutputDimensions) + "(" +
std::to_string(Offset) + ":" +
std::to_string(Offset + kOutputDimensions) + ")]";
}
// パラメータを読み込む
// read parameters
bool ReadParameters(std::istream& /*stream*/) {
return true;
}
// パラメータを書き込む
// write parameters
bool WriteParameters(std::ostream& /*stream*/) const {
return true;
}
// 順伝播
// forward propagation
const OutputType* Propagate(
const TransformedFeatureType* transformed_features,
char* /*buffer*/) const {
@ -71,4 +71,4 @@ class InputSlice {
#endif // defined(EVAL_NNUE)
#endif
#endif

View file

@ -1,4 +1,4 @@
// NNUE評価関数の層Sumの定義
// Definition of layer Sum of NNUE evaluation function
#ifndef _NNUE_LAYERS_SUM_H_
#define _NNUE_LAYERS_SUM_H_
@ -13,7 +13,7 @@ namespace NNUE {
namespace Layers {
// 複数の層の出力の和を取る層
// Layer that sums the output of multiple layers
template <typename FirstPreviousLayer, typename... RemainingPreviousLayers>
class Sum : public Sum<RemainingPreviousLayers...> {
private:
@ -21,25 +21,25 @@ class Sum : public Sum<RemainingPreviousLayers...> {
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 , "");
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;
@ -49,67 +49,67 @@ class Sum : public Sum<RemainingPreviousLayers...> {
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);
}
// パラメータを書き込む
// write parameters
bool WriteParameters(std::ostream& stream) const {
if (!Tail::WriteParameters(stream)) return false;
return previous_layer_.WriteParameters(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) {
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();
}
// 学習用クラスをfriendにする
// Make the learning class a friend
friend class Trainer<Sum>;
// この層の直前の層
// the layer immediately before this layer
FirstPreviousLayer previous_layer_;
};
// 複数の層の出力の和を取る層テンプレート引数が1つの場合
// 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;
@ -117,38 +117,38 @@ class Sum<PreviousLayer> {
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);
}
// パラメータを書き込む
// write parameters
bool WriteParameters(std::ostream& stream) const {
return previous_layer_.WriteParameters(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();
}
// 学習用クラスをfriendにする
// Make the learning class a friend
friend class Trainer<Sum>;
// この層の直前の層
// the layer immediately before this layer
PreviousLayer previous_layer_;
};
@ -160,4 +160,4 @@ class Sum<PreviousLayer> {
#endif // defined(EVAL_NNUE)
#endif
#endif

View file

@ -1,4 +1,4 @@
// NNUE評価関数の差分計算用のクラス
// Class for difference calculation of NNUE evaluation function
#ifndef _NNUE_ACCUMULATOR_H_
#define _NNUE_ACCUMULATOR_H_
@ -11,8 +11,8 @@ namespace Eval {
namespace NNUE {
// 入力特徴量をアフィン変換した結果を保持するクラス
// 最終的な出力である評価値も一緒に持たせておく
// 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 {
std::int16_t
accumulation[2][kRefreshTriggers.size()][kTransformedFeatureDimensions];
@ -27,4 +27,4 @@ struct alignas(32) Accumulator {
#endif // defined(EVAL_NNUE)
#endif
#endif

View file

@ -1,11 +1,11 @@
// NNUE評価関数で用いる入力特徴量とネットワーク構造
// Input features and network structure used in NNUE evaluation function
#ifndef _NNUE_ARCHITECTURE_H_
#define _NNUE_ARCHITECTURE_H_
#if defined(EVAL_NNUE)
// 入力特徴量とネットワーク構造が定義されたヘッダをincludeする
// include a header that defines the input features and network structure
//#include "architectures/k-p_256x2-32-32.h"
//#include "architectures/k-p-cr_256x2-32-32.h"
//#include "architectures/k-p-cr-ep_256x2-32-32.h"
@ -20,7 +20,7 @@ static_assert(kTransformedFeatureDimensions % kMaxSimdWidth == 0, "");
static_assert(Network::kOutputDimensions == 1, "");
static_assert(std::is_same<Network::OutputType, std::int32_t>::value, "");
// 差分計算の代わりに全計算を行うタイミングのリスト
// List of timings to perform all calculations instead of difference calculation
constexpr auto kRefreshTriggers = RawFeatures::kRefreshTriggers;
} // namespace NNUE
@ -29,4 +29,4 @@ constexpr auto kRefreshTriggers = RawFeatures::kRefreshTriggers;
#endif // defined(EVAL_NNUE)
#endif
#endif

View file

@ -1,4 +1,4 @@
// NNUE評価関数で用いる定数など
// Constants used in NNUE evaluation function
#ifndef _NNUE_COMMON_H_
#define _NNUE_COMMON_H_
@ -17,17 +17,17 @@ namespace Eval {
namespace NNUE {
// 評価関数ファイルのバージョンを表す定数
// A constant that represents the version of the evaluation function file
constexpr std::uint32_t kVersion = 0x7AF32F16u;
// 評価値の計算で利用する定数
// Constant used in evaluation value calculation
constexpr int FV_SCALE = 16;
constexpr int kWeightScaleBits = 6;
// キャッシュラインのサイズ(バイト単位)
// Size of cache line (in bytes)
constexpr std::size_t kCacheLineSize = 64;
// SIMD幅(バイト単位)
// SIMD width (in bytes)
#if defined(USE_AVX2)
constexpr std::size_t kSimdWidth = 32;
#elif defined(USE_SSE2)
@ -37,17 +37,17 @@ constexpr std::size_t kSimdWidth = 16;
#endif
constexpr std::size_t kMaxSimdWidth = 32;
// 変換後の入力特徴量の型
// Type of input feature after conversion
using TransformedFeatureType = std::uint8_t;
// インデックスの型
// index type
using IndexType = std::uint32_t;
// 学習用クラステンプレートの前方宣言
// Forward declaration of learning class template
template <typename Layer>
class Trainer;
// n以上で最小のbaseの倍数を求める
// find the smallest multiple of n and above
template <typename IntType>
constexpr IntType CeilToMultiple(IntType n, IntType base) {
return (n + base - 1) / base * base;

View file

@ -1,4 +1,4 @@
// NNUE評価関数の入力特徴量の変換を行うクラス
// A class that converts the input features of the NNUE evaluation function
#ifndef _NNUE_FEATURE_TRANSFORMER_H_
#define _NNUE_FEATURE_TRANSFORMER_H_
@ -15,37 +15,37 @@ namespace Eval {
namespace NNUE {
// 入力特徴量変換器
// Input feature converter
class FeatureTransformer {
private:
// 片側分の出力の次元数
// number of output dimensions for one side
static constexpr IndexType kHalfDimensions = kTransformedFeatureDimensions;
public:
// 出力の型
// output type
using OutputType = TransformedFeatureType;
// 入出力の次元数
// number of input/output dimensions
static constexpr IndexType kInputDimensions = RawFeatures::kDimensions;
static constexpr IndexType kOutputDimensions = kHalfDimensions * 2;
// 順伝播用バッファのサイズ
// size of forward propagation buffer
static constexpr std::size_t kBufferSize =
kOutputDimensions * sizeof(OutputType);
// 評価関数ファイルに埋め込むハッシュ値
// Hash value embedded in the evaluation function file
static constexpr std::uint32_t GetHashValue() {
return RawFeatures::kHashValue ^ kOutputDimensions;
}
// 構造を表す文字列
// a string representing the structure
static std::string GetStructureString() {
return RawFeatures::GetName() + "[" +
std::to_string(kInputDimensions) + "->" +
std::to_string(kHalfDimensions) + "x2]";
}
// パラメータを読み込む
// read parameters
bool ReadParameters(std::istream& stream) {
stream.read(reinterpret_cast<char*>(biases_),
kHalfDimensions * sizeof(BiasType));
@ -54,7 +54,7 @@ class FeatureTransformer {
return !stream.fail();
}
// パラメータを書き込む
// write parameters
bool WriteParameters(std::ostream& stream) const {
stream.write(reinterpret_cast<const char*>(biases_),
kHalfDimensions * sizeof(BiasType));
@ -63,7 +63,7 @@ class FeatureTransformer {
return !stream.fail();
}
// 可能なら差分計算を進める
// proceed with the difference calculation if possible
bool UpdateAccumulatorIfPossible(const Position& pos) const {
const auto now = pos.state();
if (now->accumulator.computed_accumulation) {
@ -77,7 +77,7 @@ class FeatureTransformer {
return false;
}
// 入力特徴量を変換する
// convert input features
void Transform(const Position& pos, OutputType* output, bool refresh) const {
if (refresh || !UpdateAccumulatorIfPossible(pos)) {
RefreshAccumulator(pos);
@ -174,7 +174,7 @@ class FeatureTransformer {
}
private:
// 差分計算を用いずに累積値を計算する
// Calculate cumulative value without using difference calculation
void RefreshAccumulator(const Position& pos) const {
auto& accumulator = pos.state()->accumulator;
for (IndexType i = 0; i < kRefreshTriggers.size(); ++i) {
@ -232,7 +232,7 @@ class FeatureTransformer {
accumulator.computed_score = false;
}
// 差分計算を用いて累積値を計算する
// Calculate cumulative value using difference calculation
void UpdateAccumulator(const Position& pos) const {
const auto prev_accumulator = pos.state()->previous->accumulator;
auto& accumulator = pos.state()->accumulator;
@ -263,7 +263,7 @@ class FeatureTransformer {
std::memset(accumulator.accumulation[perspective][i], 0,
kHalfDimensions * sizeof(BiasType));
}
} else { // 1から0に変化した特徴量に関する差分計算
} else {// Difference calculation for the feature amount changed from 1 to 0
std::memcpy(accumulator.accumulation[perspective][i],
prev_accumulator.accumulation[perspective][i],
kHalfDimensions * sizeof(BiasType));
@ -292,7 +292,7 @@ class FeatureTransformer {
#endif
}
}
{ // 0から1に変化した特徴量に関する差分計算
{// Difference calculation for features that changed from 0 to 1
for (const auto index : added_indices[perspective]) {
const IndexType offset = kHalfDimensions * index;
#if defined(USE_AVX2)
@ -325,14 +325,14 @@ class FeatureTransformer {
accumulator.computed_score = false;
}
// パラメータの型
// parameter type
using BiasType = std::int16_t;
using WeightType = std::int16_t;
// 学習用クラスをfriendにする
// Make the learning class a friend
friend class Trainer<FeatureTransformer>;
// パラメータ
// parameter
alignas(kCacheLineSize) BiasType biases_[kHalfDimensions];
alignas(kCacheLineSize)
WeightType weights_[kHalfDimensions * kInputDimensions];
@ -344,4 +344,4 @@ class FeatureTransformer {
#endif // defined(EVAL_NNUE)
#endif
#endif

View file

@ -1,4 +1,4 @@
// NNUE評価関数に関するUSI拡張コマンド
// USI extended command for NNUE evaluation function
#if defined(ENABLE_TEST_CMD) && defined(EVAL_NNUE)
@ -19,15 +19,15 @@ namespace NNUE {
namespace {
// 主に差分計算に関するRawFeaturesのテスト
// Testing RawFeatures mainly for difference calculation
void TestFeatures(Position& pos) {
const std::uint64_t num_games = 1000;
StateInfo si;
pos.set(StartFEN, false, &si, Threads.main());
const int MAX_PLY = 256; // 256手までテスト
const int MAX_PLY = 256; // test up to 256 hands
StateInfo state[MAX_PLY]; // StateInfoを最大手数分だけ
int ply; // 初期局面からの手数
StateInfo state[MAX_PLY]; // StateInfo only for the maximum number of steps
int ply; // Trouble from the initial phase
PRNG prng(20171128);
@ -96,13 +96,13 @@ void TestFeatures(Position& pos) {
for (std::uint64_t i = 0; i < num_games; ++i) {
auto index_sets = make_index_sets(pos);
for (ply = 0; ply < MAX_PLY; ++ply) {
MoveList<LEGAL> mg(pos); // 全合法手の生成
MoveList<LEGAL> mg(pos); // Generate all legal hands
// 合法な指し手がなかった == 詰み
// There was no legal move == Clog
if (mg.size() == 0)
break;
// 生成された指し手のなかからランダムに選び、その指し手で局面を進める。
// Randomly choose from the generated moves and advance the phase with the moves.
Move m = mg.begin()[prng.rand(mg.size())];
pos.do_move(m, state[ply]);
@ -113,7 +113,7 @@ void TestFeatures(Position& pos) {
pos.set(StartFEN, false, &si, Threads.main());
// 100回に1回ごとに'.'を出力(進んでいることがわかるように)
// Output'.' every 100 times (so you can see that it's progressing)
if ((i % 100) == 0)
std::cout << "." << std::flush;
}
@ -141,7 +141,7 @@ void TestFeatures(Position& pos) {
<< ") features" << std::endl;
}
// 評価関数の構造を表す文字列を出力する
// Output a string that represents the structure of the evaluation function
void PrintInfo(std::istream& stream) {
std::cout << "network architecture: " << GetArchitectureString() << std::endl;
@ -178,7 +178,7 @@ void PrintInfo(std::istream& stream) {
} // namespace
// NNUE評価関数に関するUSI拡張コマンド
// USI extended command for NNUE evaluation function
void TestCommand(Position& pos, std::istream& stream) {
std::string sub_command;
stream >> sub_command;

View file

@ -1,4 +1,4 @@
// NNUE評価関数に関するUSI拡張コマンドのインターフェイス
// USI extended command interface for NNUE evaluation function
#ifndef _NNUE_TEST_COMMAND_H_
#define _NNUE_TEST_COMMAND_H_
@ -9,7 +9,7 @@ namespace Eval {
namespace NNUE {
// NNUE評価関数に関するUSI拡張コマンド
// USI extended command for NNUE evaluation function
void TestCommand(Position& pos, std::istream& stream);
} // namespace NNUE

View file

@ -1,4 +1,4 @@
// NNUE評価関数の特徴量変換クラステンプレート
// NNUE evaluation function feature conversion class template
#ifndef _NNUE_TRAINER_FEATURES_FACTORIZER_H_
#define _NNUE_TRAINER_FEATURES_FACTORIZER_H_
@ -14,31 +14,31 @@ namespace NNUE {
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 <typename FeatureType>
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<TrainingFeature>* training_features) {
assert(base_index < FeatureType::kDimensions);
assert(base_index <FeatureType::kDimensions);
training_features->emplace_back(base_index);
}
};
// 学習用特徴量の情報
// Learning feature information
struct FeatureProperties {
bool active;
IndexType dimensions;
};
// 元の入力特徴量を学習用特徴量に追加する
// Add the original input features to the learning features
template <typename FeatureType>
IndexType AppendBaseFeature(
FeatureProperties properties, IndexType base_index,
@ -49,7 +49,7 @@ IndexType AppendBaseFeature(
return properties.dimensions;
}
// 学習率のスケールが0でなければ他の種類の学習用特徴量を引き継ぐ
// If the learning rate scale is not 0, inherit other types of learning features
template <typename FeatureType>
IndexType InheritFeaturesIfRequired(
IndexType index_offset, FeatureProperties properties, IndexType base_index,
@ -70,8 +70,8 @@ IndexType InheritFeaturesIfRequired(
return properties.dimensions;
}
// 学習用特徴量を追加せず、必要に応じてインデックスの差分を返す
// 対応する特徴量がない場合にInheritFeaturesIfRequired()の代わりに呼ぶ
// 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;
@ -79,7 +79,7 @@ IndexType SkipFeatures(FeatureProperties properties) {
return properties.dimensions;
}
// 学習用特徴量の次元数を取得する
// Get the dimensionality of the learning feature
template <std::size_t N>
constexpr IndexType GetActiveDimensions(
const FeatureProperties (&properties)[N]) {
@ -93,7 +93,7 @@ constexpr IndexType GetActiveDimensions(
return dimensions;
}
// 配列の要素数を取得する
// get the number of elements in the array
template <typename T, std::size_t N>
constexpr std::size_t GetArrayLength(const T (&/*array*/)[N]) {
return N;
@ -107,4 +107,4 @@ constexpr std::size_t GetArrayLength(const T (&/*array*/)[N]) {
#endif // defined(EVAL_NNUE)
#endif
#endif

View file

@ -1,4 +1,4 @@
// NNUE評価関数の特徴量変換クラステンプレートのFeatureSet用特殊化
// Specialization for feature set of feature conversion class template of NNUE evaluation function
#ifndef _NNUE_TRAINER_FEATURES_FACTORIZER_FEATURE_SET_H_
#define _NNUE_TRAINER_FEATURES_FACTORIZER_FEATURE_SET_H_
@ -14,8 +14,8 @@ namespace NNUE {
namespace Features {
// 入力特徴量を学習用特徴量に変換するクラステンプレート
// FeatureSet用特殊化
// Class template that converts input features into learning features
// Specialization for FeatureSet
template <typename FirstFeatureType, typename... RemainingFeatureTypes>
class Factorizer<FeatureSet<FirstFeatureType, RemainingFeatureTypes...>> {
private:
@ -23,16 +23,16 @@ class Factorizer<FeatureSet<FirstFeatureType, RemainingFeatureTypes...>> {
using Tail = Factorizer<FeatureSet<RemainingFeatureTypes...>>;
public:
// 元の入力特徴量の次元数
// number of dimensions of original input features
static constexpr IndexType kBaseDimensions =
FeatureSet<FirstFeatureType, RemainingFeatureTypes...>::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<TrainingFeature>* training_features,
IndexType base_dimensions = kBaseDimensions) {
@ -62,20 +62,20 @@ class Factorizer<FeatureSet<FirstFeatureType, RemainingFeatureTypes...>> {
}
};
// 入力特徴量を学習用特徴量に変換するクラステンプレート
// FeatureSetのテンプレート引数が1つの場合の特殊化
// Class template that converts input features into learning features
// Specialization when FeatureSet has one template argument
template <typename FeatureType>
class Factorizer<FeatureSet<FeatureType>> {
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<FeatureType>::GetDimensions();
}
// 学習用特徴量のインデックスと学習率のスケールを取得する
// Get index of learning feature and scale of learning rate
static void AppendTrainingFeatures(
IndexType base_index, std::vector<TrainingFeature>* training_features,
IndexType base_dimensions = kBaseDimensions) {
@ -101,4 +101,4 @@ public:
#endif // defined(EVAL_NNUE)
#endif
#endif

View file

@ -1,4 +1,4 @@
// NNUE評価関数の特徴量変換クラステンプレートのHalfKP用特殊化
// Specialization of NNUE evaluation function feature conversion class template for HalfKP
#ifndef _NNUE_TRAINER_FEATURES_FACTORIZER_HALF_KP_H_
#define _NNUE_TRAINER_FEATURES_FACTORIZER_HALF_KP_H_
@ -16,18 +16,18 @@ namespace NNUE {
namespace Features {
// 入力特徴量を学習用特徴量に変換するクラステンプレート
// HalfKP用特殊化
// Class template that converts input features into learning features
// Specialization for HalfKP
template <Side AssociatedKing>
class Factorizer<HalfKP<AssociatedKing>> {
private:
using FeatureType = HalfKP<AssociatedKing>;
// 特徴量のうち、同時に値が1となるインデックスの数の最大値
// 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,
@ -36,7 +36,7 @@ class Factorizer<HalfKP<AssociatedKing>> {
kNumTrainingFeatureTypes,
};
// 学習用特徴量の情報
// Learning feature information
static constexpr FeatureProperties kProperties[] = {
// kFeaturesHalfKP
{true, FeatureType::kDimensions},
@ -50,12 +50,12 @@ class Factorizer<HalfKP<AssociatedKing>> {
static_assert(GetArrayLength(kProperties) == kNumTrainingFeatureTypes, "");
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<TrainingFeature>* training_features) {
// kFeaturesHalfKP
@ -100,4 +100,4 @@ constexpr FeatureProperties Factorizer<HalfKP<AssociatedKing>>::kProperties[];
#endif // defined(EVAL_NNUE)
#endif
#endif

View file

@ -1,4 +1,4 @@
// NNUE評価関数の学習用クラステンプレートの共通ヘッダ
// Common header of class template for learning NNUE evaluation function
#ifndef _NNUE_TRAINER_H_
#define _NNUE_TRAINER_H_
@ -18,10 +18,10 @@ namespace Eval {
namespace NNUE {
// 評価値と勝率の関係式で用いるPonanza定数
// Ponanza constant used in the relation between evaluation value and winning percentage
constexpr double kPonanzaConstant = 600.0;
// 学習用特徴量のインデックス1つを表すクラス
// Class that represents one index of learning feature
class TrainingFeature {
using StorageType = std::uint32_t;
static_assert(std::is_unsigned<StorageType>::value, "");
@ -60,7 +60,7 @@ class TrainingFeature {
StorageType index_and_count_;
};
// 学習データ1サンプルを表す構造体
// Structure that represents one sample of training data
struct Example {
std::vector<TrainingFeature> training_features[2];
Learner::PackedSfenValue psv;
@ -68,9 +68,9 @@ struct Example {
double weight;
};
// ハイパーパラメータの設定などに使用するメッセージ
// Message used for setting hyperparameters
struct Message {
Message(const std::string& name, const std::string& value = "") :
Message(const std::string& name, const std::string& value = ""):
name(name), value(value), num_peekers(0), num_receivers(0) {}
const std::string name;
const std::string value;
@ -78,7 +78,7 @@ struct Message {
std::uint32_t num_receivers;
};
// メッセージを受理するかどうかを判定する
// determine whether to accept the message
bool ReceiveMessage(const std::string& name, Message* message) {
const auto subscript = "[" + std::to_string(message->num_peekers) + "]";
if (message->name.substr(0, name.size() + 1) == name + "[") {
@ -91,7 +91,7 @@ bool ReceiveMessage(const std::string& name, Message* message) {
return false;
}
// 文字列を分割する
// split the string
std::vector<std::string> Split(const std::string& input, char delimiter) {
std::istringstream stream(input);
std::string field;
@ -102,13 +102,13 @@ std::vector<std::string> Split(const std::string& input, char delimiter) {
return fields;
}
// 浮動小数点数を整数に丸める
// round a floating point number to an integer
template <typename IntType>
IntType Round(double value) {
return static_cast<IntType>(std::floor(value + 0.5));
}
// アライメント付きmake_shared
// make_shared with alignment
template <typename T, typename... ArgumentTypes>
std::shared_ptr<T> MakeAlignedSharedPtr(ArgumentTypes&&... arguments) {
const auto ptr = new(aligned_malloc(sizeof(T), alignof(T)))
@ -122,4 +122,4 @@ std::shared_ptr<T> MakeAlignedSharedPtr(ArgumentTypes&&... arguments) {
#endif // defined(EVAL_LEARN) && defined(EVAL_NNUE)
#endif
#endif

View file

@ -1,4 +1,4 @@
// NNUE評価関数の学習クラステンプレートのAffineTransform用特殊化
// Specialization of NNUE evaluation function learning class template for AffineTransform
#ifndef _NNUE_TRAINER_AFFINE_TRANSFORM_H_
#define _NNUE_TRAINER_AFFINE_TRANSFORM_H_
@ -15,22 +15,22 @@ namespace Eval {
namespace NNUE {
// 学習:アフィン変換層
// Learning: Affine transformation layer
template <typename PreviousLayer, IndexType OutputDimensions>
class Trainer<Layers::AffineTransform<PreviousLayer, OutputDimensions>> {
private:
// 学習対象の層の型
// Type of layer to learn
using LayerType = Layers::AffineTransform<PreviousLayer, OutputDimensions>;
public:
// ファクトリ関数
// factory function
static std::shared_ptr<Trainer> Create(
LayerType* target_layer, FeatureTransformer* feature_transformer) {
return std::shared_ptr<Trainer>(
new Trainer(target_layer, feature_transformer));
}
// ハイパーパラメータなどのオプションを設定する
// Set options such as hyperparameters
void SendMessage(Message* message) {
previous_layer_trainer_->SendMessage(message);
if (ReceiveMessage("momentum", message)) {
@ -48,19 +48,19 @@ class Trainer<Layers::AffineTransform<PreviousLayer, OutputDimensions>> {
}
}
// パラメータを乱数で初期化する
// Initialize the parameters with random numbers
template <typename RNG>
void Initialize(RNG& rng) {
previous_layer_trainer_->Initialize(rng);
if (kIsOutputLayer) {
// 出力層は0で初期化する
// Initialize output layer with 0
std::fill(std::begin(biases_), std::end(biases_),
static_cast<LearnFloatType>(0.0));
std::fill(std::begin(weights_), std::end(weights_),
static_cast<LearnFloatType>(0.0));
} else {
// 入力の分布が各ユニット平均0.5、等分散であることを仮定し、
// 出力の分布が各ユニット平均0.5、入力と同じ等分散になるように初期化する
// Assuming that the input distribution is unit-mean 0.5, equal variance,
// Initialize the output distribution so that each unit has a mean of 0.5 and the same variance as the input
const double kSigma = 1.0 / std::sqrt(kInputDimensions);
auto distribution = std::normal_distribution<double>(0.0, kSigma);
for (IndexType i = 0; i < kOutputDimensions; ++i) {
@ -76,7 +76,7 @@ class Trainer<Layers::AffineTransform<PreviousLayer, OutputDimensions>> {
QuantizeParameters();
}
// 順伝播
// forward propagation
const LearnFloatType* Propagate(const std::vector<Example>& batch) {
if (output_.size() < kOutputDimensions * batch.size()) {
output_.resize(kOutputDimensions * batch.size());
@ -111,7 +111,7 @@ class Trainer<Layers::AffineTransform<PreviousLayer, OutputDimensions>> {
return output_.data();
}
// 逆伝播
// backpropagation
void Backpropagate(const LearnFloatType* gradients,
LearnFloatType learning_rate) {
const LearnFloatType local_learning_rate =
@ -185,7 +185,7 @@ class Trainer<Layers::AffineTransform<PreviousLayer, OutputDimensions>> {
}
private:
// コンストラクタ
// constructor
Trainer(LayerType* target_layer, FeatureTransformer* feature_transformer) :
batch_size_(0),
batch_input_(nullptr),
@ -201,7 +201,7 @@ class Trainer<Layers::AffineTransform<PreviousLayer, OutputDimensions>> {
DequantizeParameters();
}
// 重みの飽和とパラメータの整数化
// Weight saturation and parameterization
void QuantizeParameters() {
for (IndexType i = 0; i < kOutputDimensions * kInputDimensions; ++i) {
weights_[i] = std::max(-kMaxWeightMagnitude,
@ -222,7 +222,7 @@ class Trainer<Layers::AffineTransform<PreviousLayer, OutputDimensions>> {
}
}
// 整数化されたパラメータの読み込み
// read parameterized integer
void DequantizeParameters() {
for (IndexType i = 0; i < kOutputDimensions; ++i) {
biases_[i] = static_cast<LearnFloatType>(
@ -242,14 +242,14 @@ class Trainer<Layers::AffineTransform<PreviousLayer, OutputDimensions>> {
static_cast<LearnFloatType>(0.0));
}
// 入出力の次元数
// number of input/output dimensions
static constexpr IndexType kInputDimensions = LayerType::kInputDimensions;
static constexpr IndexType kOutputDimensions = LayerType::kOutputDimensions;
// 出力の次元数が1なら出力層
// If the output dimensionality is 1, the output layer
static constexpr bool kIsOutputLayer = kOutputDimensions == 1;
// パラメータの整数化で用いる係数
// Coefficient used for parameterization
static constexpr LearnFloatType kActivationScale =
std::numeric_limits<std::int8_t>::max();
static constexpr LearnFloatType kBiasScale = kIsOutputLayer ?
@ -257,37 +257,37 @@ class Trainer<Layers::AffineTransform<PreviousLayer, OutputDimensions>> {
((1 << kWeightScaleBits) * kActivationScale);
static constexpr LearnFloatType kWeightScale = kBiasScale / kActivationScale;
// パラメータの整数化でオーバーフローさせないために用いる重みの絶対値の上限
// Upper limit of absolute value of weight used to prevent overflow when parameterizing integers
static constexpr LearnFloatType kMaxWeightMagnitude =
std::numeric_limits<typename LayerType::WeightType>::max() / kWeightScale;
// ミニバッチのサンプル数
// number of samples in mini-batch
IndexType batch_size_;
// ミニバッチの入力
// Input mini batch
const LearnFloatType* batch_input_;
// 直前の層のTrainer
// Trainer of the previous layer
const std::shared_ptr<Trainer<PreviousLayer>> previous_layer_trainer_;
// 学習対象の層
// layer to learn
LayerType* const target_layer_;
// パラメータ
// parameter
LearnFloatType biases_[kOutputDimensions];
LearnFloatType weights_[kOutputDimensions * kInputDimensions];
// パラメータの更新で用いるバッファ
// Buffer used for updating parameters
LearnFloatType biases_diff_[kOutputDimensions];
LearnFloatType weights_diff_[kOutputDimensions * kInputDimensions];
// 順伝播用バッファ
// Forward propagation buffer
std::vector<LearnFloatType> output_;
// 逆伝播用バッファ
// buffer for back propagation
std::vector<LearnFloatType> gradients_;
// ハイパーパラメータ
// hyper parameter
LearnFloatType momentum_;
LearnFloatType learning_rate_scale_;
};

View file

@ -1,4 +1,4 @@
// NNUE評価関数の学習クラステンプレートのClippedReLU用特殊化
// Specialization of NNUE evaluation function learning class template for ClippedReLU
#ifndef _NNUE_TRAINER_CLIPPED_RELU_H_
#define _NNUE_TRAINER_CLIPPED_RELU_H_
@ -13,22 +13,22 @@ namespace Eval {
namespace NNUE {
// 学習:アフィン変換層
// Learning: Affine transformation layer
template <typename PreviousLayer>
class Trainer<Layers::ClippedReLU<PreviousLayer>> {
private:
// 学習対象の層の型
// Type of layer to learn
using LayerType = Layers::ClippedReLU<PreviousLayer>;
public:
// ファクトリ関数
// factory function
static std::shared_ptr<Trainer> Create(
LayerType* target_layer, FeatureTransformer* feature_transformer) {
return std::shared_ptr<Trainer>(
new Trainer(target_layer, feature_transformer));
}
// ハイパーパラメータなどのオプションを設定する
// Set options such as hyperparameters
void SendMessage(Message* message) {
previous_layer_trainer_->SendMessage(message);
if (ReceiveMessage("check_health", message)) {
@ -36,13 +36,13 @@ class Trainer<Layers::ClippedReLU<PreviousLayer>> {
}
}
// パラメータを乱数で初期化する
// Initialize the parameters with random numbers
template <typename RNG>
void Initialize(RNG& rng) {
previous_layer_trainer_->Initialize(rng);
}
// 順伝播
// forward propagation
const LearnFloatType* Propagate(const std::vector<Example>& batch) {
if (output_.size() < kOutputDimensions * batch.size()) {
output_.resize(kOutputDimensions * batch.size());
@ -62,7 +62,7 @@ class Trainer<Layers::ClippedReLU<PreviousLayer>> {
return output_.data();
}
// 逆伝播
// backpropagation
void Backpropagate(const LearnFloatType* gradients,
LearnFloatType learning_rate) {
for (IndexType b = 0; b < batch_size_; ++b) {
@ -77,7 +77,7 @@ class Trainer<Layers::ClippedReLU<PreviousLayer>> {
}
private:
// コンストラクタ
// constructor
Trainer(LayerType* target_layer, FeatureTransformer* feature_transformer) :
batch_size_(0),
previous_layer_trainer_(Trainer<PreviousLayer>::Create(
@ -89,7 +89,7 @@ class Trainer<Layers::ClippedReLU<PreviousLayer>> {
std::numeric_limits<LearnFloatType>::lowest());
}
// 学習に問題が生じていないかチェックする
// Check if there are any problems with learning
void CheckHealth() {
const auto largest_min_activation = *std::max_element(
std::begin(min_activations_), std::end(min_activations_));
@ -105,30 +105,30 @@ class Trainer<Layers::ClippedReLU<PreviousLayer>> {
std::numeric_limits<LearnFloatType>::lowest());
}
// 入出力の次元数
// number of input/output dimensions
static constexpr IndexType kInputDimensions = LayerType::kOutputDimensions;
static constexpr IndexType kOutputDimensions = LayerType::kOutputDimensions;
// LearnFloatTypeの定数
// LearnFloatType constant
static constexpr LearnFloatType kZero = static_cast<LearnFloatType>(0.0);
static constexpr LearnFloatType kOne = static_cast<LearnFloatType>(1.0);
// ミニバッチのサンプル数
// number of samples in mini-batch
IndexType batch_size_;
// 直前の層のTrainer
// Trainer of the previous layer
const std::shared_ptr<Trainer<PreviousLayer>> previous_layer_trainer_;
// 学習対象の層
// layer to learn
LayerType* const target_layer_;
// 順伝播用バッファ
// Forward propagation buffer
std::vector<LearnFloatType> output_;
// 逆伝播用バッファ
// buffer for back propagation
std::vector<LearnFloatType> gradients_;
// ヘルスチェック用統計値
// Health check statistics
LearnFloatType min_activations_[kOutputDimensions];
LearnFloatType max_activations_[kOutputDimensions];
};
@ -139,4 +139,4 @@ class Trainer<Layers::ClippedReLU<PreviousLayer>> {
#endif // defined(EVAL_LEARN) && defined(EVAL_NNUE)
#endif
#endif

View file

@ -1,4 +1,4 @@
// NNUE評価関数の学習クラステンプレートのFeatureTransformer用特殊化
// Specialization for feature transformer of learning class template of NNUE evaluation function
#ifndef _NNUE_TRAINER_FEATURE_TRANSFORMER_H_
#define _NNUE_TRAINER_FEATURE_TRANSFORMER_H_
@ -24,11 +24,11 @@ namespace Eval {
namespace NNUE {
// 学習:入力特徴量変換器
// Learning: Input feature converter
template <>
class Trainer<FeatureTransformer> {
private:
// 学習対象の層の型
// Type of layer to learn
using LayerType = FeatureTransformer;
public:
@ -37,12 +37,12 @@ class Trainer<FeatureTransformer> {
template <typename T, typename... ArgumentTypes>
friend std::shared_ptr<T> MakeAlignedSharedPtr(ArgumentTypes&&... arguments);
// ファクトリ関数
// factory function
static std::shared_ptr<Trainer> Create(LayerType* target_layer) {
return MakeAlignedSharedPtr<Trainer>(target_layer);
}
// ハイパーパラメータなどのオプションを設定する
// Set options such as hyperparameters
void SendMessage(Message* message) {
if (ReceiveMessage("momentum", message)) {
momentum_ = static_cast<LearnFloatType>(std::stod(message->value));
@ -65,7 +65,7 @@ class Trainer<FeatureTransformer> {
}
}
// パラメータを乱数で初期化する
// Initialize the parameters with random numbers
template <typename RNG>
void Initialize(RNG& rng) {
std::fill(std::begin(weights_), std::end(weights_), +kZero);
@ -81,7 +81,7 @@ class Trainer<FeatureTransformer> {
QuantizeParameters();
}
// 順伝播
// forward propagation
const LearnFloatType* Propagate(const std::vector<Example>& batch) {
if (output_.size() < kOutputDimensions * batch.size()) {
output_.resize(kOutputDimensions * batch.size());
@ -131,7 +131,7 @@ class Trainer<FeatureTransformer> {
return output_.data();
}
// 逆伝播
// backpropagation
void Backpropagate(const LearnFloatType* gradients,
LearnFloatType learning_rate) {
const LearnFloatType local_learning_rate =
@ -144,8 +144,8 @@ class Trainer<FeatureTransformer> {
((output_[index] > kZero) * (output_[index] < kOne));
}
}
// 重み行列は入力に出現した特徴量に対応する列のみを更新するため、
// momentumを使用せず、学習率を補正してスケールを合わせる
// Since the weight matrix updates only the columns corresponding to the features that appeared in the input,
// Correct the learning rate and adjust the scale without using momentum
const LearnFloatType effective_learning_rate =
static_cast<LearnFloatType>(local_learning_rate / (1.0 - momentum_));
#if defined(USE_BLAS)
@ -227,7 +227,7 @@ class Trainer<FeatureTransformer> {
}
private:
// コンストラクタ
// constructor
Trainer(LayerType* target_layer) :
batch_(nullptr),
target_layer_(target_layer),
@ -245,7 +245,7 @@ class Trainer<FeatureTransformer> {
DequantizeParameters();
}
// 重みの飽和とパラメータの整数化
// Weight saturation and parameterization
void QuantizeParameters() {
for (IndexType i = 0; i < kHalfDimensions; ++i) {
target_layer_->biases_[i] =
@ -268,7 +268,7 @@ class Trainer<FeatureTransformer> {
}
}
// 整数化されたパラメータの読み込み
// read parameterized integer
void DequantizeParameters() {
for (IndexType i = 0; i < kHalfDimensions; ++i) {
biases_[i] = static_cast<LearnFloatType>(
@ -282,7 +282,7 @@ class Trainer<FeatureTransformer> {
std::fill(std::begin(biases_diff_), std::end(biases_diff_), +kZero);
}
// 学習データに出現していない特徴量に対応する重みを0にする
// Set the weight corresponding to the feature that does not appear in the learning data to 0
void ClearUnobservedFeatureWeights() {
for (IndexType i = 0; i < kInputDimensions; ++i) {
if (!observed_features.test(i)) {
@ -293,7 +293,7 @@ class Trainer<FeatureTransformer> {
QuantizeParameters();
}
// 学習に問題が生じていないかチェックする
// Check if there are any problems with learning
void CheckHealth() {
std::cout << "INFO: observed " << observed_features.count()
<< " (out of " << kInputDimensions << ") features" << std::endl;
@ -320,48 +320,48 @@ class Trainer<FeatureTransformer> {
std::numeric_limits<LearnFloatType>::lowest());
}
// 入出力の次元数
// number of input/output dimensions
static constexpr IndexType kInputDimensions =
Features::Factorizer<RawFeatures>::GetDimensions();
static constexpr IndexType kOutputDimensions = LayerType::kOutputDimensions;
static constexpr IndexType kHalfDimensions = LayerType::kHalfDimensions;
// パラメータの整数化で用いる係数
// Coefficient used for parameterization
static constexpr LearnFloatType kActivationScale =
std::numeric_limits<std::int8_t>::max();
static constexpr LearnFloatType kBiasScale = kActivationScale;
static constexpr LearnFloatType kWeightScale = kActivationScale;
// LearnFloatTypeの定数
// LearnFloatType constant
static constexpr LearnFloatType kZero = static_cast<LearnFloatType>(0.0);
static constexpr LearnFloatType kOne = static_cast<LearnFloatType>(1.0);
// ミニバッチ
// mini batch
const std::vector<Example>* batch_;
// 学習対象の層
// layer to learn
LayerType* const target_layer_;
// パラメータ
// parameter
alignas(kCacheLineSize) LearnFloatType biases_[kHalfDimensions];
alignas(kCacheLineSize)
LearnFloatType weights_[kHalfDimensions * kInputDimensions];
// パラメータの更新で用いるバッファ
// Buffer used for updating parameters
LearnFloatType biases_diff_[kHalfDimensions];
std::vector<LearnFloatType> gradients_;
// 順伝播用バッファ
// Forward propagation buffer
std::vector<LearnFloatType> output_;
// 学習データに出現した特徴量
// Features that appeared in the training data
std::bitset<kInputDimensions> observed_features;
// ハイパーパラメータ
// hyper parameter
LearnFloatType momentum_;
LearnFloatType learning_rate_scale_;
// ヘルスチェック用統計値
// Health check statistics
LearnFloatType min_pre_activation_;
LearnFloatType max_pre_activation_;
LearnFloatType min_activations_[kHalfDimensions];
@ -374,4 +374,4 @@ class Trainer<FeatureTransformer> {
#endif // defined(EVAL_LEARN) && defined(EVAL_NNUE)
#endif
#endif

View file

@ -1,4 +1,4 @@
// NNUE評価関数の学習クラステンプレートのInputSlice用特殊化
// Specialization of NNUE evaluation function learning class template for InputSlice
#ifndef _NNUE_TRAINER_INPUT_SLICE_H_
#define _NNUE_TRAINER_INPUT_SLICE_H_
@ -13,10 +13,10 @@ namespace Eval {
namespace NNUE {
// 学習:入力層
// Learning: Input layer
class SharedInputTrainer {
public:
// ファクトリ関数
// factory function
static std::shared_ptr<SharedInputTrainer> Create(
FeatureTransformer* feature_transformer) {
static std::shared_ptr<SharedInputTrainer> instance;
@ -27,7 +27,7 @@ class SharedInputTrainer {
return instance;
}
// ハイパーパラメータなどのオプションを設定する
// Set options such as hyperparameters
void SendMessage(Message* message) {
if (num_calls_ == 0) {
current_operation_ = Operation::kSendMessage;
@ -40,7 +40,7 @@ class SharedInputTrainer {
}
}
// パラメータを乱数で初期化する
// Initialize the parameters with random numbers
template <typename RNG>
void Initialize(RNG& rng) {
if (num_calls_ == 0) {
@ -54,7 +54,7 @@ class SharedInputTrainer {
}
}
// 順伝播
// forward propagation
const LearnFloatType* Propagate(const std::vector<Example>& batch) {
if (gradients_.size() < kInputDimensions * batch.size()) {
gradients_.resize(kInputDimensions * batch.size());
@ -72,7 +72,7 @@ class SharedInputTrainer {
return output_;
}
// 逆伝播
// backpropagation
void Backpropagate(const LearnFloatType* gradients,
LearnFloatType learning_rate) {
if (num_referrers_ == 1) {
@ -104,7 +104,7 @@ class SharedInputTrainer {
}
private:
// コンストラクタ
// constructor
SharedInputTrainer(FeatureTransformer* feature_transformer) :
batch_size_(0),
num_referrers_(0),
@ -115,11 +115,11 @@ class SharedInputTrainer {
output_(nullptr) {
}
// 入出力の次元数
// number of input/output dimensions
static constexpr IndexType kInputDimensions =
FeatureTransformer::kOutputDimensions;
// 処理の種類
// type of processing
enum class Operation {
kNone,
kSendMessage,
@ -128,55 +128,55 @@ class SharedInputTrainer {
kBackPropagate,
};
// ミニバッチのサンプル数
// number of samples in mini-batch
IndexType batch_size_;
// この層を入力として共有する層の数
// number of layers sharing this layer as input
std::uint32_t num_referrers_;
// 現在の処理が呼び出された回数
// Number of times the current process has been called
std::uint32_t num_calls_;
// 現在の処理の種類
// current processing type
Operation current_operation_;
// 入力特徴量変換器のTrainer
// Trainer of input feature converter
const std::shared_ptr<Trainer<FeatureTransformer>>
feature_transformer_trainer_;
// 順伝播用に共有する出力のポインタ
// pointer to output shared for forward propagation
const LearnFloatType* output_;
// 逆伝播用バッファ
// buffer for back propagation
std::vector<LearnFloatType> gradients_;
};
// 学習:入力層
// Learning: Input layer
template <IndexType OutputDimensions, IndexType Offset>
class Trainer<Layers::InputSlice<OutputDimensions, Offset>> {
private:
// 学習対象の層の型
// Type of layer to learn
using LayerType = Layers::InputSlice<OutputDimensions, Offset>;
public:
// ファクトリ関数
// factory function
static std::shared_ptr<Trainer> Create(
LayerType* /*target_layer*/, FeatureTransformer* feature_transformer) {
return std::shared_ptr<Trainer>(new Trainer(feature_transformer));
}
// ハイパーパラメータなどのオプションを設定する
// Set options such as hyperparameters
void SendMessage(Message* message) {
shared_input_trainer_->SendMessage(message);
}
// パラメータを乱数で初期化する
// Initialize the parameters with random numbers
template <typename RNG>
void Initialize(RNG& rng) {
shared_input_trainer_->Initialize(rng);
}
// 順伝播
// forward propagation
const LearnFloatType* Propagate(const std::vector<Example>& batch) {
if (output_.size() < kOutputDimensions * batch.size()) {
output_.resize(kOutputDimensions * batch.size());
@ -199,7 +199,7 @@ class Trainer<Layers::InputSlice<OutputDimensions, Offset>> {
return output_.data();
}
// 逆伝播
// backpropagation
void Backpropagate(const LearnFloatType* gradients,
LearnFloatType learning_rate) {
for (IndexType b = 0; b < batch_size_; ++b) {
@ -217,28 +217,28 @@ class Trainer<Layers::InputSlice<OutputDimensions, Offset>> {
}
private:
// コンストラクタ
Trainer(FeatureTransformer* feature_transformer) :
// constructor
Trainer(FeatureTransformer* feature_transformer):
batch_size_(0),
shared_input_trainer_(SharedInputTrainer::Create(feature_transformer)) {
}
// 入出力の次元数
// number of input/output dimensions
static constexpr IndexType kInputDimensions =
FeatureTransformer::kOutputDimensions;
static constexpr IndexType kOutputDimensions = OutputDimensions;
static_assert(Offset + kOutputDimensions <= kInputDimensions, "");
// ミニバッチのサンプル数
// number of samples in mini-batch
IndexType batch_size_;
// 共有入力層のTrainer
// Trainer of shared input layer
const std::shared_ptr<SharedInputTrainer> shared_input_trainer_;
// 順伝播用バッファ
// Forward propagation buffer
std::vector<LearnFloatType> output_;
// 逆伝播用バッファ
// buffer for back propagation
std::vector<LearnFloatType> gradients_;
};

View file

@ -1,4 +1,4 @@
// NNUE評価関数の学習クラステンプレートのSum用特殊化
// Specialization of NNUE evaluation function learning class template for Sum
#ifndef _NNUE_TRAINER_SUM_H_
#define _NNUE_TRAINER_SUM_H_
@ -13,40 +13,40 @@ namespace Eval {
namespace NNUE {
// 学習:複数の層の出力の和を取る層
// Learning: A layer that sums the outputs of multiple layers
template <typename FirstPreviousLayer, typename... RemainingPreviousLayers>
class Trainer<Layers::Sum<FirstPreviousLayer, RemainingPreviousLayers...>> :
Trainer<Layers::Sum<RemainingPreviousLayers...>> {
private:
// 学習対象の層の型
// Type of layer to learn
using LayerType = Layers::Sum<FirstPreviousLayer, RemainingPreviousLayers...>;
using Tail = Trainer<Layers::Sum<RemainingPreviousLayers...>>;
public:
// ファクトリ関数
// factory function
static std::shared_ptr<Trainer> Create(
LayerType* target_layer, FeatureTransformer* feature_transformer) {
return std::shared_ptr<Trainer>(
new Trainer(target_layer, feature_transformer));
}
// ハイパーパラメータなどのオプションを設定する
// Set options such as hyperparameters
void SendMessage(Message* message) {
// 他のメンバ関数の結果は処理の順番に依存しないため、
// 実装をシンプルにすることを目的としてTailを先に処理するが、
// SendMessageは添字の対応を分かりやすくするためにHeadを先に処理する
// 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);
}
// パラメータを乱数で初期化する
// Initialize the parameters with random numbers
template <typename RNG>
void Initialize(RNG& rng) {
Tail::Initialize(rng);
previous_layer_trainer_->Initialize(rng);
}
// 順伝播
// forward propagation
/*const*/ LearnFloatType* Propagate(const std::vector<Example>& batch) {
batch_size_ = static_cast<IndexType>(batch.size());
auto output = Tail::Propagate(batch);
@ -65,7 +65,7 @@ class Trainer<Layers::Sum<FirstPreviousLayer, RemainingPreviousLayers...>> :
return output;
}
// 逆伝播
// backpropagation
void Backpropagate(const LearnFloatType* gradients,
LearnFloatType learning_rate) {
Tail::Backpropagate(gradients, learning_rate);
@ -73,8 +73,8 @@ class Trainer<Layers::Sum<FirstPreviousLayer, RemainingPreviousLayers...>> :
}
private:
// コンストラクタ
Trainer(LayerType* target_layer, FeatureTransformer* feature_transformer) :
// constructor
Trainer(LayerType* target_layer, FeatureTransformer* feature_transformer):
Tail(target_layer, feature_transformer),
batch_size_(0),
previous_layer_trainer_(Trainer<FirstPreviousLayer>::Create(
@ -82,51 +82,51 @@ class Trainer<Layers::Sum<FirstPreviousLayer, RemainingPreviousLayers...>> :
target_layer_(target_layer) {
}
// 入出力の次元数
// number of input/output dimensions
static constexpr IndexType kOutputDimensions = LayerType::kOutputDimensions;
// サブクラスをfriendにする
// make subclass friend
template <typename SumLayer>
friend class Trainer;
// ミニバッチのサンプル数
// number of samples in mini-batch
IndexType batch_size_;
// 直前の層のTrainer
// Trainer of the previous layer
const std::shared_ptr<Trainer<FirstPreviousLayer>> previous_layer_trainer_;
// 学習対象の層
// layer to learn
LayerType* const target_layer_;
};
// 学習複数の層の出力の和を取る層テンプレート引数が1つの場合
// Learning: Layer that takes the sum of the outputs of multiple layers (when there is one template argument)
template <typename PreviousLayer>
class Trainer<Layers::Sum<PreviousLayer>> {
private:
// 学習対象の層の型
// Type of layer to learn
using LayerType = Layers::Sum<PreviousLayer>;
public:
// ファクトリ関数
// factory function
static std::shared_ptr<Trainer> Create(
LayerType* target_layer, FeatureTransformer* feature_transformer) {
return std::shared_ptr<Trainer>(
new Trainer(target_layer, feature_transformer));
}
// ハイパーパラメータなどのオプションを設定する
// Set options such as hyperparameters
void SendMessage(Message* message) {
previous_layer_trainer_->SendMessage(message);
}
// パラメータを乱数で初期化する
// Initialize the parameters with random numbers
template <typename RNG>
void Initialize(RNG& rng) {
previous_layer_trainer_->Initialize(rng);
}
// 順伝播
// forward propagation
/*const*/ LearnFloatType* Propagate(const std::vector<Example>& batch) {
if (output_.size() < kOutputDimensions * batch.size()) {
output_.resize(kOutputDimensions * batch.size());
@ -146,14 +146,14 @@ class Trainer<Layers::Sum<PreviousLayer>> {
return output_.data();
}
// 逆伝播
// backpropagation
void Backpropagate(const LearnFloatType* gradients,
LearnFloatType learning_rate) {
previous_layer_trainer_->Backpropagate(gradients, learning_rate);
}
private:
// コンストラクタ
// constructor
Trainer(LayerType* target_layer, FeatureTransformer* feature_transformer) :
batch_size_(0),
previous_layer_trainer_(Trainer<PreviousLayer>::Create(
@ -161,23 +161,23 @@ class Trainer<Layers::Sum<PreviousLayer>> {
target_layer_(target_layer) {
}
// 入出力の次元数
// number of input/output dimensions
static constexpr IndexType kOutputDimensions = LayerType::kOutputDimensions;
// サブクラスをfriendにする
// make subclass friend
template <typename SumLayer>
friend class Trainer;
// ミニバッチのサンプル数
// number of samples in mini-batch
IndexType batch_size_;
// 直前の層のTrainer
// Trainer of the previous layer
const std::shared_ptr<Trainer<PreviousLayer>> previous_layer_trainer_;
// 学習対象の層
// layer to learn
LayerType* const target_layer_;
// 順伝播用バッファ
// Forward propagation buffer
std::vector<LearnFloatType> output_;
};
@ -187,4 +187,4 @@ class Trainer<Layers::Sum<PreviousLayer>> {
#endif // defined(EVAL_LEARN) && defined(EVAL_NNUE)
#endif
#endif

View file

@ -5,33 +5,33 @@
#include <sstream>
#include <fstream>
#include <cstring> // std::memset()
#include <cstring> // std::memset()
using namespace std;
// -----------------------------------
// 局面の圧縮・解凍
// stage compression/decompression
// -----------------------------------
// ビットストリームを扱うクラス
// 局面の符号化を行なうときに、これがあると便利
// Class that handles bitstream
// useful when doing aspect encoding
struct BitStream
{
// データを格納するメモリを事前にセットする。
// そのメモリは0クリアされているものとする。
// Set the memory to store the data in advance.
// Assume that memory is cleared to 0.
void set_data(uint8_t* data_) { data = data_; reset(); }
// set_data()で渡されたポインタの取得。
// Get the pointer passed in set_data().
uint8_t* get_data() const { return data; }
// カーソルの取得。
// Get the cursor.
int get_cursor() const { return bit_cursor; }
// カーソルのリセット
// reset the cursor
void reset() { bit_cursor = 0; }
// ストリームに1bit書き出す。
// bは非0なら1を書き出す。0なら0を書き出す。
// Write 1bit to the stream.
// If b is non-zero, write out 1. If 0, write 0.
void write_one_bit(int b)
{
if (b)
@ -40,7 +40,7 @@ struct BitStream
++bit_cursor;
}
// ストリームから1ビット取り出す。
// Get 1 bit from the stream.
int read_one_bit()
{
int b = (data[bit_cursor / 8] >> (bit_cursor & 7)) & 1;
@ -49,16 +49,16 @@ struct BitStream
return b;
}
// nビットのデータを書き出す
// データはdの下位から順に書き出されるものとする。
// write n bits of data
// Data shall be written out from the lower order of d.
void write_n_bit(int d, int n)
{
for (int i = 0; i < n; ++i)
for (int i = 0; i <n; ++i)
write_one_bit(d & (1 << i));
}
// nビットのデータを読み込む
// write_n_bit()の逆変換。
// read n bits of data
// Reverse conversion of write_n_bit().
int read_n_bit(int n)
{
int result = 0;
@ -69,46 +69,46 @@ struct BitStream
}
private:
// 次に読み書きすべきbit位置。
// Next bit position to read/write.
int bit_cursor;
// データの実体
// data entity
uint8_t* data;
};
// ハフマン符号化
// ※  なのはminiの符号化から、変換が楽になるように単純化。
// Huffman coding
// * is simplified from mini encoding to make conversion easier.
//
// 盤上の1升(NO_PIECE以外) = 26bit ( + 成りフラグ1bit+ 先後1bit )
// 手駒の1枚 = 15bit ( + 成りフラグ1bit+ 先後1bit )
// 1 box on the board (other than NO_PIECE) = 2 to 6 bits (+ 1-bit flag + 1-bit forward and backward)
// 1 piece of hand piece = 1-5bit (+ 1-bit flag + 1bit ahead and behind)
//
// 空 xxxxx0 + 0 (none)
// 歩 xxxx01 + 2 xxxx0 + 2
// 香 xx0011 + 2 xx001 + 2
// 桂 xx1011 + 2 xx101 + 2
// 銀 xx0111 + 2 xx011 + 2
// 金 x01111 + 1 x0111 + 1 // 金は成りフラグはない。
// 角 011111 + 2 01111 + 2
// 飛 111111 + 2 11111 + 2
// empty xxxxx0 + 0 (none)
// step xxxx01 + 2 xxxx0 + 2
// incense xx0011 + 2 xx001 + 2
// Katsura xx1011 + 2 xx101 + 2
// silver xx0111 + 2 xx011 + 2
// Gold x01111 + 1 x0111 + 1 // Gold is valid and has no flags.
// corner 011111 + 2 01111 + 2
// Fly 111111 + 2 11111 + 2
//
// すべての駒が盤上にあるとして、
// 空 81 - 40駒 = 41升 = 41bit
// 歩 4bit*18駒 = 72bit
// 香 6bit* 4駒 = 24bit
// 桂 6bit* 4駒 = 24bit
// 銀 6bit* 4駒 = 24bit
// 金 6bit* 4駒 = 24bit
// 角 8bit* 2駒 = 16bit
// 飛 8bit* 2駒 = 16bit
// -------
// 241bit + 1bit(手番) + 7bit×2(王の位置先後) = 256bit
// Assuming all pieces are on the board,
// Sky 81-40 pieces = 41 boxes = 41bit
// Walk 4bit*18 pieces = 72bit
// Incense 6bit*4 pieces = 24bit
// Katsura 6bit*4 pieces = 24bit
// Silver 6bit*4 pieces = 24bit
// Gold 6bit* 4 pieces = 24bit
// corner 8bit* 2 pieces = 16bit
// Fly 8bit* 2 pieces = 16bit
// -------
// 241bit + 1bit (turn) + 7bit × 2 (King's position after) = 256bit
//
// 盤上の駒が手駒に移動すると盤上の駒が空になるので盤上のその升は1bitで表現でき、
// 手駒は、盤上の駒より1bit少なく表現できるので結局、全体のbit数に変化はない。
// ゆえに、この表現において、どんな局面でもこのbit数で表現できる。
// 手駒に成りフラグは不要だが、これも含めておくと盤上の駒のbit数-1になるので
// 全体のbit数が固定化できるのでこれも含めておくことにする。
// When the piece on the board moves to the hand piece, the piece on the board becomes empty, so the box on the board can be expressed with 1 bit,
// Since the hand piece can be expressed by 1 bit less than the piece on the board, the total number of bits does not change in the end.
// Therefore, in this expression, any aspect can be expressed by this bit number.
// It is a hand piece and no flag is required, but if you include this, the bit number of the piece on the board will be -1
// Since the total number of bits can be fixed, we will include this as well.
// Huffman Encoding
//
@ -120,8 +120,8 @@ private:
struct HuffmanedPiece
{
int code; // どうコード化されるか
int bits; // 何bit専有するのか
int code; // how it will be coded
int bits; // How many bits do you have
};
HuffmanedPiece huffman_table[] =
@ -134,11 +134,11 @@ HuffmanedPiece huffman_table[] =
{0b1001,4}, // QUEEN
};
// sfenを圧縮/解凍するためのクラス
// sfenはハフマン符号化をすることで256bit(32bytes)にpackできる。
// このことはなのはminiにより証明された。上のハフマン符号化である。
// Class for compressing/decompressing sfen
// sfen can be packed to 256bit (32bytes) by Huffman coding.
// This is proven by mini. The above is Huffman coding.
//
// 内部フォーマット = 手番1bit+王の位置7bit*2 + 盤上の駒(ハフマン符号化) + 手駒(ハフマン符号化)
// Internal format = 1-bit turn + 7-bit king position *2 + piece on board (Huffman coding) + hand piece (Huffman coding)
// Side to move (White = 0, Black = 1) (1bit)
// White King Position (6 bits)
// Black King Position (6 bits)
@ -152,21 +152,21 @@ HuffmanedPiece huffman_table[] =
//
struct SfenPacker
{
// sfenをpackしてdata[32]に格納する。
// Pack sfen and store in data[32].
void pack(const Position& pos)
{
// cout << pos;
// cout << pos;
memset(data, 0, 32 /* 256bit */);
stream.set_data(data);
// 手番
// turn
// Side to move.
stream.write_one_bit((int)(pos.side_to_move()));
// 先手玉、後手玉の位置、それぞれ7bit
// 7-bit positions for leading and trailing balls
// White king and black king, 6 bits for each.
for(auto c : Colors)
for(auto c: Colors)
stream.write_n_bit(pos.king_square(c), 6);
// Write the pieces on the board other than the kings.
@ -197,24 +197,24 @@ struct SfenPacker
stream.write_n_bit(pos.state()->rule50, 6);
stream.write_n_bit(1 + (pos.game_ply() - (pos.side_to_move() == BLACK)) / 2, 8);
stream.write_n_bit(1 + (pos.game_ply()-(pos.side_to_move() == BLACK)) / 2, 8);
assert(stream.get_cursor() <= 256);
}
// pack()でpackされたsfen(256bit = 32bytes)
// もしくはunpack()でdecodeするsfen
// sfen packed by pack() (256bit = 32bytes)
// Or sfen to decode with unpack()
uint8_t *data; // uint8_t[32];
//private:
// Position::set_from_packed_sfen(uint8_t data[32])でこれらの関数を使いたいので筋は悪いがpublicにしておく。
// Position::set_from_packed_sfen(uint8_t data[32]) I want to use these functions, so the line is bad, but I want to keep it public.
BitStream stream;
// 盤面の駒をstreamに出力する。
// Output the board pieces to stream.
void write_board_piece_to_stream(Piece pc)
{
// 駒種
// piece type
PieceType pr = type_of(pc);
auto c = huffman_table[pr];
stream.write_n_bit(c.code, c.bits);
@ -222,11 +222,11 @@ struct SfenPacker
if (pc == NO_PIECE)
return;
// 先後フラグ
// first and second flag
stream.write_one_bit(color_of(pc));
}
// 盤面の駒を1枚streamから読み込む
// Read one board piece from stream
Piece read_board_piece_from_stream()
{
PieceType pr = NO_PIECE_TYPE;
@ -238,7 +238,7 @@ struct SfenPacker
assert(bits <= 6);
for (pr = NO_PIECE_TYPE; pr < KING; ++pr)
for (pr = NO_PIECE_TYPE; pr <KING; ++pr)
if (huffman_table[pr].code == code
&& huffman_table[pr].bits == bits)
goto Found;
@ -247,7 +247,7 @@ struct SfenPacker
if (pr == NO_PIECE_TYPE)
return NO_PIECE;
// 先後フラグ
// first and second flag
Color c = (Color)stream.read_one_bit();
return make_piece(c, pr);
@ -256,12 +256,12 @@ struct SfenPacker
// -----------------------------------
// Positionクラスに追加
// Add to Position class
// -----------------------------------
// 高速化のために直接unpackする関数を追加。かなりしんどい。
// packer::unpack()とPosition::set()とを合体させて書く。
// 渡された局面に問題があって、エラーのときは非0を返す。
// Add a function that directly unpacks for speed. It's pretty tough.
// Write it by combining packer::unpack() and Position::set().
// If there is a problem with the passed phase and there is an error, non-zero is returned.
int Position::set_from_packed_sfen(const PackedSfen& sfen , StateInfo * si, Thread* th, bool mirror)
{
SfenPacker packer;
@ -276,17 +276,17 @@ int Position::set_from_packed_sfen(const PackedSfen& sfen , StateInfo * si, Thre
// Active color
sideToMove = (Color)stream.read_one_bit();
// evalListのclear。上でmemsetでゼロクリアしたときにクリアされているが…。
// clear evalList. It is cleared when memset is cleared to zero above...
evalList.clear();
// PieceListを更新する上で、どの駒がどこにあるかを設定しなければならないが、
// それぞれの駒をどこまで使ったかのカウンター
// In updating the PieceList, we have to set which piece is where,
// A counter of how much each piece has been used
PieceNumber next_piece_number = PIECE_NUMBER_ZERO;
pieceList[W_KING][0] = SQUARE_NB;
pieceList[B_KING][0] = SQUARE_NB;
// まず玉の位置
// First the position of the ball
if (mirror)
{
for (auto c : Colors)
@ -308,7 +308,7 @@ int Position::set_from_packed_sfen(const PackedSfen& sfen , StateInfo * si, Thre
sq = Mir(sq);
}
// すでに玉がいるようだ
// it seems there are already balls
Piece pc;
if (type_of(board[sq]) != KING)
{
@ -318,26 +318,26 @@ int Position::set_from_packed_sfen(const PackedSfen& sfen , StateInfo * si, Thre
else
{
pc = board[sq];
board[sq] = NO_PIECE; // いっかい取り除いておかないとput_piece()でASSERTに引っかかる。
board[sq] = NO_PIECE; // put_piece() will catch ASSERT unless you remove it all.
}
// 駒がない場合もあるのでその場合はスキップする。
// There may be no pieces, so skip in that case.
if (pc == NO_PIECE)
continue;
put_piece(Piece(pc), sq);
// evalListの更新
// update evalList
PieceNumber piece_no =
(pc == B_KING) ? PIECE_NUMBER_BKING : // 先手玉
(pc == W_KING) ? PIECE_NUMBER_WKING : // 後手玉
next_piece_number++; // それ以外
(pc == B_KING) ?PIECE_NUMBER_BKING :// Move ball
(pc == W_KING) ?PIECE_NUMBER_WKING :// Backing ball
next_piece_number++; // otherwise
evalList.put_piece(piece_no, sq, pc); // sqの升にpcの駒を配置する
evalList.put_piece(piece_no, sq, pc); // Place the pc piece in the sq box
//cout << sq << ' ' << board[sq] << ' ' << stream.get_cursor() << endl;
if (stream.get_cursor() > 256)
if (stream.get_cursor()> 256)
return 1;
//assert(stream.get_cursor() <= 256);
@ -397,7 +397,7 @@ int Position::set_from_packed_sfen(const PackedSfen& sfen , StateInfo * si, Thre
chess960 = false;
thisThread = th;
set_state(st);
set_state(st);
//std::cout << *this << std::endl;
@ -409,11 +409,11 @@ int Position::set_from_packed_sfen(const PackedSfen& sfen , StateInfo * si, Thre
return 0;
}
// 盤面と手駒、手番を与えて、そのsfenを返す。
// Give the board, hand piece, and turn, and return the sfen.
//std::string Position::sfen_from_rawdata(Piece board[81], Hand hands[2], Color turn, int gamePly_)
//{
// // 内部的な構造体にコピーして、sfen()を呼べば、変換過程がそこにしか依存していないならば
// // これで正常に変換されるのでは…。
// // Copy it to an internal structure and call sfen() if the conversion process depends only on it
// // Maybe it will be converted normally...
// Position pos;
//
// memcpy(pos.board, board, sizeof(Piece) * 81);
@ -423,11 +423,11 @@ int Position::set_from_packed_sfen(const PackedSfen& sfen , StateInfo * si, Thre
//
// return pos.sfen();
//
// // ↑の実装、美しいが、いかんせん遅い。
// // 棋譜を大量に読み込ませて学習させるときにここがボトルネックになるので直接unpackする関数を書く。
// // Implementation of ↑ is beautiful, but slow.
// // This is a bottleneck when learning a large amount of game records, so write a function to unpack directly.
//}
// packされたsfenを得る。引数に指定したバッファに返す。
// Get the packed sfen. Returns to the buffer specified in the argument.
void Position::sfen_pack(PackedSfen& sfen)
{
SfenPacker sp;
@ -435,14 +435,13 @@ void Position::sfen_pack(PackedSfen& sfen)
sp.pack(*this);
}
//// packされたsfenを解凍する。sfen文字列が返る。
//// Unpack the packed sfen. Returns an sfen string.
//std::string Position::sfen_unpack(const PackedSfen& sfen)
//{
// SfenPacker sp;
// sp.data = (uint8_t*)&sfen;
// return sp.unpack();
// SfenPacker sp;
// sp.data = (uint8_t*)&sfen;
// return sp.unpack();
//}
#endif // USE_SFEN_PACKER

View file

@ -4,8 +4,8 @@
// Half Float Library by yaneurao
// (16-bit float)
// 16bit型による浮動小数点演算
// コンパイラの生成するfloat型のコードがIEEE 754の形式であると仮定して、それを利用する。
// Floating point operation by 16bit type
// Assume that the float type code generated by the compiler is in IEEE 754 format and use it.
#include "../types.h"
@ -99,7 +99,7 @@ namespace HalfFloat
return c.f;
}
// unit testになってないが、一応計算が出来ることは確かめた。コードはあとでなおす(かも)。
// It is not a unit test, but I confirmed that it can be calculated. I'll fix the code later (maybe).
static void unit_test()
{
float16 a, b, c, d;
@ -130,4 +130,4 @@ namespace HalfFloat
}
#endif // __HALF_FLOAT_H__
#endif // __HALF_FLOAT_H__

View file

@ -6,173 +6,173 @@
#include <vector>
// =====================
// 学習時の設定
// Settings for learning
// =====================
// 以下のいずれかを選択すれば、そのあとの細々したものは自動的に選択される。
// いずれも選択しない場合は、そのあとの細々したものをひとつひとつ設定する必要がある。
// If you select one of the following, the details after that will be automatically selected.
// If you don't select any of them, you need to set the subsequent details one by one.
// elmo方式での学習設定。これをデフォルト設定とする。
// 標準の雑巾絞りにするためにはlearnコマンドで "lambda 1"を指定してやれば良い。
// Learning setting by elmo method. This is the default setting.
// To make a standard squeeze diaphragm, specify "lambda 1" with the learn command.
#define LEARN_ELMO_METHOD
// ----------------------
// 更新式
// update formula
// ----------------------
// AdaGrad。これが安定しているのでお勧め。
// Ada Grad. Recommended because it is stable.
// #define ADA_GRAD_UPDATE
// 勾配の符号だけ見るSGD。省メモリで済むが精度は…。
// SGD looking only at the sign of the gradient. It requires less memory, but the accuracy is...
// #define SGD_UPDATE
// ----------------------
// 学習時の設定
// Settings for learning
// ----------------------
// mini-batchサイズ。
// この数だけの局面をまとめて勾配を計算する。
// 小さくするとupdate_weights()の回数が増えるので収束が速くなる。勾配が不正確になる。
// 大きくするとupdate_weights()の回数が減るので収束が遅くなる。勾配は正確に出るようになる。
// 多くの場合において、この値を変更する必要はないと思う。
// mini-batch size.
// Calculate the gradient by combining this number of phases.
// If you make it smaller, the number of update_weights() will increase and the convergence will be faster. The gradient is incorrect.
// If you increase it, the number of update_weights() decreases, so the convergence will be slow. The slope will come out accurately.
// I don't think you need to change this value in most cases.
#define LEARN_MINI_BATCH_SIZE (1000 * 1000 * 1)
// ファイルから1回に読み込む局面数。これだけ読み込んだあとshuffleする。
// ある程度大きいほうが良いが、この数×40byte×3倍ぐらいのメモリを消費する。10M局面なら400MB*3程度消費する。
// THREAD_BUFFER_SIZE(=10000)の倍数にすること。
// The number of phases to read from the file at one time. After reading this much, shuffle.
// It is better to have a certain size, but this number x 40 bytes x 3 times as much memory is consumed. 400MB*3 is consumed in the 10M phase.
// Must be a multiple of THREAD_BUFFER_SIZE(=10000).
#define LEARN_SFEN_READ_SIZE (1000 * 1000 * 10)
// 学習時の評価関数の保存間隔。この局面数だけ学習させるごとに保存。
// 当然ながら、保存間隔を長くしたほうが学習時間は短くなる。
// フォルダ名は 0/ , 1/ , 2/ ...のように保存ごとにインクリメントされていく。
// デフォルトでは10億局面に1回。
// Saving interval of evaluation function at learning. Save each time you learn this number of phases.
// Needless to say, the longer the saving interval, the shorter the learning time.
// Folder name is incremented for each save like 0/, 1/, 2/...
// By default, once every 1 billion phases.
#define LEARN_EVAL_SAVE_INTERVAL (1000000000ULL)
// ----------------------
// 目的関数の選択
// Select the objective function
// ----------------------
// 目的関数が勝率の差の二乗和
// 詳しい説明は、learner.cppを見ること。
// The objective function is the sum of squares of the difference in winning percentage
// See learner.cpp for more information.
//#define LOSS_FUNCTION_IS_WINNING_PERCENTAGE
// 目的関数が交差エントロピー
// 詳しい説明は、learner.cppを見ること。
// いわゆる、普通の「雑巾絞り」
// Objective function is cross entropy
// See learner.cpp for more information.
// So-called ordinary "rag cloth squeezer"
//#define LOSS_FUNCTION_IS_CROSS_ENTOROPY
// 目的関数が交差エントロピーだが、勝率の関数を通さない版
// A version in which the objective function is cross entropy, but the win rate function is not passed
// #define LOSS_FUNCTION_IS_CROSS_ENTOROPY_FOR_VALUE
// elmo(WCSC27)の方式
// elmo (WCSC27) method
// #define LOSS_FUNCTION_IS_ELMO_METHOD
// ※ 他、色々追加するかも。
// ※ Other things may be added.
// ----------------------
// 学習に関するデバッグ設定
// debug settings for learning
// ----------------------
// 学習時のrmseの出力をこの回数に1回に減らす。
// rmseの計算は1スレッドで行なうためそこそこ時間をとられるので出力を減らすと効果がある。
// Reduce the output of rmse during learning to 1 for this number of times.
// rmse calculation is done in one thread, so it takes some time, so reducing the output is effective.
#define LEARN_RMSE_OUTPUT_INTERVAL 1
// ----------------------
// ゼロベクトルからの学習
// learning from zero vector
// ----------------------
// 評価関数パラメーターをゼロベクトルから学習を開始する。
// ゼロ初期化して棋譜生成してゼロベクトルから学習させて、
// 棋譜生成→学習を繰り返すとプロの棋譜に依らないパラメーターが得られる。(かも)
// (すごく時間かかる)
// Start learning the evaluation function parameters from the zero vector.
// Initialize to zero, generate a game, learn from zero vector,
// Game generation → If you repeat learning, you will get parameters that do not depend on the professional game. (maybe)
// (very time consuming)
//#define RESET_TO_ZERO_VECTOR
// ----------------------
// 学習のときの浮動小数
// Floating point for learning
// ----------------------
// これをdoubleにしたほうが計算精度は上がるが、重み配列絡みのメモリが倍必要になる。
// 現状、ここをfloatにした場合、評価関数ファイルに対して、重み配列はその4.5倍のサイズ。(KPPTで4.5GB程度)
// double型にしても収束の仕方にほとんど差異がなかったのでfloatに固定する。
// If this is set to double, the calculation accuracy will be higher, but the weight array entangled memory will be doubled.
// Currently, if this is float, the weight array is 4.5 times the size of the evaluation function file. (About 4.5GB with KPPT)
// Even if it is a double type, there is almost no difference in the way of convergence, so fix it to float.
// floatを使う場合
// when using float
typedef float LearnFloatType;
// doubleを使う場合
// when using double
//typedef double LearnFloatType;
// float16を使う場合
// when using float16
//#include "half_float.h"
//typedef HalfFloat::float16 LearnFloatType;
// ----------------------
// 省メモリ化
// save memory
// ----------------------
// Weight配列(のうちのKPP)に三角配列を用いて省メモリ化する。
// これを用いると、学習用の重み配列は評価関数ファイルの3倍程度で済むようになる。
// Use a triangular array for the Weight array (of which is KPP) to save memory.
// If this is used, the weight array for learning will be about 3 times as large as the evaluation function file.
#define USE_TRIANGLE_WEIGHT_ARRAY
// ----------------------
// 次元下げ
// dimension down
// ----------------------
// ミラー(左右対称性)、インバース(先後対称性)に関して次元下げを行なう。
// デフォルトではすべてオン。
// Dimension reduction for mirrors (left/right symmetry) and inverse (forward/backward symmetry).
// All on by default.
// KKに対してミラー、インバースを利用した次元下げを行なう。(効果のほどは不明)
// USE_KK_INVERSE_WRITEをオンにするときはUSE_KK_MIRROR_WRITEもオンでなければならない。
// Dimension reduction using mirror and inverse for KK. (Unclear effect)
// USE_KK_MIRROR_WRITE must be on when USE_KK_INVERSE_WRITE is on.
#define USE_KK_MIRROR_WRITE
#define USE_KK_INVERSE_WRITE
// KKPに対してミラー、インバースを利用した次元下げを行なう。(インバースのほうは効果のほどは不明)
// USE_KKP_INVERSE_WRITEをオンにするときは、USE_KKP_MIRROR_WRITEもオンになっていなければならない。
// Dimension reduction using Mirror and Inverse for KKP. (Inverse is not so effective)
// When USE_KKP_INVERSE_WRITE is turned on, USE_KKP_MIRROR_WRITE must also be turned on.
#define USE_KKP_MIRROR_WRITE
#define USE_KKP_INVERSE_WRITE
// KPPに対してミラーを利用した次元下げを行なう。(これをオフにすると教師局面が倍ぐらい必要になる)
// KPPにはインバースはない。(先手側のKしかないので)
// Perform dimension reduction using a mirror for KPP. (Turning this off requires double the teacher position)
// KPP has no inverse. (Because there is only K on the front side)
#define USE_KPP_MIRROR_WRITE
// KPPPに対してミラーを利用した次元下げを行なう。(これをオフにすると教師局面が倍ぐらい必要になる)
// KPPPにもインバースはない。(先手側のKしかないので)
// Perform a dimension reduction using a mirror for KPPP. (Turning this off requires double the teacher position)
// KPPP has no inverse. (Because there is only K on the front side)
#define USE_KPPP_MIRROR_WRITE
// KKPP成分に対して学習時にKPPによる次元下げを行なう。
// 学習、めっちゃ遅くなる。
// 未デバッグなので使わないこと。
// Reduce the dimension by KPP for learning the KKPP component.
// Learning is very slow.
// Do not use as it is not debugged.
//#define USE_KKPP_LOWER_DIM
// ======================
// 教師局面生成時の設定
// Settings for creating teacher phases
// ======================
// ----------------------
// 引き分けを書き出す
// write out the draw
// ----------------------
// 引き分けに至ったとき、それを教師局面として書き出す
// これをするほうが良いかどうかは微妙。
// When you reach a draw, write it out as a teacher position
// It's subtle whether it's better to do this.
// #define LEARN_GENSFEN_USE_DRAW_RESULT
// ======================
// configure
// configure
// ======================
// ----------------------
// elmo(WCSC27)の方法での学習
// Learning with the method of elmo (WCSC27)
// ----------------------
#if defined( LEARN_ELMO_METHOD )
@ -182,49 +182,49 @@ typedef float LearnFloatType;
// ----------------------
// Learnerで用いるstructの定義
// Definition of struct used in Learner
// ----------------------
#include "../position.h"
namespace Learner
{
// PackedSfenと評価値が一体化した構造体
// オプションごとに書き出す内容が異なると教師棋譜を再利用するときに困るので
// とりあえず、以下のメンバーはオプションによらずすべて書き出しておく。
//Structure in which PackedSfen and evaluation value are integrated
// If you write different contents for each option, it will be a problem when reusing the teacher game
// For the time being, write all the following members regardless of the options.
struct PackedSfenValue
{
// 局面
// phase
PackedSfen sfen;
// Learner::search()から返ってきた評価値
// Evaluation value returned from Learner::search()
int16_t score;
// PVの初手
// 教師との指し手一致率を求めるときなどに用いる
// PV first move
// Used when finding the match rate with the teacher
uint16_t move;
// 初期局面からの局面の手数。
// Trouble of the phase from the initial phase.
uint16_t gamePly;
// この局面の手番側が、ゲームを最終的に勝っているなら1。負けているなら-1。
// 引き分けに至った場合は、0。
// 引き分けは、教師局面生成コマンドgensfenにおいて、
// LEARN_GENSFEN_DRAW_RESULTが有効なときにだけ書き出す。
// 1 if the player on this side ultimately wins the game. -1 if you are losing.
// 0 if a draw is reached.
// The draw is in the teacher position generation command gensfen,
// Only write if LEARN_GENSFEN_DRAW_RESULT is enabled.
int8_t game_result;
// 教師局面を書き出したファイルを他の人とやりとりするときに
// この構造体サイズが不定だと困るため、paddingしてどの環境でも必ず40bytesになるようにしておく。
// When exchanging the file that wrote the teacher aspect with other people
//Because this structure size is not fixed, pad it so that it is 40 bytes in any environment.
uint8_t padding;
// 32 + 2 + 2 + 2 + 1 + 1 = 40bytes
};
// 読み筋とそのときの評価値を返す型
// Learner::search() , Learner::qsearch()で用いる。
// Type that returns the reading line and the evaluation value at that time
// Used in Learner::search(), Learner::qsearch().
typedef std::pair<Value, std::vector<Move> > ValueAndPV;
// いまのところ、やねうら王2018 Otafukuしか、このスタブを持っていないが
// EVAL_LEARNをdefineするなら、このスタブが必須。
// So far, only Yaneura King 2018 Otafuku has this stub
// This stub is required if EVAL_LEARN is defined.
extern Learner::ValueAndPV search(Position& pos, int depth , size_t multiPV = 1 , uint64_t NodesLimit = 0);
extern Learner::ValueAndPV qsearch(Position& pos);
@ -234,4 +234,4 @@ namespace Learner
#endif
#endif // ifndef _LEARN_H_
#endif // ifndef _LEARN_H_

File diff suppressed because it is too large Load diff

View file

@ -23,15 +23,15 @@ namespace EvalLearningTools
std::vector<bool> min_index_flag;
// --- 個別のテーブルごとの初期化
// --- initialization for each individual table
void init_min_index_flag()
{
// mir_piece、inv_pieceの初期化が終わっていなければならない。
// Initialization of mir_piece and inv_piece must be completed.
assert(mir_piece(Eval::f_pawn) == Eval::e_pawn);
// 次元下げ用フラグ配列の初期化
// KPPPに関しては関与しない。
// Initialize the flag array for dimension reduction
// Not involved in KPPP.
KK g_kk;
g_kk.set(SQUARE_NB, Eval::fe_end, 0);
@ -46,9 +46,9 @@ namespace EvalLearningTools
#pragma omp parallel
{
#if defined(_OPENMP)
// Windows環境下でCPUがつあるときに、論理64コアまでしか使用されないのを防ぐために
// ここで明示的にCPUに割り当てる
int thread_index = omp_get_thread_num(); // 自分のthread numberを取得
// To prevent the logical 64 cores from being used when there are two CPUs under Windows
// explicitly assign to CPU here
int thread_index = omp_get_thread_num(); // get your thread number
WinProcGroup::bindThisThread(thread_index);
#endif
@ -56,20 +56,20 @@ namespace EvalLearningTools
for (int64_t index_ = 0; index_ < (int64_t)size; ++index_)
{
// OpenMPの制約からループ変数は符号型でないといけないらしいのだが、
// さすがに使いにくい。
// It seems that the loop variable must be a sign type due to OpenMP restrictions, but
// It's really difficult to use.
uint64_t index = (uint64_t)index_;
if (g_kk.is_ok(index))
{
// indexからの変換と逆変換によって元のindexに戻ることを確認しておく。
// 起動時に1回しか実行しない処理なのでassertで書いておく。
// Make sure that the original index will be restored by conversion from index and reverse conversion.
// It is a process that is executed only once at startup, so write it in assert.
assert(g_kk.fromIndex(index).toIndex() == index);
KK a[KK_LOWER_COUNT];
g_kk.fromIndex(index).toLowerDimensions(a);
// 次元下げの1つ目の要素が元のindexと同一であることを確認しておく。
// Make sure that the first element of dimension reduction is the same as the original index.
assert(a[0].toIndex() == index);
uint64_t min_index = UINT64_MAX;
@ -118,9 +118,9 @@ namespace EvalLearningTools
void learning_tools_unit_test_kpp()
{
// KPPの三角配列化にバグがないかテストする
// k-p0-p1のすべての組み合わせがきちんとKPPの扱う対象になっていかと、そのときの次元下げが
// 正しいかを判定する。
// test KPP triangulation for bugs
// All combinations of k-p0-p1 are properly handled by KPP, and the dimension reduction at that time is
// Determine if it is correct.
KK g_kk;
g_kk.set(SQUARE_NB, Eval::fe_end, 0);
@ -159,24 +159,24 @@ namespace EvalLearningTools
f[index - g_kpp.min_index()] = f[index2-g_kpp.min_index()] = true;
}
// 抜けてるindexがなかったかの確認。
// Check if there is no missing index.
for(size_t index = 0 ; index < f.size(); index++)
if (!f[index])
{
std::cout << index << g_kpp.fromIndex(index + g_kpp.min_index()) << std::endl;
std::cout << index << g_kpp.fromIndex(index + g_kpp.min_index()) << std::endl;
}
}
void learning_tools_unit_test_kppp()
{
// KPPPの計算に抜けがないかをテストする
// Test for missing KPPP calculations
KPPP g_kppp;
g_kppp.set(15, Eval::fe_end,0);
uint64_t min_index = g_kppp.min_index();
uint64_t max_index = g_kppp.max_index();
// 最後の要素の確認。
// Confirm last element.
//KPPP x = KPPP::fromIndex(max_index-1);
//std::cout << x << std::endl;
@ -208,10 +208,10 @@ namespace EvalLearningTools
void learning_tools_unit_test_kkpp()
{
KKPP g_kkpp;
g_kkpp.set(SQUARE_NB, 10000 , 0);
g_kkpp.set(SQUARE_NB, 10000, 0);
uint64_t n = 0;
for (int k = 0; k<SQUARE_NB; ++k)
for (int i = 0; i<10000; ++i) // 試しに、かなり大きなfe_endを想定して10000で回してみる。
for (int i = 0; i<10000; ++i) // As a test, assuming a large fe_end, try turning at 10000.
for (int j = 0; j < i; ++j)
{
auto kkpp = g_kkpp.fromKKPP(k, (BonaPiece)i, (BonaPiece)j);
@ -222,27 +222,27 @@ namespace EvalLearningTools
}
}
// このEvalLearningTools全体の初期化
// Initialize this entire EvalLearningTools
void init()
{
// 初期化は、起動後1回限りで良いのでそのためのフラグ。
// Initialization is required only once after startup, so a flag for that.
static bool first = true;
if (first)
{
std::cout << "EvalLearningTools init..";
// mir_piece()とinv_piece()を利用可能にする。
// このあとmin_index_flagの初期化を行なうが、そこが
// これに依存しているので、こちらを先に行なう必要がある。
// Make mir_piece() and inv_piece() available.
// After this, the min_index_flag is initialized, but
// It depends on this, so you need to do this first.
init_mir_inv_tables();
//learning_tools_unit_test_kpp();
//learning_tools_unit_test_kppp();
//learning_tools_unit_test_kkpp();
// UnitTestを実行するの最後でも良いのだが、init_min_index_flag()にとても時間がかかるので
// デバッグ時はこのタイミングで行いたい。
// It may be the last time to execute UnitTest, but since init_min_index_flag() takes a long time,
// I want to do this at the time of debugging.
init_min_index_flag();
@ -253,4 +253,4 @@ namespace EvalLearningTools
}
}
#endif
#endif

File diff suppressed because it is too large Load diff

View file

@ -10,67 +10,67 @@
void MultiThink::go_think()
{
// あとでOptionsの設定を復元するためにコピーで保持しておく。
// Keep a copy to restore the Options settings later.
auto oldOptions = Options;
// 定跡を用いる場合、on the flyで行なうとすごく時間がかかるファイルアクセスを行なう部分が
// thread safeではないので、メモリに丸読みされている状態であることをここで保証する。
// When using the constant track, it takes a lot of time to perform on the fly & the part to access the file is
// Since it is not thread safe, it is guaranteed here that it is being completely read in memory.
Options["BookOnTheFly"] = std::string("false");
// 評価関数の読み込み等
// learnコマンドの場合、評価関数読み込み後に評価関数の値を補正している可能性があるので、
// メモリの破損チェックは省略する。
// Read evaluation function, etc.
// In the case of the learn command, the value of the evaluation function may be corrected after reading the evaluation function, so
// Skip memory corruption check.
is_ready(true);
// 派生クラスのinit()を呼び出す。
// Call the derived class's init().
init();
// ループ上限はset_loop_max()で設定されているものとする。
// The loop upper limit is set with set_loop_max().
loop_count = 0;
done_count = 0;
// threadをOptions["Threads"]の数だけ生成して思考開始。
// Create threads as many as Options["Threads"] and start thinking.
std::vector<std::thread> threads;
auto thread_num = (size_t)Options["Threads"];
// worker threadの終了フラグの確保
// Secure end flag of worker thread
thread_finished.resize(thread_num);
// worker threadの起動
// start worker thread
for (size_t i = 0; i < thread_num; ++i)
{
thread_finished[i] = 0;
threads.push_back(std::thread([i, this]
{
// プロセッサの全スレッドを使い切る。
// exhaust all processor threads.
WinProcGroup::bindThisThread(i);
// オーバーライドされている処理を実行
// execute the overridden process
this->thread_worker(i);
// スレッドが終了したので終了フラグを立てる
// Set the end flag because the thread has ended
this->thread_finished[i] = 1;
}));
}
// すべてのthreadの終了待ちを
// for (auto& th : threads)
// th.join();
// のように書くとスレッドがまだ仕事をしている状態でここに突入するので、
// その間、callback_func()が呼び出せず、セーブできなくなる。
// そこで終了フラグを自前でチェックする必要がある。
// wait for all threads to finish
// for (auto& th :threads)
// th.join();
// If you write like, the thread will rush here while it is still working,
// During that time, callback_func() cannot be called and you cannot save.
// Therefore, you need to check the end flag yourself.
// すべてのスレッドが終了したかを判定する関数
// function to determine if all threads have finished
auto threads_done = [&]()
{
// ひとつでも終了していなければfalseを返す
// returns false if no one is finished
for (auto& f : thread_finished)
if (!f)
return false;
return true;
};
// コールバック関数が設定されているならコールバックする。
// Call back if the callback function is set.
auto do_a_callback = [&]()
{
if (callback_func)
@ -80,44 +80,44 @@ void MultiThink::go_think()
for (uint64_t i = 0 ; ; )
{
// 全スレッドが終了していたら、ループを抜ける。
// If all threads have finished, exit the loop.
if (threads_done())
break;
sleep(1000);
// callback_secondsごとにcallback_func()が呼び出される。
// callback_func() is called every callback_seconds.
if (++i == callback_seconds)
{
do_a_callback();
// ↑から戻ってきてからカウンターをリセットしているので、
// do_a_callback()のなかでsave()などにどれだけ時間がかかろうと
// 次に呼び出すのは、そこから一定時間の経過を要する。
// Since I am returning from ↑, I reset the counter, so
// no matter how long it takes to save() etc. in do_a_callback()
// The next call will take a certain amount of time.
i = 0;
}
}
// 最後の保存。
// Last save.
std::cout << std::endl << "finalize..";
// do_a_callback();
// → 呼び出し元で保存するはずで、ここでは要らない気がする。
// → It should be saved by the caller, so I feel that it is not necessary here.
// 終了したフラグは立っているがスレッドの終了コードの実行中であるということはありうるので
// join()でその終了を待つ必要がある。
// It is possible that the exit code of the thread is running but the exit code of the thread is running, so
// We need to wait for the end with join().
for (auto& th : threads)
th.join();
// 全スレッドが終了しただけでfileの書き出しスレッドなどはまだ動いていて
// 作業自体は完了していない可能性があるのでスレッドがすべて終了したことだけ出力する。
// The file writing thread etc. are still running only when all threads are finished
// Since the work itself may not have completed, output only that all threads have finished.
std::cout << "all threads are joined." << std::endl;
// Optionsを書き換えたので復元。
// 値を代入しないとハンドラが起動しないのでこうやって復元する。
// Restored because Options were rewritten.
// Restore the handler because the handler will not start unless you assign a value.
for (auto& s : oldOptions)
Options[s.first] = std::string(s.second);
}
#endif // defined(EVAL_LEARN)
#endif // defined(EVAL_LEARN)

View file

@ -11,9 +11,9 @@
#include <atomic>
// 棋譜からの学習や、自ら思考させて定跡を生成するときなど、
// 複数スレッドが個別にSearch::think()を呼び出したいときに用いるヘルパクラス。
// このクラスを派生させて用いる。
// Learning from a game record, when making yourself think and generating a fixed track, etc.
// Helper class used when multiple threads want to call Search::think() individually.
// Derive and use this class.
struct MultiThink
{
MultiThink() : prng(21120903)
@ -21,43 +21,43 @@ struct MultiThink
loop_count = 0;
}
// マスタースレッドからこの関数を呼び出すと、スレッドがそれぞれ思考して、
// 思考終了条件を満たしたところで制御を返す。
// 他にやってくれること。
// ・各スレッドがLearner::search(),qsearch()を呼び出しても安全なように
//  置換表をスレッドごとに分離してくれる。(終了後、元に戻してくれる。)
// ・bookはon the flyモードだとthread safeではないので、このモードを一時的に
//  オフにしてくれる。
// [要件]
// 1) thread_worker()のオーバーライド
// 2) set_loop_max()でループ回数の設定
// 3) 定期的にcallbackされる関数を設定する(必要なら)
// callback_funcとcallback_interval
// Call this function from the master thread, each thread will think,
// Return control when the thought ending condition is satisfied.
// Do something else.
// ・It is safe for each thread to call Learner::search(),qsearch()
// Separates the substitution table for each thread. (It will be restored after the end.)
// ・Book is not thread safe when in on the fly mode, so temporarily change this mode.
// Turn it off.
// [Requirements]
// 1) Override thread_worker()
// 2) Set the loop count with set_loop_max()
// 3) set a function to be called back periodically (if necessary)
// callback_func and callback_interval
void go_think();
// 派生クラス側で初期化したいものがあればこれをoverrideしておけば、
// go_think()で初期化が終わったタイミングで呼び出される。
// 定跡の読み込みなどはそのタイミングで行うと良い。
// If there is something you want to initialize on the derived class side, override this,
// Called when initialization is completed with go_think().
// It is better to read the fixed trace at that timing.
virtual void init() {}
// go_think()したときにスレッドを生成して呼び出されるthread worker
// これをoverrideして用いる。
// A thread worker that is called by creating a thread when you go_think()
// Override and use this.
virtual void thread_worker(size_t thread_id) = 0;
// go_think()したときにcallback_seconds[秒]ごとにcallbackされる。
// Called back every callback_seconds [seconds] when go_think().
std::function<void()> callback_func;
uint64_t callback_seconds = 600;
// workerが処理する(Search::think()を呼び出す)回数を設定する。
// Set the number of times worker processes (calls Search::think()).
void set_loop_max(uint64_t loop_max_) { loop_max = loop_max_; }
// set_loop_max()で設定した値を取得する。
// Get the value set by set_loop_max().
uint64_t get_loop_max() const { return loop_max; }
// [ASYNC] ループカウンターの値を取り出して、取り出し後にループカウンターを加算する。
// もしループカウンターがloop_maxに達していたらUINT64_MAXを返す。
// 局面を生成する場合などは、局面を生成するタイミングでこの関数を呼び出すようにしないと、
// 生成した局面数と、カウンターの値が一致しなくなってしまうので注意すること。
// [ASYNC] Take the value of the loop counter and add the loop counter after taking it out.
// If the loop counter has reached loop_max, return UINT64_MAX.
// If you want to generate a phase, you must call this function at the time of generating the phase,
// Please note that the number of generated phases and the value of the counter will not match.
uint64_t get_next_loop_count() {
std::unique_lock<std::mutex> lk(loop_mutex);
if (loop_count >= loop_max)
@ -65,46 +65,46 @@ struct MultiThink
return loop_count++;
}
// [ASYNC] 処理した個数を返す用。呼び出されるごとにインクリメントされたカウンターが返る。
// [ASYNC] For returning the processed number. Each time it is called, it returns a counter that is incremented.
uint64_t get_done_count() {
std::unique_lock<std::mutex> lk(loop_mutex);
return ++done_count;
}
// worker threadがI/Oにアクセスするときのmutex
// Mutex when worker thread accesses I/O
std::mutex io_mutex;
protected:
// 乱数発生器本体
// Random number generator body
AsyncPRNG prng;
private:
// workerが処理する(Search::think()を呼び出す)回数
// number of times worker processes (calls Search::think())
std::atomic<uint64_t> loop_max;
// workerが処理した(Search::think()を呼び出した)回数
// number of times the worker has processed (calls Search::think())
std::atomic<uint64_t> loop_count;
// 処理した回数を返す用。
// To return the number of times it has been processed.
std::atomic<uint64_t> done_count;
// ↑の変数を変更するときのmutex
// Mutex when changing the variables in ↑
std::mutex loop_mutex;
// スレッドの終了フラグ。
// vector<bool>にすると複数スレッドから書き換えようとしたときに正しく反映されないことがある…はず。
// Thread end flag.
// vector<bool> may not be reflected properly when trying to rewrite from multiple threads...
typedef uint8_t Flag;
std::vector<Flag> thread_finished;
};
// idle時間にtaskを処理する仕組み。
// masterは好きなときにpush_task_async()でtaskを渡す。
// slaveは暇なときにon_idle()を実行すると、taskを一つ取り出してqueueがなくなるまで実行を続ける。
// MultiThinkのthread workerをmaster-slave方式で書きたいときに用いると便利。
// Mechanism to process task during idle time.
// master passes the task with push_task_async() whenever you like.
// When slave executes on_idle() in its spare time, it retrieves one task and continues execution until there is no queue.
// Convenient to use when you want to write MultiThink thread worker in master-slave method.
struct TaskDispatcher
{
typedef std::function<void(size_t /* thread_id */)> Task;
// slaveはidle中にこの関数を呼び出す。
// slave calls this function during idle.
void on_idle(size_t thread_id)
{
Task task;
@ -114,24 +114,24 @@ struct TaskDispatcher
sleep(1);
}
// [ASYNC] taskを一つ積む。
// Stack [ASYNC] task.
void push_task_async(Task task)
{
std::unique_lock<std::mutex> lk(task_mutex);
tasks.push_back(task);
}
// task用の配列の要素をsize分だけ事前に確保する。
// Allocate size array elements for task in advance.
void task_reserve(size_t size)
{
tasks.reserve(size);
}
protected:
// taskの集合
// set of tasks
std::vector<Task> tasks;
// [ASYNC] taskを一つ取り出す。on_idle()から呼び出される。
// Take out one [ASYNC] task. Called from on_idle().
Task get_task_async()
{
std::unique_lock<std::mutex> lk(task_mutex);
@ -142,10 +142,10 @@ protected:
return task;
}
// tasksにアクセスするとき用のmutex
// a mutex for accessing tasks
std::mutex task_mutex;
};
#endif // defined(EVAL_LEARN) && defined(YANEURAOU_2018_OTAFUKU_ENGINE)
#endif
#endif