diff --git a/src/eval/evaluate_common.h b/src/eval/evaluate_common.h index 5d5d05b1..84a96bee 100644 --- a/src/eval/evaluate_common.h +++ b/src/eval/evaluate_common.h @@ -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 -// 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::functionf, 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& 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& 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& 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 diff --git a/src/eval/evaluate_mir_inv_tools.cpp b/src/eval/evaluate_mir_inv_tools.cpp index 56a0a63e..3b5d3a36 100644 --- a/src/eval/evaluate_mir_inv_tools.cpp +++ b/src/eval/evaluate_mir_inv_tools.cpp @@ -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 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 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 s; vector 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]); diff --git a/src/eval/evaluate_mir_inv_tools.h b/src/eval/evaluate_mir_inv_tools.h index 8d6378ec..fa4e70ac 100644 --- a/src/eval/evaluate_mir_inv_tools.h +++ b/src/eval/evaluate_mir_inv_tools.h @@ -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 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 \ No newline at end of file diff --git a/src/eval/nnue/architectures/halfkp-cr-ep_256x2-32-32.h b/src/eval/nnue/architectures/halfkp-cr-ep_256x2-32-32.h index 9f1f97c0..1bb9609e 100644 --- a/src/eval/nnue/architectures/halfkp-cr-ep_256x2-32-32.h +++ b/src/eval/nnue/architectures/halfkp-cr-ep_256x2-32-32.h @@ -1,4 +1,4 @@ -// NNUE]֐ŗp͓ʂƃlbg[N\̒` +// 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 { - // ]֐ŗp͓ + // Input features used in evaluation function using RawFeatures = Features::FeatureSet< Features::HalfKP, Features::CastlingRight, Features::EnPassant>; - // ϊ͓̓ʂ̎ + // Number of input feature dimensions after conversion constexpr IndexType kTransformedFeatureDimensions = 256; namespace Layers { - // lbg[N\̒` + // define network structure using InputLayer = InputSlice; using HiddenLayer1 = ClippedReLU>; using HiddenLayer2 = ClippedReLU>; diff --git a/src/eval/nnue/architectures/halfkp_256x2-32-32.h b/src/eval/nnue/architectures/halfkp_256x2-32-32.h index c79747c3..467d0222 100644 --- a/src/eval/nnue/architectures/halfkp_256x2-32-32.h +++ b/src/eval/nnue/architectures/halfkp_256x2-32-32.h @@ -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>; -// 変換後の入力特徴量の次元数 +// Number of input feature dimensions after conversion constexpr IndexType kTransformedFeatureDimensions = 256; namespace Layers { -// ネットワーク構造の定義 +// define network structure using InputLayer = InputSlice; using HiddenLayer1 = ClippedReLU>; using HiddenLayer2 = ClippedReLU>; diff --git a/src/eval/nnue/architectures/k-p-cr-ep_256x2-32-32.h b/src/eval/nnue/architectures/k-p-cr-ep_256x2-32-32.h index dc761866..72531fd4 100644 --- a/src/eval/nnue/architectures/k-p-cr-ep_256x2-32-32.h +++ b/src/eval/nnue/architectures/k-p-cr-ep_256x2-32-32.h @@ -1,4 +1,4 @@ -// NNUE]֐ŗp͓ʂƃlbg[N\̒` +// 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 { - // ]֐ŗp͓ + // Input features used in evaluation function using RawFeatures = Features::FeatureSet; - // ϊ͓̓ʂ̎ + // Number of input feature dimensions after conversion constexpr IndexType kTransformedFeatureDimensions = 256; namespace Layers { - // lbg[N\̒` + // define network structure using InputLayer = InputSlice; using HiddenLayer1 = ClippedReLU>; using HiddenLayer2 = ClippedReLU>; diff --git a/src/eval/nnue/architectures/k-p-cr_256x2-32-32.h b/src/eval/nnue/architectures/k-p-cr_256x2-32-32.h index 331cb4f2..b4161880 100644 --- a/src/eval/nnue/architectures/k-p-cr_256x2-32-32.h +++ b/src/eval/nnue/architectures/k-p-cr_256x2-32-32.h @@ -1,4 +1,4 @@ -// NNUE]֐ŗp͓ʂƃlbg[N\̒` +// 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 { - // ]֐ŗp͓ + // Input features used in evaluation function using RawFeatures = Features::FeatureSet; - // ϊ͓̓ʂ̎ + // Number of input feature dimensions after conversion constexpr IndexType kTransformedFeatureDimensions = 256; namespace Layers { - // lbg[N\̒` + // define network structure using InputLayer = InputSlice; using HiddenLayer1 = ClippedReLU>; using HiddenLayer2 = ClippedReLU>; diff --git a/src/eval/nnue/architectures/k-p_256x2-32-32.h b/src/eval/nnue/architectures/k-p_256x2-32-32.h index 2576ddfa..9fc9b2a1 100644 --- a/src/eval/nnue/architectures/k-p_256x2-32-32.h +++ b/src/eval/nnue/architectures/k-p_256x2-32-32.h @@ -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; -// 変換後の入力特徴量の次元数 +// Number of input feature dimensions after conversion constexpr IndexType kTransformedFeatureDimensions = 256; namespace Layers { -// ネットワーク構造の定義 +// define network structure using InputLayer = InputSlice; using HiddenLayer1 = ClippedReLU>; using HiddenLayer2 = ClippedReLU>; diff --git a/src/eval/nnue/evaluate_nnue.cpp b/src/eval/nnue/evaluate_nnue.cpp index 46b3b5f9..6b3f0b2f 100644 --- a/src/eval/nnue/evaluate_nnue.cpp +++ b/src/eval/nnue/evaluate_nnue.cpp @@ -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 feature_transformer; -// 評価関数 +// Evaluation function AlignedPtr 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 void Initialize(AlignedPtr& pointer) { pointer.reset(reinterpret_cast(aligned_malloc(sizeof(T), alignof(T)))); std::memset(pointer.get(), 0, sizeof(T)); } -// 評価関数パラメータを読み込む +// read evaluation function parameters template bool ReadParameters(std::istream& stream, const AlignedPtr& pointer) { std::uint32_t header; @@ -51,7 +51,7 @@ bool ReadParameters(std::istream& stream, const AlignedPtr& pointer) { return pointer->ReadParameters(stream); } -// 評価関数パラメータを書き込む +// write evaluation function parameters template bool WriteParameters(std::ostream& stream, const AlignedPtr& pointer) { constexpr std::uint32_t header = T::GetHashValue(); @@ -61,7 +61,7 @@ bool WriteParameters(std::ostream& stream, const AlignedPtr& 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(&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(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 struct HashTable { HashTable() { clear(); } T* operator [] (const Key k) { return entries_ + (static_cast(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 {}; #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 {}; #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; } diff --git a/src/eval/nnue/evaluate_nnue.h b/src/eval/nnue/evaluate_nnue.h index a95f2bd9..7f8f700a 100644 --- a/src/eval/nnue/evaluate_nnue.h +++ b/src/eval/nnue/evaluate_nnue.h @@ -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 struct AlignedDeleter { void operator()(T* ptr) const { @@ -29,30 +29,30 @@ struct AlignedDeleter { template using AlignedPtr = std::unique_ptr>; -// 入力特徴量変換器 +// Input feature converter extern AlignedPtr feature_transformer; -// 評価関数 +// Evaluation function extern AlignedPtr 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 \ No newline at end of file diff --git a/src/eval/nnue/evaluate_nnue_learner.cpp b/src/eval/nnue/evaluate_nnue_learner.cpp index 636f90e1..0a2077a7 100644 --- a/src/eval/nnue/evaluate_nnue_learner.cpp +++ b/src/eval/nnue/evaluate_nnue_learner.cpp @@ -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 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; -// 学習率のスケール +// 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 messages) { for (auto& message : messages) { trainer->SendMessage(&message); @@ -64,7 +64,7 @@ void SendMessages(std::vector 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 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; } diff --git a/src/eval/nnue/evaluate_nnue_learner.h b/src/eval/nnue/evaluate_nnue_learner.h index e2e68738..932a5f8c 100644 --- a/src/eval/nnue/evaluate_nnue_learner.h +++ b/src/eval/nnue/evaluate_nnue_learner.h @@ -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 \ No newline at end of file diff --git a/src/eval/nnue/features/castling_right.cpp b/src/eval/nnue/features/castling_right.cpp index 30e46e23..ee7b6576 100644 --- a/src/eval/nnue/features/castling_right.cpp +++ b/src/eval/nnue/features/castling_right.cpp @@ -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 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) { diff --git a/src/eval/nnue/features/castling_right.h b/src/eval/nnue/features/castling_right.h index 1384865f..f585b1d7 100644 --- a/src/eval/nnue/features/castling_right.h +++ b/src/eval/nnue/features/castling_right.h @@ -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 { - // KFʂ̈ʒu + // Feature K: Ball position class CastlingRight { public: - // ʖ + // feature quantity name static constexpr const char* kName = "CastlingRight"; - // ]֐t@CɖߍރnbVl + // Hash value embedded in the evaluation function file static constexpr std::uint32_t kHashValue = 0x913968AAu; - // ʂ̎ + // number of feature dimensions static constexpr IndexType kDimensions = 4; - // ʂ̂Aɒl1ƂȂCfbNX̐̍ől + // 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; - // vZ̑ɑSvZs^C~O + // Timing of full calculation instead of difference calculation static constexpr TriggerEvent kRefreshTrigger = TriggerEvent::kNone; - // ʂ̂Al1łCfbNX̃Xg擾 + // Get a list of indices with a value of 1 among the features static void AppendActiveIndices(const Position& pos, Color perspective, IndexList* active); - // ʂ̂AOlωCfbNX̃Xg擾 + // 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 \ No newline at end of file diff --git a/src/eval/nnue/features/enpassant.cpp b/src/eval/nnue/features/enpassant.cpp index 523fd966..82a4158e 100644 --- a/src/eval/nnue/features/enpassant.cpp +++ b/src/eval/nnue/features/enpassant.cpp @@ -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 { - // ʂ̂Al1łCfbNX̃Xg擾 + // Get a list of indices with a value of 1 among the features void EnPassant::AppendActiveIndices( const Position& pos, Color perspective, IndexList* active) { - // RpČx邽߁AzTCYꍇ͉Ȃ + // 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); } - // ʂ̂AOlωCfbNX̃Xg擾 + // 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) { diff --git a/src/eval/nnue/features/enpassant.h b/src/eval/nnue/features/enpassant.h index fe827584..c0ac8234 100644 --- a/src/eval/nnue/features/enpassant.h +++ b/src/eval/nnue/features/enpassant.h @@ -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 { - // KFʂ̈ʒu + // Feature K: Ball position class EnPassant { public: - // ʖ + // feature quantity name static constexpr const char* kName = "EnPassant"; - // ]֐t@CɖߍރnbVl + // Hash value embedded in the evaluation function file static constexpr std::uint32_t kHashValue = 0x02924F91u; - // ʂ̎ + // number of feature dimensions static constexpr IndexType kDimensions = 8; - // ʂ̂Aɒl1ƂȂCfbNX̐̍ől + // 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; - // vZ̑ɑSvZs^C~O + // Timing of full calculation instead of difference calculation static constexpr TriggerEvent kRefreshTrigger = TriggerEvent::kAnyPieceMoved; - // ʂ̂Al1łCfbNX̃Xg擾 + // Get a list of indices with a value of 1 among the features static void AppendActiveIndices(const Position& pos, Color perspective, IndexList* active); - // ʂ̂AOlωCfbNX̃Xg擾 + // 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 \ No newline at end of file diff --git a/src/eval/nnue/features/feature_set.h b/src/eval/nnue/features/feature_set.h index 919be65d..6190db04 100644 --- a/src/eval/nnue/features/feature_set.h +++ b/src/eval/nnue/features/feature_set.h @@ -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 struct CompileTimeList; template @@ -36,7 +36,7 @@ struct CompileTimeList { static constexpr std::array kValues = {{}}; }; -// リストの先頭への追加を行うクラステンプレート +// Class template that adds to the beginning of the list template struct AppendToList; template @@ -44,7 +44,7 @@ struct AppendToList, AnotherValue> { using Result = CompileTimeList; }; -// ソートされた重複のないリストへの追加を行うクラステンプレート +// Class template for adding to a sorted, unique list template struct InsertToSet; template @@ -52,7 +52,7 @@ struct InsertToSet, AnotherValue> { using Result = std::conditional_t< CompileTimeList::Contains(AnotherValue), CompileTimeList, - std::conditional_t<(AnotherValue < First), + std::conditional_t<(AnotherValue , typename AppendToList, AnotherValue>::Result, @@ -63,21 +63,21 @@ struct InsertToSet, Value> { using Result = CompileTimeList; }; -// 特徴量セットの基底クラス +// Base class of feature set template class FeatureSetBase { public: - // 特徴量のうち、値が1であるインデックスのリストを取得する + // Get a list of indices with a value of 1 among the features template 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 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 class FeatureSet : public FeatureSetBase< @@ -131,27 +131,27 @@ class FeatureSet : using Tail = FeatureSet; 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::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 static void CollectActiveIndices( const Position& pos, const TriggerEvent trigger, const Color perspective, @@ -166,7 +166,7 @@ class FeatureSet : } } - // 特徴量のうち、一手前から値が変化したインデックスのリストを取得する + // Get a list of indices whose values ​​have changed from the previous one in the feature quantity template static void CollectChangedIndices( const Position& pos, const TriggerEvent trigger, const Color perspective, @@ -185,36 +185,36 @@ class FeatureSet : } } - // 基底クラスと、自身を再帰的に利用するクラステンプレートをfriendにする + // Make the base class and the class template that recursively uses itself a friend friend class FeatureSetBase; template friend class FeatureSet; }; -// 特徴量セットを表すクラステンプレート -// テンプレート引数が1つの場合の特殊化 +// Class template that represents the feature set +// Specialization with one template argument template class FeatureSet : public FeatureSetBase> { 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; 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 : public FeatureSetBase> { } } - // 特徴量のうち、一手前から値が変化したインデックスのリストを取得する + // 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 : public FeatureSetBase> { } } - // 基底クラスと、自身を再帰的に利用するクラステンプレートをfriendにする + // Make the base class and the class template that recursively uses itself a friend friend class FeatureSetBase; template friend class FeatureSet; @@ -246,4 +246,4 @@ class FeatureSet : public FeatureSetBase> { #endif // defined(EVAL_NNUE) -#endif +#endif \ No newline at end of file diff --git a/src/eval/nnue/features/features_common.h b/src/eval/nnue/features/features_common.h index 15ccb8a7..0031d37b 100644 --- a/src/eval/nnue/features/features_common.h +++ b/src/eval/nnue/features/features_common.h @@ -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 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 \ No newline at end of file diff --git a/src/eval/nnue/features/half_kp.cpp b/src/eval/nnue/features/half_kp.cpp index 5cd95637..72156c82 100644 --- a/src/eval/nnue/features/half_kp.cpp +++ b/src/eval/nnue/features/half_kp.cpp @@ -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 inline IndexType HalfKP::MakeIndex(Square sq_k, BonaPiece p) { return static_cast(fe_end) * static_cast(sq_k) + p; } -// 駒の情報を取得する +// Get the piece information template inline void HalfKP::GetPieces( const Position& pos, Color perspective, @@ -31,7 +31,7 @@ inline void HalfKP::GetPieces( *sq_target_k = static_cast(((*pieces)[target] - f_king) % SQUARE_NB); } -// 特徴量のうち、値が1であるインデックスのリストを取得する +// Get a list of indices with a value of 1 among the features template void HalfKP::AppendActiveIndices( const Position& pos, Color perspective, IndexList* active) { @@ -48,7 +48,7 @@ void HalfKP::AppendActiveIndices( } } -// 特徴量のうち、一手前から値が変化したインデックスのリストを取得する +// Get a list of indices whose values ​​have changed from the previous one in the feature quantity template void HalfKP::AppendChangedIndices( const Position& pos, Color perspective, diff --git a/src/eval/nnue/features/half_kp.h b/src/eval/nnue/features/half_kp.h index 556127d3..65ea46f1 100644 --- a/src/eval/nnue/features/half_kp.h +++ b/src/eval/nnue/features/half_kp.h @@ -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 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(SQUARE_NB) * static_cast(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 \ No newline at end of file diff --git a/src/eval/nnue/features/half_relative_kp.cpp b/src/eval/nnue/features/half_relative_kp.cpp index d62beea0..623b839c 100644 --- a/src/eval/nnue/features/half_relative_kp.cpp +++ b/src/eval/nnue/features/half_relative_kp.cpp @@ -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 inline IndexType HalfRelativeKP::MakeIndex( Square sq_k, BonaPiece p) { @@ -24,7 +24,7 @@ inline IndexType HalfRelativeKP::MakeIndex( return H * W * piece_index + H * relative_file + relative_rank; } -// 駒の情報を取得する +// Get the piece information template inline void HalfRelativeKP::GetPieces( const Position& pos, Color perspective, @@ -38,11 +38,11 @@ inline void HalfRelativeKP::GetPieces( *sq_target_k = static_cast(((*pieces)[target] - f_king) % SQUARE_NB); } -// 特徴量のうち、値が1であるインデックスのリストを取得する +// Get a list of indices with a value of 1 among the features template void HalfRelativeKP::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::AppendActiveIndices( } } -// 特徴量のうち、一手前から値が変化したインデックスのリストを取得する +// Get a list of indices whose values ​​have changed from the previous one in the feature quantity template void HalfRelativeKP::AppendChangedIndices( const Position& pos, Color perspective, diff --git a/src/eval/nnue/features/half_relative_kp.h b/src/eval/nnue/features/half_relative_kp.h index 99e10c57..f6ca5cc0 100644 --- a/src/eval/nnue/features/half_relative_kp.h +++ b/src/eval/nnue/features/half_relative_kp.h @@ -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 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 \ No newline at end of file diff --git a/src/eval/nnue/features/index_list.h b/src/eval/nnue/features/index_list.h index a5a71011..90317b4c 100644 --- a/src/eval/nnue/features/index_list.h +++ b/src/eval/nnue/features/index_list.h @@ -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 class ValueList { public: @@ -39,7 +39,7 @@ class ValueList { std::size_t size_ = 0; }; -// 特徴量のインデックスリストの型 +//Type of feature index list class IndexList : public ValueList { }; @@ -52,4 +52,4 @@ class IndexList #endif // defined(EVAL_NNUE) -#endif +#endif \ No newline at end of file diff --git a/src/eval/nnue/features/k.cpp b/src/eval/nnue/features/k.cpp index 03f66ff5..dc01eb92 100644 --- a/src/eval/nnue/features/k.cpp +++ b/src/eval/nnue/features/k.cpp @@ -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) { diff --git a/src/eval/nnue/features/k.h b/src/eval/nnue/features/k.h index 1a01c471..0930c160 100644 --- a/src/eval/nnue/features/k.h +++ b/src/eval/nnue/features/k.h @@ -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 \ No newline at end of file diff --git a/src/eval/nnue/features/p.cpp b/src/eval/nnue/features/p.cpp index 56bca0a4..68527119 100644 --- a/src/eval/nnue/features/p.cpp +++ b/src/eval/nnue/features/p.cpp @@ -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) { diff --git a/src/eval/nnue/features/p.h b/src/eval/nnue/features/p.h index 77ea882d..ded678a5 100644 --- a/src/eval/nnue/features/p.h +++ b/src/eval/nnue/features/p.h @@ -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 \ No newline at end of file diff --git a/src/eval/nnue/layers/affine_transform.h b/src/eval/nnue/layers/affine_transform.h index d8101ba4..99dae0fe 100644 --- a/src/eval/nnue/layers/affine_transform.h +++ b/src/eval/nnue/layers/affine_transform.h @@ -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 class AffineTransform { public: - // 入出力の型 + // Input/output type using InputType = typename PreviousLayer::OutputType; using OutputType = std::int32_t; static_assert(std::is_same::value, ""); - // 入出力の次元数 + // number of input/output dimensions static constexpr IndexType kInputDimensions = PreviousLayer::kOutputDimensions; static constexpr IndexType kOutputDimensions = OutputDimensions; static constexpr IndexType kPaddedInputDimensions = CeilToMultiple(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(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(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; - // この層の直前の層 + // 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 \ No newline at end of file diff --git a/src/eval/nnue/layers/clipped_relu.h b/src/eval/nnue/layers/clipped_relu.h index 5877fc32..1b7e8fc1 100644 --- a/src/eval/nnue/layers/clipped_relu.h +++ b/src/eval/nnue/layers/clipped_relu.h @@ -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 class ClippedReLU { public: - // 入出力の型 + // Input/output type using InputType = typename PreviousLayer::OutputType; using OutputType = std::uint8_t; static_assert(std::is_same::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; - // この層の直前の層 + // the layer immediately before this layer PreviousLayer previous_layer_; }; @@ -165,4 +165,4 @@ class ClippedReLU { #endif // defined(EVAL_NNUE) -#endif +#endif \ No newline at end of file diff --git a/src/eval/nnue/layers/input_slice.h b/src/eval/nnue/layers/input_slice.h index c9c6a7c9..0497e769 100644 --- a/src/eval/nnue/layers/input_slice.h +++ b/src/eval/nnue/layers/input_slice.h @@ -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 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 \ No newline at end of file diff --git a/src/eval/nnue/layers/sum.h b/src/eval/nnue/layers/sum.h index 3fe000cf..c64852a1 100644 --- a/src/eval/nnue/layers/sum.h +++ b/src/eval/nnue/layers/sum.h @@ -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 class Sum : public Sum { private: @@ -21,25 +21,25 @@ class Sum : public Sum { using Tail = Sum; public: - // 入出力の型 + // Input/output type using InputType = typename Head::OutputType; using OutputType = InputType; static_assert(std::is_same::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 { 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(buffer); - for (IndexType i = 0; i < kOutputDimensions; ++i) { + for (IndexType i = 0; i ; - // この層の直前の層 + // 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 class Sum { 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 { 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; - // この層の直前の層 + // the layer immediately before this layer PreviousLayer previous_layer_; }; @@ -160,4 +160,4 @@ class Sum { #endif // defined(EVAL_NNUE) -#endif +#endif \ No newline at end of file diff --git a/src/eval/nnue/nnue_accumulator.h b/src/eval/nnue/nnue_accumulator.h index 4241edb3..e480526b 100644 --- a/src/eval/nnue/nnue_accumulator.h +++ b/src/eval/nnue/nnue_accumulator.h @@ -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 \ No newline at end of file diff --git a/src/eval/nnue/nnue_architecture.h b/src/eval/nnue/nnue_architecture.h index 7479ac0a..aa4e8c7f 100644 --- a/src/eval/nnue/nnue_architecture.h +++ b/src/eval/nnue/nnue_architecture.h @@ -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::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 \ No newline at end of file diff --git a/src/eval/nnue/nnue_common.h b/src/eval/nnue/nnue_common.h index b82bc2c2..bb52bdfe 100644 --- a/src/eval/nnue/nnue_common.h +++ b/src/eval/nnue/nnue_common.h @@ -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 class Trainer; -// n以上で最小のbaseの倍数を求める +// find the smallest multiple of n and above template constexpr IntType CeilToMultiple(IntType n, IntType base) { return (n + base - 1) / base * base; diff --git a/src/eval/nnue/nnue_feature_transformer.h b/src/eval/nnue/nnue_feature_transformer.h index 57d25310..039a0b98 100644 --- a/src/eval/nnue/nnue_feature_transformer.h +++ b/src/eval/nnue/nnue_feature_transformer.h @@ -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(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(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; - // パラメータ + // parameter alignas(kCacheLineSize) BiasType biases_[kHalfDimensions]; alignas(kCacheLineSize) WeightType weights_[kHalfDimensions * kInputDimensions]; @@ -344,4 +344,4 @@ class FeatureTransformer { #endif // defined(EVAL_NNUE) -#endif +#endif \ No newline at end of file diff --git a/src/eval/nnue/nnue_test_command.cpp b/src/eval/nnue/nnue_test_command.cpp index 28e44273..46bc97de 100644 --- a/src/eval/nnue/nnue_test_command.cpp +++ b/src/eval/nnue/nnue_test_command.cpp @@ -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 mg(pos); // 全合法手の生成 + MoveList 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; diff --git a/src/eval/nnue/nnue_test_command.h b/src/eval/nnue/nnue_test_command.h index 10f57f6c..570ef01b 100644 --- a/src/eval/nnue/nnue_test_command.h +++ b/src/eval/nnue/nnue_test_command.h @@ -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 diff --git a/src/eval/nnue/trainer/features/factorizer.h b/src/eval/nnue/trainer/features/factorizer.h index 3bc59260..dea95370 100644 --- a/src/eval/nnue/trainer/features/factorizer.h +++ b/src/eval/nnue/trainer/features/factorizer.h @@ -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 class Factorizer { public: - // 学習用特徴量の次元数を取得する + // Get the dimensionality of the learning feature static constexpr IndexType GetDimensions() { return FeatureType::kDimensions; } - // 学習用特徴量のインデックスと学習率のスケールを取得する + // Get index of learning feature and scale of learning rate static void AppendTrainingFeatures( IndexType base_index, std::vector* training_features) { - assert(base_index < FeatureType::kDimensions); + assert(base_index emplace_back(base_index); } }; -// 学習用特徴量の情報 +// Learning feature information struct FeatureProperties { bool active; IndexType dimensions; }; -// 元の入力特徴量を学習用特徴量に追加する +// Add the original input features to the learning features template IndexType AppendBaseFeature( FeatureProperties properties, IndexType base_index, @@ -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 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 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 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 \ No newline at end of file diff --git a/src/eval/nnue/trainer/features/factorizer_feature_set.h b/src/eval/nnue/trainer/features/factorizer_feature_set.h index 111678e4..0afe7a48 100644 --- a/src/eval/nnue/trainer/features/factorizer_feature_set.h +++ b/src/eval/nnue/trainer/features/factorizer_feature_set.h @@ -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 class Factorizer> { private: @@ -23,16 +23,16 @@ class Factorizer> { using Tail = Factorizer>; public: - // 元の入力特徴量の次元数 + // number of dimensions of original input features static constexpr IndexType kBaseDimensions = FeatureSet::kDimensions; - // 学習用特徴量の次元数を取得する + // Get the dimensionality of the learning feature static constexpr IndexType GetDimensions() { return Head::GetDimensions() + Tail::GetDimensions(); } - // 学習用特徴量のインデックスと学習率のスケールを取得する + // Get index of learning feature and scale of learning rate static void AppendTrainingFeatures( IndexType base_index, std::vector* training_features, IndexType base_dimensions = kBaseDimensions) { @@ -62,20 +62,20 @@ class Factorizer> { } }; -// 入力特徴量を学習用特徴量に変換するクラステンプレート -// FeatureSetのテンプレート引数が1つの場合の特殊化 +// Class template that converts input features into learning features +// Specialization when FeatureSet has one template argument template class Factorizer> { public: - // 元の入力特徴量の次元数 + // number of dimensions of original input features static constexpr IndexType kBaseDimensions = FeatureType::kDimensions; - // 学習用特徴量の次元数を取得する + // Get the dimensionality of the learning feature static constexpr IndexType GetDimensions() { return Factorizer::GetDimensions(); } - // 学習用特徴量のインデックスと学習率のスケールを取得する + // Get index of learning feature and scale of learning rate static void AppendTrainingFeatures( IndexType base_index, std::vector* training_features, IndexType base_dimensions = kBaseDimensions) { @@ -101,4 +101,4 @@ public: #endif // defined(EVAL_NNUE) -#endif +#endif \ No newline at end of file diff --git a/src/eval/nnue/trainer/features/factorizer_half_kp.h b/src/eval/nnue/trainer/features/factorizer_half_kp.h index 28c11074..6ce5854a 100644 --- a/src/eval/nnue/trainer/features/factorizer_half_kp.h +++ b/src/eval/nnue/trainer/features/factorizer_half_kp.h @@ -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 class Factorizer> { private: using FeatureType = HalfKP; - // 特徴量のうち、同時に値が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> { kNumTrainingFeatureTypes, }; - // 学習用特徴量の情報 + // Learning feature information static constexpr FeatureProperties kProperties[] = { // kFeaturesHalfKP {true, FeatureType::kDimensions}, @@ -50,12 +50,12 @@ class Factorizer> { 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* training_features) { // kFeaturesHalfKP @@ -100,4 +100,4 @@ constexpr FeatureProperties Factorizer>::kProperties[]; #endif // defined(EVAL_NNUE) -#endif +#endif \ No newline at end of file diff --git a/src/eval/nnue/trainer/trainer.h b/src/eval/nnue/trainer/trainer.h index 630f1a3d..f50ce092 100644 --- a/src/eval/nnue/trainer/trainer.h +++ b/src/eval/nnue/trainer/trainer.h @@ -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::value, ""); @@ -60,7 +60,7 @@ class TrainingFeature { StorageType index_and_count_; }; -// 学習データ1サンプルを表す構造体 +// Structure that represents one sample of training data struct Example { std::vector 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 Split(const std::string& input, char delimiter) { std::istringstream stream(input); std::string field; @@ -102,13 +102,13 @@ std::vector Split(const std::string& input, char delimiter) { return fields; } -// 浮動小数点数を整数に丸める +// round a floating point number to an integer template IntType Round(double value) { return static_cast(std::floor(value + 0.5)); } -// アライメント付きmake_shared +// make_shared with alignment template std::shared_ptr MakeAlignedSharedPtr(ArgumentTypes&&... arguments) { const auto ptr = new(aligned_malloc(sizeof(T), alignof(T))) @@ -122,4 +122,4 @@ std::shared_ptr MakeAlignedSharedPtr(ArgumentTypes&&... arguments) { #endif // defined(EVAL_LEARN) && defined(EVAL_NNUE) -#endif +#endif \ No newline at end of file diff --git a/src/eval/nnue/trainer/trainer_affine_transform.h b/src/eval/nnue/trainer/trainer_affine_transform.h index 34c4816b..f5b208a3 100644 --- a/src/eval/nnue/trainer/trainer_affine_transform.h +++ b/src/eval/nnue/trainer/trainer_affine_transform.h @@ -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 class Trainer> { private: - // 学習対象の層の型 + // Type of layer to learn using LayerType = Layers::AffineTransform; public: - // ファクトリ関数 + // factory function static std::shared_ptr Create( LayerType* target_layer, FeatureTransformer* feature_transformer) { return std::shared_ptr( 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> { } } - // パラメータを乱数で初期化する + // Initialize the parameters with random numbers template 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(0.0)); std::fill(std::begin(weights_), std::end(weights_), static_cast(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(0.0, kSigma); for (IndexType i = 0; i < kOutputDimensions; ++i) { @@ -76,7 +76,7 @@ class Trainer> { QuantizeParameters(); } - // 順伝播 + // forward propagation const LearnFloatType* Propagate(const std::vector& batch) { if (output_.size() < kOutputDimensions * batch.size()) { output_.resize(kOutputDimensions * batch.size()); @@ -111,7 +111,7 @@ class Trainer> { return output_.data(); } - // 逆伝播 + // backpropagation void Backpropagate(const LearnFloatType* gradients, LearnFloatType learning_rate) { const LearnFloatType local_learning_rate = @@ -185,7 +185,7 @@ class Trainer> { } private: - // コンストラクタ + // constructor Trainer(LayerType* target_layer, FeatureTransformer* feature_transformer) : batch_size_(0), batch_input_(nullptr), @@ -201,7 +201,7 @@ class Trainer> { 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> { } } - // 整数化されたパラメータの読み込み + // read parameterized integer void DequantizeParameters() { for (IndexType i = 0; i < kOutputDimensions; ++i) { biases_[i] = static_cast( @@ -242,14 +242,14 @@ class Trainer> { static_cast(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::max(); static constexpr LearnFloatType kBiasScale = kIsOutputLayer ? @@ -257,37 +257,37 @@ class Trainer> { ((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::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> 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 output_; - // 逆伝播用バッファ + // buffer for back propagation std::vector gradients_; - // ハイパーパラメータ + // hyper parameter LearnFloatType momentum_; LearnFloatType learning_rate_scale_; }; diff --git a/src/eval/nnue/trainer/trainer_clipped_relu.h b/src/eval/nnue/trainer/trainer_clipped_relu.h index bd894769..7fe1913d 100644 --- a/src/eval/nnue/trainer/trainer_clipped_relu.h +++ b/src/eval/nnue/trainer/trainer_clipped_relu.h @@ -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 class Trainer> { private: - // 学習対象の層の型 + // Type of layer to learn using LayerType = Layers::ClippedReLU; public: - // ファクトリ関数 + // factory function static std::shared_ptr Create( LayerType* target_layer, FeatureTransformer* feature_transformer) { return std::shared_ptr( 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> { } } - // パラメータを乱数で初期化する + // Initialize the parameters with random numbers template void Initialize(RNG& rng) { previous_layer_trainer_->Initialize(rng); } - // 順伝播 + // forward propagation const LearnFloatType* Propagate(const std::vector& batch) { if (output_.size() < kOutputDimensions * batch.size()) { output_.resize(kOutputDimensions * batch.size()); @@ -62,7 +62,7 @@ class Trainer> { 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> { } private: - // コンストラクタ + // constructor Trainer(LayerType* target_layer, FeatureTransformer* feature_transformer) : batch_size_(0), previous_layer_trainer_(Trainer::Create( @@ -89,7 +89,7 @@ class Trainer> { std::numeric_limits::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> { std::numeric_limits::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(0.0); static constexpr LearnFloatType kOne = static_cast(1.0); - // ミニバッチのサンプル数 + // number of samples in mini-batch IndexType batch_size_; - // 直前の層のTrainer + // Trainer of the previous layer const std::shared_ptr> previous_layer_trainer_; - // 学習対象の層 + // layer to learn LayerType* const target_layer_; - // 順伝播用バッファ + // Forward propagation buffer std::vector output_; - // 逆伝播用バッファ + // buffer for back propagation std::vector gradients_; - // ヘルスチェック用統計値 + // Health check statistics LearnFloatType min_activations_[kOutputDimensions]; LearnFloatType max_activations_[kOutputDimensions]; }; @@ -139,4 +139,4 @@ class Trainer> { #endif // defined(EVAL_LEARN) && defined(EVAL_NNUE) -#endif +#endif \ No newline at end of file diff --git a/src/eval/nnue/trainer/trainer_feature_transformer.h b/src/eval/nnue/trainer/trainer_feature_transformer.h index 742da440..eb14d98b 100644 --- a/src/eval/nnue/trainer/trainer_feature_transformer.h +++ b/src/eval/nnue/trainer/trainer_feature_transformer.h @@ -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 { private: - // 学習対象の層の型 + // Type of layer to learn using LayerType = FeatureTransformer; public: @@ -37,12 +37,12 @@ class Trainer { template friend std::shared_ptr MakeAlignedSharedPtr(ArgumentTypes&&... arguments); - // ファクトリ関数 + // factory function static std::shared_ptr Create(LayerType* target_layer) { return MakeAlignedSharedPtr(target_layer); } - // ハイパーパラメータなどのオプションを設定する + // Set options such as hyperparameters void SendMessage(Message* message) { if (ReceiveMessage("momentum", message)) { momentum_ = static_cast(std::stod(message->value)); @@ -65,7 +65,7 @@ class Trainer { } } - // パラメータを乱数で初期化する + // Initialize the parameters with random numbers template void Initialize(RNG& rng) { std::fill(std::begin(weights_), std::end(weights_), +kZero); @@ -81,7 +81,7 @@ class Trainer { QuantizeParameters(); } - // 順伝播 + // forward propagation const LearnFloatType* Propagate(const std::vector& batch) { if (output_.size() < kOutputDimensions * batch.size()) { output_.resize(kOutputDimensions * batch.size()); @@ -131,7 +131,7 @@ class Trainer { return output_.data(); } - // 逆伝播 + // backpropagation void Backpropagate(const LearnFloatType* gradients, LearnFloatType learning_rate) { const LearnFloatType local_learning_rate = @@ -144,8 +144,8 @@ class Trainer { ((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(local_learning_rate / (1.0 - momentum_)); #if defined(USE_BLAS) @@ -227,7 +227,7 @@ class Trainer { } private: - // コンストラクタ + // constructor Trainer(LayerType* target_layer) : batch_(nullptr), target_layer_(target_layer), @@ -245,7 +245,7 @@ class Trainer { DequantizeParameters(); } - // 重みの飽和とパラメータの整数化 + // Weight saturation and parameterization void QuantizeParameters() { for (IndexType i = 0; i < kHalfDimensions; ++i) { target_layer_->biases_[i] = @@ -268,7 +268,7 @@ class Trainer { } } - // 整数化されたパラメータの読み込み + // read parameterized integer void DequantizeParameters() { for (IndexType i = 0; i < kHalfDimensions; ++i) { biases_[i] = static_cast( @@ -282,7 +282,7 @@ class Trainer { 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 { 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 { std::numeric_limits::lowest()); } - // 入出力の次元数 + // number of input/output dimensions static constexpr IndexType kInputDimensions = Features::Factorizer::GetDimensions(); static constexpr IndexType kOutputDimensions = LayerType::kOutputDimensions; static constexpr IndexType kHalfDimensions = LayerType::kHalfDimensions; - // パラメータの整数化で用いる係数 + // Coefficient used for parameterization static constexpr LearnFloatType kActivationScale = std::numeric_limits::max(); static constexpr LearnFloatType kBiasScale = kActivationScale; static constexpr LearnFloatType kWeightScale = kActivationScale; - // LearnFloatTypeの定数 + // LearnFloatType constant static constexpr LearnFloatType kZero = static_cast(0.0); static constexpr LearnFloatType kOne = static_cast(1.0); - // ミニバッチ + // mini batch const std::vector* 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 gradients_; - // 順伝播用バッファ + // Forward propagation buffer std::vector output_; - // 学習データに出現した特徴量 + // Features that appeared in the training data std::bitset 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 { #endif // defined(EVAL_LEARN) && defined(EVAL_NNUE) -#endif +#endif \ No newline at end of file diff --git a/src/eval/nnue/trainer/trainer_input_slice.h b/src/eval/nnue/trainer/trainer_input_slice.h index 0660e987..f5b263d3 100644 --- a/src/eval/nnue/trainer/trainer_input_slice.h +++ b/src/eval/nnue/trainer/trainer_input_slice.h @@ -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 Create( FeatureTransformer* feature_transformer) { static std::shared_ptr 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 void Initialize(RNG& rng) { if (num_calls_ == 0) { @@ -54,7 +54,7 @@ class SharedInputTrainer { } } - // 順伝播 + // forward propagation const LearnFloatType* Propagate(const std::vector& 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> feature_transformer_trainer_; - // 順伝播用に共有する出力のポインタ + // pointer to output shared for forward propagation const LearnFloatType* output_; - // 逆伝播用バッファ + // buffer for back propagation std::vector gradients_; }; -// 学習:入力層 +// Learning: Input layer template class Trainer> { private: - // 学習対象の層の型 + // Type of layer to learn using LayerType = Layers::InputSlice; public: - // ファクトリ関数 + // factory function static std::shared_ptr Create( LayerType* /*target_layer*/, FeatureTransformer* feature_transformer) { return std::shared_ptr(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 void Initialize(RNG& rng) { shared_input_trainer_->Initialize(rng); } - // 順伝播 + // forward propagation const LearnFloatType* Propagate(const std::vector& batch) { if (output_.size() < kOutputDimensions * batch.size()) { output_.resize(kOutputDimensions * batch.size()); @@ -199,7 +199,7 @@ class Trainer> { 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> { } 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 shared_input_trainer_; - // 順伝播用バッファ + // Forward propagation buffer std::vector output_; - // 逆伝播用バッファ + // buffer for back propagation std::vector gradients_; }; diff --git a/src/eval/nnue/trainer/trainer_sum.h b/src/eval/nnue/trainer/trainer_sum.h index 76f6073f..bae3edd5 100644 --- a/src/eval/nnue/trainer/trainer_sum.h +++ b/src/eval/nnue/trainer/trainer_sum.h @@ -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 class Trainer> : Trainer> { private: - // 学習対象の層の型 + // Type of layer to learn using LayerType = Layers::Sum; using Tail = Trainer>; public: - // ファクトリ関数 + // factory function static std::shared_ptr Create( LayerType* target_layer, FeatureTransformer* feature_transformer) { return std::shared_ptr( 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 void Initialize(RNG& rng) { Tail::Initialize(rng); previous_layer_trainer_->Initialize(rng); } - // 順伝播 + // forward propagation /*const*/ LearnFloatType* Propagate(const std::vector& batch) { batch_size_ = static_cast(batch.size()); auto output = Tail::Propagate(batch); @@ -65,7 +65,7 @@ class Trainer> : return output; } - // 逆伝播 + // backpropagation void Backpropagate(const LearnFloatType* gradients, LearnFloatType learning_rate) { Tail::Backpropagate(gradients, learning_rate); @@ -73,8 +73,8 @@ class Trainer> : } 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::Create( @@ -82,51 +82,51 @@ class Trainer> : target_layer_(target_layer) { } - // 入出力の次元数 + // number of input/output dimensions static constexpr IndexType kOutputDimensions = LayerType::kOutputDimensions; - // サブクラスをfriendにする + // make subclass friend template friend class Trainer; - // ミニバッチのサンプル数 + // number of samples in mini-batch IndexType batch_size_; - // 直前の層のTrainer + // Trainer of the previous layer const std::shared_ptr> 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 class Trainer> { private: - // 学習対象の層の型 + // Type of layer to learn using LayerType = Layers::Sum; public: - // ファクトリ関数 + // factory function static std::shared_ptr Create( LayerType* target_layer, FeatureTransformer* feature_transformer) { return std::shared_ptr( 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 void Initialize(RNG& rng) { previous_layer_trainer_->Initialize(rng); } - // 順伝播 + // forward propagation /*const*/ LearnFloatType* Propagate(const std::vector& batch) { if (output_.size() < kOutputDimensions * batch.size()) { output_.resize(kOutputDimensions * batch.size()); @@ -146,14 +146,14 @@ class Trainer> { 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::Create( @@ -161,23 +161,23 @@ class Trainer> { target_layer_(target_layer) { } - // 入出力の次元数 + // number of input/output dimensions static constexpr IndexType kOutputDimensions = LayerType::kOutputDimensions; - // サブクラスをfriendにする + // make subclass friend template friend class Trainer; - // ミニバッチのサンプル数 + // number of samples in mini-batch IndexType batch_size_; - // 直前の層のTrainer + // Trainer of the previous layer const std::shared_ptr> previous_layer_trainer_; - // 学習対象の層 + // layer to learn LayerType* const target_layer_; - // 順伝播用バッファ + // Forward propagation buffer std::vector output_; }; @@ -187,4 +187,4 @@ class Trainer> { #endif // defined(EVAL_LEARN) && defined(EVAL_NNUE) -#endif +#endif \ No newline at end of file diff --git a/src/extra/sfen_packer.cpp b/src/extra/sfen_packer.cpp index d56e808b..b3404542 100644 --- a/src/extra/sfen_packer.cpp +++ b/src/extra/sfen_packer.cpp @@ -5,33 +5,33 @@ #include #include -#include // std::memset() +#include // 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 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 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 - diff --git a/src/learn/half_float.h b/src/learn/half_float.h index 31dc5a29..d5c2f83c 100644 --- a/src/learn/half_float.h +++ b/src/learn/half_float.h @@ -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__ \ No newline at end of file diff --git a/src/learn/learn.h b/src/learn/learn.h index 246e5cc9..ab53e046 100644 --- a/src/learn/learn.h +++ b/src/learn/learn.h @@ -6,173 +6,173 @@ #include // ===================== -// 学習時の設定 +// 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 > 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_ \ No newline at end of file diff --git a/src/learn/learner.cpp b/src/learn/learner.cpp index 7189b5a3..ea7c4d7e 100644 --- a/src/learn/learner.cpp +++ b/src/learn/learner.cpp @@ -1,16 +1,16 @@ -// 学習関係のルーチン +// learning routines // -// 1) 棋譜の自動生成 -// → "gensfen"コマンド -// 2) 生成した棋譜からの評価関数パラメーターの学習 -// → "learn"コマンド -// → 教師局面のshuffleもこのコマンドの拡張として行なう。 -// 例) "learn shuffle" -// 3) 定跡の自動生成 -// → "makebook think"コマンド -// → extra/book/book.cppで実装 -// 4) 局後自動検討モード -// → GUIが補佐すべき問題なのでエンジンでは関与しないことにする。 +// 1) Automatic generation of game records +// → "gensfen" command +// 2) Learning evaluation function parameters from the generated game record +// → "learn" command +// → Shuffle in the teacher phase is also an extension of this command. +// Example) "learn shuffle" +// 3) Automatic generation of fixed traces +// → "makebook think" command +// → implemented in extra/book/book.cpp +// 4) Post-station automatic review mode +// → I will not be involved in the engine because it is a problem that the GUI should assist. // etc.. #if defined(EVAL_LEARN) @@ -23,15 +23,15 @@ #include "multi_think.h" #include "../uci.h" -// 学習用のevaluate絡みのheader +// evaluate header for learning #include "../eval/evaluate_common.h" // ---------------------- -// 設定内容に基づく定数文字列 +// constant string based on the settings // ---------------------- -// 更新式に応じた文字列。(デバッグ用に出力する。) -// 色々更新式を実装したがAdaGradが速度面、メモリ面においてベストという結論になった。 +// Character string according to update formula. (Output for debugging.) +// Implemented various update expressions, but concluded that AdaGrad is the best in terms of speed and memory. #if defined(ADA_GRAD_UPDATE) #define LEARN_UPDATE "AdaGrad" #elif defined(SGD_UPDATE) @@ -49,7 +49,7 @@ #endif // ----------------------------------- -// 以下、実装部。 +// Below, the implementation section. // ----------------------------------- #include @@ -65,9 +65,9 @@ #endif #if defined(_MSC_VER) -// C++のfilesystemは、C++17以降か、MSVCでないと使えないようだ。 -// windows.hを使うようにしたが、msys2のg++だとうまくフォルダ内のファイルが取得できない。 -// 仕方ないのでdirent.hを用いる。 +// The C++ filesystem cannot be used unless it is C++17 or later or MSVC. +// I tried to use windows.h, but with g++ of msys2 I can not get the files in the folder well. +// Use dirent.h because there is no help for it. #include #elif defined(__GNUC__) #include @@ -87,17 +87,17 @@ using namespace std; -//// これは探索部で定義されているものとする。 +//// This is defined in the search section. //extern Book::BookMoveSelector book; -// atomicに対する足し算、引き算の定義 -// Apery/learner.hppにあるatomicAdd()に合わせてある。 +// Addition and subtraction definition for atomic +// Aligned with atomicAdd() in Apery/learner.hpp. template T operator += (std::atomic& x, const T rhs) { T old = x.load(std::memory_order_consume); - // このタイミングで他スレッドから値が書き換えられることは許容する。 - // 値が破壊されなければ良しという考え。 + // It is allowed that the value is rewritten from other thread at this timing. + // The idea that the value is not destroyed is good. T desired = old + rhs; while (!x.compare_exchange_weak(old, desired, std::memory_order_release, std::memory_order_consume)) desired = old + rhs; @@ -109,7 +109,7 @@ T operator -= (std::atomic& x, const T rhs) { return x += -rhs; } namespace Learner { -// 局面の配列 : PSVector は packed sfen vector の略。 +// Phase array: PSVector stands for packed sfen vector. typedef std::vector PSVector; bool use_draw_in_training_data_generation = false; @@ -118,20 +118,20 @@ bool use_draw_in_validation = false; bool use_hash_in_training = true; // ----------------------------------- -// 局面のファイルへの書き出し +// write phase file // ----------------------------------- -// Sfenを書き出して行くためのヘルパクラス +// Helper class for exporting Sfen struct SfenWriter { - // 書き出すファイル名と生成するスレッドの数 + // File name to write and number of threads to create SfenWriter(string filename, int thread_num) { sfen_buffers_pool.reserve((size_t)thread_num * 10); sfen_buffers.resize(thread_num); - // 追加学習するとき、評価関数の学習後も生成される教師の質はあまり変わらず、教師局面数を稼ぎたいので - // 古い教師も使うのが好ましいのでこういう仕様にしてある。 + // When performing additional learning, the quality of the teacher generated after learning the evaluation function does not change much and I want to earn more teacher positions. + // Since it is preferable that old teachers also use it, it has such a specification. fs.open(filename, ios::out | ios::binary | ios::app); filename_ = filename; @@ -144,76 +144,76 @@ struct SfenWriter file_worker_thread.join(); fs.close(); - // file_worker_threadがすべて書き出したあとなのでbufferはすべて空のはずなのだが.. + // all buffers should be empty since file_worker_thread has written all.. for (auto p : sfen_buffers) { assert(p == nullptr); } assert(sfen_buffers_pool.empty()); } - // 各スレッドについて、この局面数ごとにファイルにflushする。 + // For each thread, flush the file by this number of phases. const size_t SFEN_WRITE_SIZE = 5000; - // 局面と評価値をペアにして1つ書き出す(packされたsfen形式で) + // write one by pairing the phase and evaluation value (in packed sfen format) void write(size_t thread_id, const PackedSfenValue& psv) { - // スレッドごとにbufferを持っていて、そこに追加する。 - // bufferが溢れたら、ファイルに書き出す。 + // We have a buffer for each thread and add it there. + // If the buffer overflows, write it to a file. - // このバッファはスレッドごとに用意されている。 + // This buffer is prepared for each thread. auto& buf = sfen_buffers[thread_id]; - // 初回とスレッドバッファを書き出した直後はbufがないので確保する。 + // Secure since there is no buf at the first time and immediately after writing the thread buffer. if (!buf) { buf = new PSVector(); buf->reserve(SFEN_WRITE_SIZE); } - // スレッドごとに用意されており、一つのスレッドが同時にこのwrite()関数を呼び出さないので - // この時点では排他する必要はない。 + // It is prepared for each thread, so one thread does not call this write() function at the same time. + // There is no need to exclude at this point. buf->push_back(psv); if (buf->size() >= SFEN_WRITE_SIZE) { - // sfen_buffers_poolに積んでおけばあとはworkerがよきに計らってくれる。 + // If you load it in sfen_buffers_pool, the worker will do the rest. - // sfen_buffers_poolの内容を変更するときはmutexのlockが必要。 + // Mutex lock is required when changing the contents of sfen_buffers_pool. std::unique_lock lk(mutex); sfen_buffers_pool.push_back(buf); buf = nullptr; - // buf == nullptrにしておけば次回にこの関数が呼び出されたときにバッファは確保される。 + // If you set buf == nullptr, the buffer will be allocated the next time this function is called. } } - // 自分のスレッド用のバッファに残っている分をファイルに書き出すためのバッファに移動させる。 + // Move what remains in the buffer for your thread to a buffer for writing to a file. void finalize(size_t thread_id) { std::unique_lock lk(mutex); auto& buf = sfen_buffers[thread_id]; - // buf==nullptrであるケースもあるのでそのチェックが必要。 + // There is a case that buf==nullptr, so that check is necessary. if (buf && buf->size() != 0) sfen_buffers_pool.push_back(buf); buf = nullptr; } - // write_workerスレッドを開始する。 + // Start the write_worker thread. void start_file_write_worker() { file_worker_thread = std::thread([&] { this->file_write_worker(); }); } - // ファイルに書き出すの専用スレッド + // Dedicated thread to write to file void file_write_worker() { auto output_status = [&]() { - // 現在時刻も出力 + // also output the current time sync_cout << endl << sfen_write_count << " sfens , at " << now_string() << sync_endl; - // flush()はこのタイミングで十分。 + // This is enough for flush(). fs.flush(); }; @@ -223,12 +223,12 @@ struct SfenWriter { std::unique_lock lk(mutex); - // まるごとコピー + // copy the whole buffers = sfen_buffers_pool; sfen_buffers_pool.clear(); } - // 何も取得しなかったならsleep() + // sleep() if you didn't get anything if (!buffers.size()) sleep(100); else @@ -240,83 +240,83 @@ struct SfenWriter sfen_write_count += ptr->size(); #if 1 - // 処理した件数をここに加算していき、save_everyを超えたら、ファイル名を変更し、このカウンターをリセットする。 + // Add the processed number here, and if it exceeds save_every, change the file name and reset this counter. save_every_counter += ptr->size(); if (save_every_counter >= save_every) { save_every_counter = 0; - // ファイル名を変更。 + // Change the file name. fs.close(); - // ファイルにつける連番 + // Sequential number attached to the file int n = (int)(sfen_write_count / save_every); - // ファイル名を変更して再度openする。上書き考慮してios::appをつけておく。(運用によっては、ないほうがいいかも..) + // Rename the file and open it again. Add ios::app in consideration of overwriting. (Depending on the operation, it may not be necessary.) string filename = filename_ + "_" + std::to_string(n); fs.open(filename, ios::out | ios::binary | ios::app); cout << endl << "output sfen file = " << filename << endl; } #endif - // 棋譜を書き出すごとに'.'を出力。 + // Output'.' every time when writing a game record. std::cout << "."; - // 40回ごとに処理した局面数を出力 - // 最後、各スレッドの教師局面の余りを書き出すので中途半端な数が表示されるが、まあいいか…。 - // スレッドを論理コアの最大数まで酷使するとコンソールが詰まるのでもう少し間隔甘くてもいいと思う。 + // Output the number of phases processed every 40 times + // Finally, the remainder of the teacher phase of each thread is written out, so halfway numbers are displayed, but is it okay? + // If you overuse the threads to the maximum number of logical cores, the console will be clogged, so it may be a little more loose. if ((++time_stamp_count % 40) == 0) output_status(); - // このメモリは不要なのでこのタイミングで開放しておく。 + // Since this memory is unnecessary, release it at this timing. delete ptr; } } } - // 終了前にもう一度、タイムスタンプを出力。 + // Output the time stamp again before the end. output_status(); } - // この単位でファイル名を変更する。 + // Change the file name in this unit. uint64_t save_every = UINT64_MAX; private: fstream fs; - // コンストラクタで渡されたファイル名 + // File name passed in the constructor std::string filename_; - // 処理した件数をここに加算していき、save_everyを超えたら、ファイル名を変更し、このカウンターをリセットする。 + // Add the processed number here, and if it exceeds save_every, change the file name and reset this counter. uint64_t save_every_counter = 0; - // ファイルに書き込む用のthread + // thread to write to the file std::thread file_worker_thread; - // すべてのスレッドが終了したかのフラグ + // Flag that all threads have finished atomic finished; - // タイムスタンプの出力用のカウンター + // Counter for time stamp output uint64_t time_stamp_count = 0; - // ファイルに書き出す前のバッファ - // sfen_buffersは各スレッドに対するバッファ - // sfen_buffers_poolは書き出しのためのバッファ。 - // 前者のバッファに局面をSFEN_WRITE_SIZEだけ積んだら、後者に積み替える。 + // buffer before writing to file + // sfen_buffers is the buffer for each thread + // sfen_buffers_pool is a buffer for writing. + // After loading the phase in the former buffer by SFEN_WRITE_SIZE, transfer it to the latter. std::vector sfen_buffers; std::vector sfen_buffers_pool; - // sfen_buffers_poolにアクセスするときに必要なmutex + // Mutex required to access sfen_buffers_pool std::mutex mutex; - // 書きだした局面の数 + // number of written phases uint64_t sfen_write_count = 0; }; // ----------------------------------- -// 棋譜を生成するworker(スレッドごと) +// worker that creates the game record (for each thread) // ----------------------------------- -// 複数スレッドでsfenを生成するためのクラス +// Class to generate sfen with multiple threads struct MultiThinkGenSfen : public MultiThink { MultiThinkGenSfen(int search_depth_, int search_depth2_, SfenWriter& sw_) @@ -324,49 +324,49 @@ struct MultiThinkGenSfen : public MultiThink { hash.resize(GENSFEN_HASH_SIZE); - // PCを並列化してgensfenするときに同じ乱数seedを引いていないか確認用の出力。 + // Output for confirmation if the same random seed is not drawn when parallelizing and gensfening the PC. std::cout << prng << std::endl; } virtual void thread_worker(size_t thread_id); void start_file_write_worker() { sw.start_file_write_worker(); } - // search_depth = 通常探索の探索深さ + // search_depth = search depth for normal search int search_depth; int search_depth2; - // 生成する局面の評価値の上限 + // Upper limit of evaluation value of generated situation int eval_limit; - // ランダムムーブを行なう最小ply + // minimum ply with random move int random_move_minply; - // ランダムムーブを行なう最大ply + // maximum ply with random move int random_move_maxply; - // 1局のなかでランダムムーブを行なう回数 + // Number of random moves in one station int random_move_count; - // Aperyのようにランダムムーブのときに1/Nの確率で玉を動かす。 - // また玉を動かしたときは1/Nの確率で相手番で1回ランダムムーブする。 - // AperyはN=2。ここ0を指定するとこの機能を無効化する。 + // Move balls with a probability of 1/N when randomly moving like Apery. + // When you move the ball again, there is a 1/N chance that it will randomly move once in the opponent's number. + // Apery has N=2. Specifying 0 here disables this function. int random_move_like_apery; - // ランダムムーブの代わりにmulti pvを使うとき用。 - // random_multi_pvは、MultiPVのときの候補手の数。 - // 候補手の指し手を採択するとき、1位の指し手の評価値とN位の指し手の評価値との差が - // random_multi_pv_diffの範囲でなければならない。 - // random_multi_pv_depthはMultiPVのときの探索深さ。 + // For when using multi pv instead of random move. + // random_multi_pv is the number of candidates for MultiPV. + // When adopting the move of the candidate move, the difference between the evaluation value of the move of the 1st place and the evaluation value of the move of the Nth place is + // Must be in the range random_multi_pv_diff. + // random_multi_pv_depth is the search depth for MultiPV. int random_multi_pv; int random_multi_pv_diff; int random_multi_pv_depth; - // 書き出す局面のply(初期局面からの手数)の最小、最大。 + // The minimum and maximum ply (number of steps from the initial phase) of the phase to write out. int write_minply; int write_maxply; - // sfenの書き出し器 + // sfen exporter SfenWriter& sw; - // 同一局面の書き出しを制限するためのhash - // hash_indexを求めるためのmaskに使うので、2**Nでなければならない。 + // hash to limit the export of the same phase + // It must be 2**N because it will be used as the mask to calculate hash_index. static const uint64_t GENSFEN_HASH_SIZE = 64 * 1024 * 1024; vector hash; // 64MB*sizeof(HASH_KEY) = 512MB @@ -375,25 +375,25 @@ struct MultiThinkGenSfen : public MultiThink // thread_id = 0..Threads.size()-1 void MultiThinkGenSfen::thread_worker(size_t thread_id) { - // とりあえず、書き出す手数の最大のところで引き分け扱いになるものとする。 + // For the time being, it will be treated as a draw at the maximum number of steps to write. const int MAX_PLY2 = write_maxply; - // StateInfoを最大手数分 + SearchのPVでleafにまで進めるbuffer + //Maximum StateInfo + Search PV to advance to leaf buffer std::vector> states(MAX_PLY2 + MAX_PLY /* == search_depth + α */); StateInfo si; - // 今回の指し手。この指し手で局面を進める。 + // This move. Use this move to advance the stage. Move m = MOVE_NONE; - // 終了フラグ + // end flag bool quit = false; - // 規定回数回になるまで繰り返し + // repeat until the specified number of times while (!quit) { - // Positionに対して従属スレッドの設定が必要。 - // 並列化するときは、Threads (これが実体が vectorなので、 - // Threads[0]...Threads[thread_num-1]までに対して同じようにすれば良い。 + // It is necessary to set a dependent thread for Position. + // When parallelizing, Threads (since this is a vector, + // Do the same for up to Threads[0]...Threads[thread_num-1]. auto th = Threads[thread_id]; auto& pos = th->rootPos; @@ -409,42 +409,42 @@ void MultiThinkGenSfen::thread_worker(size_t thread_id) // assert(actual == StartFEN); //} - // 探索部で定義されているBookMoveSelectorのメンバを参照する。 + // Refer to the members of BookMoveSelector defined in the search section. //auto& book = ::book; - // 1局分の局面を保存しておき、終局のときに勝敗を含めて書き出す。 - // 書き出す関数は、この下にあるflush_psv()である。 + // Save the situation for one station, and write it out including the winning and losing at the end. + // The function to write is flush_psv() below this. PSVector a_psv; a_psv.reserve(MAX_PLY2 + MAX_PLY); - // a_psvに積まれている局面をファイルに書き出す。 - // lastTurnIsWin : a_psvに積まれている最終局面の次の局面での勝敗 - // 勝ちのときは1。負けのときは-1。引き分けのときは0を渡す。 - // 返し値 : もう規定局面数に達したので終了する場合にtrue。 + // Write out the phases loaded in a_psv to a file. + // lastTurnIsWin: win/loss in the next phase after the final phase in a_psv + // 1 when winning. -1 when losing. Pass 0 for a draw. + // Return value: true if the specified number of phases has already been reached and the process ends. auto flush_psv = [&](int8_t lastTurnIsWin) { int8_t isWin = lastTurnIsWin; - // 終局の局面(の一つ前)から初手に向けて、各局面に関して、対局の勝敗の情報を付与しておく。 - // a_psvに保存されている局面は(手番的に)連続しているものとする。 + // From the final stage (one step before) to the first stage, give information on the outcome of the game for each stage. + // The phases stored in a_psv are assumed to be continuous (in order). for (auto it = a_psv.rbegin(); it != a_psv.rend(); ++it) { - // isWin == 0(引き分け)なら -1を掛けても 0(引き分け)のまま + // If isWin == 0 (draw), multiply by -1 and it will remain 0 (draw) isWin = - isWin; it->game_result = isWin; - // 局面を書き出そうと思ったら規定回数に達していた。 - // get_next_loop_count()内でカウンターを加算するので - // 局面を出力したときにこれを呼び出さないとカウンターが狂う。 + // When I tried to write out the phase, it reached the specified number of times. + // Because the counter is added in get_next_loop_count() + // If you don't call this when the phase is output, the counter goes crazy. auto loop_count = get_next_loop_count(); if (loop_count == UINT64_MAX) { - // 終了フラグを立てておく。 + // Set the end flag. quit = true; return; } - // 局面を一つ書き出す。 + // Write out one aspect. sw.write(thread_id, *it); #if 0 @@ -454,30 +454,30 @@ void MultiThinkGenSfen::thread_worker(size_t thread_id) } }; - // ply手目でランダムムーブをするかどうかのフラグ + // ply flag for whether or not to randomly move by eyes vector random_move_flag; { - // ランダムムーブを入れるならrandom_move_maxply手目までに絶対にrandom_move_count回入れる。 - // そこそこばらけて欲しい。 - // どれくらいがベストなのかはよくわからない。色々条件を変えて実験中。 - - // a[0] = 0 , a[1] = 1, ... みたいな配列を作って、これを - // Fisher-Yates shuffleして先頭のN個を取り出せば良い。 - // 実際には、N個欲しいだけなので先頭N個分だけFisher-Yatesでshuffleすれば良い。 + // If you want to add a random move, random_move_maxply be sure to enter random_move_count times before the first move. + // I want you to disperse so much. + // I'm not sure how best it is. Experimenting under various conditions. + + // Make an array like a[0] = 0 ,a[1] = 1, ... + // Fisher-Yates shuffle and take out the first N items. + // Actually, I only want N pieces, so I only need to shuffle the first N pieces with Fisher-Yates. vector a; a.reserve((size_t)random_move_maxply); - // random_move_minply , random_move_maxplyは1 originで指定されるが、 - // ここでは0 originで扱っているので注意。 + // random_move_minply ,random_move_maxply is specified by 1 origin, + // Note that we are handling 0 origin here. for (int i = std::max(random_move_minply - 1 , 0) ; i < random_move_maxply; ++i) a.push_back(i); - // Apery方式のランダムムーブの場合、insert()がrandom_move_count回呼び出される可能性があるので - // それを考慮したサイズだけ確保しておく。 + // In case of Apery random move, insert() may be called random_move_count times. + // Reserve only the size considering it. random_move_flag.resize((size_t)random_move_maxply + random_move_count); - // a[]のsize()を超える回数のランダムムーブは適用できないので制限する。 + // A random move that exceeds the size() of a[] cannot be applied, so limit it. for (int i = 0 ; i < std::min(random_move_count, (int)a.size()) ; ++i) { swap(a[i], a[prng.rand((uint64_t)a.size() - i) + i]); @@ -485,26 +485,26 @@ void MultiThinkGenSfen::thread_worker(size_t thread_id) } } - // random moveを行なった回数をカウントしておくカウンター - // random_move_minply == -1のときに、連続してランダムムーブを行なうので、このときに用いる。 + // A counter that keeps track of the number of random moves + // When random_move_minply == -1, random moves are performed continuously, so use it at this time. int random_move_c = 0; - // ply : 初期局面からの手数 + // ply: steps from the initial stage for (int ply = 0; ; ++ply) { //cout << pos << endl; - // 今回の探索depth - // gotoで飛ぶので先に宣言しておく。 + // Current search depth + // Goto will fly, so declare it first. int depth = search_depth + (int)prng.rand(search_depth2 - search_depth + 1); - // 長手数に達したのか + // has it reached the length if (ply >= MAX_PLY2) { if (use_draw_in_training_data_generation) { - // 勝敗 = 引き分けとして書き出す。 - // こうしたほうが自分が入玉したときに、相手の入玉を許しにくい(かも) - flush_psv(0); + // Write out as win/loss = draw. + // This way it is harder to allow the opponent to enter the ball when I enter (may) + flush_psv(0); } break; } @@ -514,13 +514,13 @@ void MultiThinkGenSfen::thread_worker(size_t thread_id) // Write if draw. flush_psv(0); } - break; + break; } - // 全駒されて詰んでいたりしないか? - if (MoveList(pos).size() == 0) // Can be mate or stalemate + // Isn't all pieces stuck and stuck? + if (MoveList(pos).size() == 0) { - // (この局面の一つ前の局面までは書き出す) + // (write up to the previous phase of this phase) // Write the positions other than this position if checkmated. if (pos.checkers()) // Mate flush_psv(-1); @@ -530,63 +530,63 @@ void MultiThinkGenSfen::thread_worker(size_t thread_id) break; } - //// 定跡 + //// constant track //if ((m = book.probe(pos)) != MOVE_NONE) //{ - // // 定跡にhitした。 - // // その指し手はmに格納された。 + // // Hit the constant track. + // // The move was stored in m. - // // 定跡の局面は学習には用いない。 - // a_psv.clear(); + // // Do not use the fixed phase for learning. + // a_psv.clear(); - // if (random_move_minply != -1) - // // 定跡の局面であっても、一定確率でランダムムーブは行なう。 - // goto RANDOM_MOVE; - // else - // // random_move_minplyとして-1が指定されているときは定跡を抜けるところまでは定跡に従って指す。 - // // 巨大定跡を用いて、ConsiderBookMoveCount trueとして定跡を抜けた局面を無数に用意しておき、 - // // そこから5回ランダムムーブを行なう、などの用途に用いる。 - // goto DO_MOVE; + // if (random_move_minply != -1) + // // Random move is performed with a certain probability even in the constant phase. + // goto RANDOM_MOVE; + // else + // // When -1 is specified as random_move_minply, it points according to the standard until it goes out of the standard. + // // Prepare an innumerable number of situations that have left the constant as ConsiderationBookMoveCount true using a huge constant + // // Used for purposes such as performing a random move 5 times from there. + // goto DO_MOVE; //} { - // search_depth~search_depth2 手読みの評価値とPV(最善応手列) - // 探索窓を狭めておいても問題ないはず。 + // search_depth~search_depth2 Evaluation value of hand reading and PV (best responder row) + // There should be no problem if you narrow the search window. auto pv_value1 = search(pos, depth); auto value1 = pv_value1.first; auto& pv1 = pv_value1.second; - // 評価値の絶対値がこの値以上の局面については - // その局面を学習に使うのはあまり意味がないのでこの試合を終了する。 - // これをもって勝敗がついたという扱いをする。 + // For situations where the absolute evaluation value is greater than or equal to this value + // It doesn't make much sense to use that aspect for learning, so this game ends. + // Treat this as having won or lost. - // 1手詰め、宣言勝ちならば、ここでmate_in(2)が返るのでeval_limitの上限値と同じ値になり、 - // このif式は必ず真になる。resignについても同様。 + // If you win one move, declarative win, mate_in(2) will be returned here, so it will be the same value as the upper limit of eval_limit, + // This if expression is always true. The same applies to resign. if (abs(value1) >= eval_limit) { -// sync_cout << pos << "eval limit = " << eval_limit << " over , move = " << pv1[0] << sync_endl; + // sync_cout << pos << "eval limit = "<< eval_limit << "over ,move = "<< pv1[0] << sync_endl; - // この局面でvalue1 >= eval_limitならば、(この局面の手番側の)勝ちである。 + // If value1 >= eval_limit in this aspect, you win (the turn side of this aspect). flush_psv((value1 >= eval_limit) ? 1 : -1); break; } - // おかしな指し手の検証 + // Verification of a strange move if (pv1.size() > 0 && (pv1[0] == MOVE_NONE || pv1[0] == MOVE_NULL) ) { - // MOVE_WINは、この手前で宣言勝ちの局面であるかチェックしているので - // ここで宣言勝ちの指し手が返ってくることはないはず。 - // また、MOVE_RESIGNのときvalue1は1手詰めのスコアであり、eval_limitの最小値(-31998)のはずなのだが…。 + // MOVE_WIN is checking if it is the declaration victory stage before this + // The declarative winning move should never come back here. + // Also, when MOVE_RESIGN, value1 is a one-stop score, which should be the minimum value of eval_limit (-31998)... cout << "Error! : " << pos.fen() << m << value1 << endl; break; } - // 各千日手に応じた処理。 + // Processing according to each thousand-day hand. if (pos.is_draw(0)) { if (use_draw_in_training_data_generation) { @@ -596,7 +596,7 @@ void MultiThinkGenSfen::thread_worker(size_t thread_id) break; } - // PVの指し手でleaf nodeまで進めて、そのleaf nodeでevaluate()を呼び出した値を用いる。 + // Use PV's move to the leaf node and use the value that evaluated() is called on that leaf node. auto evaluate_leaf = [&](Position& pos , vector& pv) { auto rootColor = pos.side_to_move(); @@ -604,14 +604,14 @@ void MultiThinkGenSfen::thread_worker(size_t thread_id) int ply2 = ply; for (auto m : pv) { - // デバッグ用の検証として、途中に非合法手が存在しないことを確認する。 - // NULL_MOVEはこないものとする。 + // As a verification for debugging, make sure there are no illegal players in the middle. + // NULL_MOVE does not come. - // 十分にテストしたのでコメントアウトで良い。 + // I tested it out enough so I can comment it out. #if 1 - // 非合法手はやってこないはずなのだが。 - // 宣言勝ちとmated()でないことは上でテストしているので - // 読み筋としてMOVE_WINとMOVE_RESIGNが来ないことは保証されている。(はずだが…) + // I shouldn't be an illegal player. + // declarative win and not mated() are tested above so + // It is guaranteed that MOVE_WIN and MOVE_RESIGN do not come as a reader. (Should...) if (!pos.pseudo_legal(m) || !pos.legal(m)) { cout << "Error! : " << pos.fen() << m << endl; @@ -619,25 +619,25 @@ void MultiThinkGenSfen::thread_worker(size_t thread_id) #endif pos.do_move(m, states[ply2++]); - // 毎ノードevaluate()を呼び出さないと、evaluate()の差分計算が出来ないので注意! - // depthが8以上だとこの差分計算はしないほうが速いと思われる。 + //Because the difference calculation of evaluate() cannot be performed unless each node evaluate() is called! + // If the depth is 8 or more, it seems faster not to calculate this difference. #if defined(EVAL_NNUE) if (depth < 8) Eval::evaluate_with_no_return(pos); #endif // defined(EVAL_NNUE) } - // leafに到達 - // cout << pos; + // reach leaf + // cout << pos; auto v = Eval::evaluate(pos); - // evaluate()は手番側の評価値を返すので、 - // root_colorと違う手番なら、vを反転させて返さないといけない。 + // evaluate() returns the evaluation value on the turn side, so + // If it's a turn different from root_color, you must invert v and return it. if (rootColor != pos.side_to_move()) v = -v; - // 巻き戻す。 - // C++x14にもなって、いまだreverseで回すforeachすらないのか…。 + // Rewind. + // Is it C++x14, and isn't there even foreach to turn in reverse? // for (auto it : boost::adaptors::reverse(pv)) for (auto it = pv.rbegin(); it != pv.rend(); ++it) @@ -655,52 +655,52 @@ void MultiThinkGenSfen::thread_worker(size_t thread_id) // gensfen depth 6 eval_limit 3000 // Total 53879 Hits 43713 hit rate (%) 81.132 - // 置換表の指し手で枝刈りされるなどの問題。 - // これ、教師としては少し気持ち悪いが…。 + // Problems such as pruning with moves in the substitution table. + // This is a little uncomfortable as a teacher... #endif - // depth 0の場合、pvが得られていないのでdepth 2で探索しなおす。 + //If depth 0, pv is not obtained, so search again at depth 2. if (search_depth <= 0) { pv_value1 = search(pos, 2); pv1 = pv_value1.second; } - // 初期局面周辺はは類似局面ばかりなので - // 学習に用いると過学習になりかねないから書き出さない。 - // → 比較実験すべき + // The surroundings of the initial stage are all similar + // Do not write it out because it can lead to overlearning when used for learning. + // → comparative experiment should be done if (ply < write_minply - 1) { a_psv.clear(); goto SKIP_SAVE; } - // 同一局面を書き出したところか? - // これ、複数のPCで並列して生成していると同じ局面が含まれることがあるので - // 読み込みのときにも同様の処理をしたほうが良い。 + // Did you just write the same phase? + // This may include the same aspect as it is generated in parallel on multiple PCs, so + // It is better to do the same process when reading. { auto key = pos.key(); auto hash_index = (size_t)(key & (GENSFEN_HASH_SIZE - 1)); auto key2 = hash[hash_index]; if (key == key2) { - // スキップするときはこれ以前に関する - // 勝敗の情報がおかしくなるので保存している局面をクリアする。 - // どのみち、hashが合致した時点でそこ以前の局面も合致している可能性が高いから - // 書き出す価値がない。 + // when skipping regarding earlier + // Clear the saved situation because the win/loss information will be incorrect. + // anyway, when the hash matches, it's likely that the previous phases also match + // Not worth writing out. a_psv.clear(); goto SKIP_SAVE; } - hash[hash_index] = key; // 今回のkeyに入れ替えておく。 + hash[hash_index] = key; // Replace with the current key. } - // 局面の一時保存。 + // Temporary saving of the situation. { a_psv.emplace_back(PackedSfenValue()); auto &psv = a_psv.back(); - - // packを要求されているならpackされたsfenとそのときの評価値を書き出す。 - // 最終的な書き出しは、勝敗がついてから。 + + // If pack is requested, write the packed sfen and the evaluation value at that time. + // The final writing is after winning or losing. pos.sfen_pack(psv.sfen); //{ @@ -710,12 +710,12 @@ void MultiThinkGenSfen::thread_worker(size_t thread_id) // assert(before_fen == after_fen); //} - // PV lineのleaf nodeでのroot colorから見たevaluate()の値を取得。 - // search()の返し値をそのまま使うのとこうするのとの善悪は良くわからない。 + // Get the value of evaluate() as seen from the root color on the leaf node of the PV line. + //I don't know the goodness and badness of using the return value of search() as it is. psv.score = evaluate_leaf(pos, pv1); psv.gamePly = ply; - // PVの初手を取り出す。これはdepth 0でない限りは存在するはず。 + // Take out the first PV hand. This should be present unless depth 0. assert(pv_value1.second.size() >= 1); Move pv_move1 = pv_value1.second[0]; psv.move = pv_move1; @@ -723,44 +723,44 @@ void MultiThinkGenSfen::thread_worker(size_t thread_id) SKIP_SAVE:; - // 何故かPVが得られなかった(置換表などにhitして詰んでいた?)ので次の対局に行く。 - // かなりのレアケースなので無視して良いと思う。 + // For some reason, I could not get PV (hit the substitution table etc. and got stuck?) so go to the next game. + // It's a rare case, so you can ignore it. if (pv1.size() == 0) break; - - // search_depth手読みの指し手で局面を進める。 + + // search_depth Advance the phase by hand reading. m = pv1[0]; } RANDOM_MOVE:; - // 合法手のなかからランダムに1手選ぶフェーズ + // Phase to randomly choose one from legal hands if ( - // 1. random_move_minplyからrandom_move_maxplyの間でrandom_move_count回のランダムムーブを行なうモード - (random_move_minply != -1 && ply < (int)random_move_flag.size() && random_move_flag[ply]) || - // 2. 定跡を抜けたあとにまとめてrandom_move_count回のランダムムーブを行なうモード - (random_move_minply == -1 && random_move_c < random_move_count)) + // 1. Random move of random_move_count times from random_move_minply to random_move_maxply + (random_move_minply != -1 && ply <(int)random_move_flag.size() && random_move_flag[ply]) || + // 2. A mode to perform random move of random_move_count times after leaving the track + (random_move_minply == -1 && random_move_c list(pos); - // ここをApery方式にするのとの善悪はよくわからない。 + // I don't really know the goodness and badness of making this the Apery method. if (random_move_like_apery == 0 || prng.rand(random_move_like_apery) != 0 ) { - // 普通に合法手から1手選択 + // Normally one move from legal move m = list.at((size_t)prng.rand((uint64_t)list.size())); } else { - // 玉が動かせるなら玉を動かす - Move moves[8]; // 8近傍 + // if you can move the ball, move the ball + Move moves[8]; // Near 8 Move* p = &moves[0]; for (auto& m : list) if (type_of(pos.moved_piece(m)) == KING) @@ -768,36 +768,36 @@ void MultiThinkGenSfen::thread_worker(size_t thread_id) size_t n = p - &moves[0]; if (n != 0) { - // 玉を動かす指し手 + // move to move the ball m = moves[prng.rand(n)]; - // Apery方式ではこのとき1/2の確率で相手もランダムムーブ + // In Apery method, at this time there is a 1/2 chance that the opponent will also move randomly if (prng.rand(2) == 0) { - // random_move_flag[ply]の次のところに"1"を追加するのがシンプルなhackか。 + // Is it a simple hack to add a "1" next to random_move_flag[ply]? random_move_flag.insert(random_move_flag.begin() + ply + 1, 1, true); } } else - // 普通に合法手から1手選択 + // Normally one move from legal move m = list.at((size_t)prng.rand((uint64_t)list.size())); } - // 玉の2手指しのコードを入れていたが、合法手から1手選べばそれに相当するはずで - // コードが複雑化するだけだから不要だと判断した。 + // I put in the code of two handed balls, but if you choose one from legal hands, it should be equivalent to that + // I decided it's unnecessary because it just makes the code more complicated. } else { - // ロジックが複雑になるので、すまんがここで再度MultiPVで探索する。 + // Since the logic becomes complicated, I'm sorry, I will search again with MultiPV here. Learner::search(pos, random_multi_pv_depth, random_multi_pv); - // rootMovesの上位N手のなかから一つ選択 + // Select one from the top N hands of root Moves auto& rm = pos.this_thread()->rootMoves; uint64_t s = min((uint64_t)rm.size(), (uint64_t)random_multi_pv); for (uint64_t i = 1; i < s; ++i) { - // rm[0]の評価値との差がrandom_multi_pv_diffの範囲でなければならない。 - // rm[x].scoreは、降順に並んでいると仮定できる。 + // The difference from the evaluation value of rm[0] must be within the range of random_multi_pv_diff. + // It can be assumed that rm[x].score is arranged in descending order. if (rm[0].score > rm[i].score + random_multi_pv_diff) { s = i; @@ -807,81 +807,81 @@ void MultiThinkGenSfen::thread_worker(size_t thread_id) m = rm[prng.rand(s)].pv[0]; - // まだ1局面も書き出していないのに終局してたので書き出し処理は端折って次の対局に。 + // I haven't written one phase yet, but it ended, so the writing process ends and the next game starts. if (!is_ok(m)) break; } - // ゲームの勝敗から指し手を評価しようとするとき、 - // 今回のrandom moveがあるので、ここ以前には及ばないようにする。 - a_psv.clear(); // 保存していた局面のクリア + // When trying to evaluate the move from the outcome of the game, + // There is a random move this time, so try not to fall below this. + a_psv.clear(); // clear saved aspect } DO_MOVE:; pos.do_move(m, states[ply]); - // 差分計算を行なうために毎node evaluate()を呼び出しておく。 + // Call node evaluate() for each difference calculation. Eval::evaluate_with_no_return(pos); } // for (int ply = 0; ; ++ply) - + } // while(!quit) - + sw.finalize(thread_id); } // ----------------------------------- -// 棋譜を生成するコマンド(master thread) +// Command to generate a game record (master thread) // ----------------------------------- -// 棋譜を生成するコマンド +// Command to generate a game record void gen_sfen(Position&, istringstream& is) { - // スレッド数(これは、USIのsetoptionで与えられる) + // number of threads (given by USI setoption) uint32_t thread_num = (uint32_t)Options["Threads"]; - // 生成棋譜の個数 default = 80億局面(Ponanza仕様) + // Number of generated game records default = 8 billion phases (Ponanza specification) uint64_t loop_max = 8000000000UL; - // 評価値がこの値になったら生成を打ち切る。 + // Stop the generation when the evaluation value reaches this value. int eval_limit = 3000; - // 探索深さ + // search depth int search_depth = 3; int search_depth2 = INT_MIN; - // ランダムムーブを行なう最小plyと最大plyと回数 + // minimum ply, maximum ply and number of random moves int random_move_minply = 1; int random_move_maxply = 24; int random_move_count = 5; - // ランダムムーブをAperyのように玉を主に動かす機能 - // これを例えば3にすると1/3の確率で玉を動かす。 + // A function to move the random move mainly like Apery + // If this is set to 3, the ball will move with a probability of 1/3. int random_move_like_apery = 0; - // ランダムムーブの代わりにmultipvで探索してそのなかからランダムに選ぶときはrandom_multi_pv = 1以上の数にする。 + // If you search with multipv instead of random move and choose from among them randomly, set random_multi_pv = 1 or more. int random_multi_pv = 0; int random_multi_pv_diff = 32000; int random_multi_pv_depth = INT_MIN; - // 書き出す局面のply(初期局面からの手数)の最小、最大。 + // The minimum and maximum ply (number of steps from the initial phase) of the phase to write out. int write_minply = 16; int write_maxply = 400; - // 書き出すファイル名 + // File name to write string output_file_name = "generated_kifu.bin"; string token; - // eval hashにhitすると初期局面付近の評価値として、hash衝突して大きな値を書き込まれてしまうと - // eval_limitが小さく設定されているときに初期局面で毎回eval_limitを超えてしまい局面の生成が進まなくなる。 - // そのため、eval hashは無効化する必要がある。 - // あとeval hashのhash衝突したときに、変な値の評価値が使われ、それを教師に使うのが気分が悪いというのもある。 + // When hit to eval hash, as a evaluation value near the initial stage, if a hash collision occurs and a large value is written + // When eval_limit is set small, eval_limit will be exceeded every time in the initial phase, and phase generation will not proceed. + // Therefore, eval hash needs to be disabled. + // After that, when the hash of the eval hash collides, the evaluation value of a strange value is used, and it may be unpleasant to use it for the teacher. bool use_eval_hash = false; - // この単位でファイルに保存する。 - // ファイル名は file_1.bin , file_2.binのように連番がつく。 + // Save to file in this unit. + // File names are serialized like file_1.bin, file_2.bin. uint64_t save_every = UINT64_MAX; - // ファイル名の末尾にランダムな数値を付与する。 + // Add a random number to the end of the file name. bool random_file_name = false; while (true) @@ -902,7 +902,7 @@ void gen_sfen(Position&, istringstream& is) else if (token == "eval_limit") { is >> eval_limit; - // 最大値を1手詰みのスコアに制限する。(そうしないとループを終了しない可能性があるので) + // Limit the maximum to a one-stop score. (Otherwise you might not end the loop) eval_limit = std::min(eval_limit, (int)mate_in(2)); } else if (token == "random_move_minply") @@ -934,12 +934,12 @@ void gen_sfen(Position&, istringstream& is) } #if defined(USE_GLOBAL_OPTIONS) - // あとで復元するために保存しておく。 + // Save it for later restore. auto oldGlobalOptions = GlobalOptions; GlobalOptions.use_eval_hash = use_eval_hash; #endif - // search depth2が設定されていないなら、search depthと同じにしておく。 + // If search depth2 is not set, leave it the same as search depth. if (search_depth2 == INT_MIN) search_depth2 = search_depth; if (random_multi_pv_depth == INT_MIN) @@ -947,10 +947,10 @@ void gen_sfen(Position&, istringstream& is) if (random_file_name) { - // output_file_nameにこの時点でランダムな数値を付与してしまう。 + // Give a random number to output_file_name at this point. std::random_device seed_gen; PRNG r(seed_gen()); - // 念のため乱数振り直しておく。 + // Just in case, reassign the random numbers. for(int i=0;i<10;++i) r.rand(1); auto to_hex = [](uint64_t u){ @@ -958,7 +958,7 @@ void gen_sfen(Position&, istringstream& is) ss << std::hex << u; return ss.str(); }; - // 64bitの数値で偶然かぶると嫌なので念のため64bitの数値2つくっつけておく。 + // I don't want to wear 64bit numbers by accident, so I'm going to make a 64bit number 2 just in case. output_file_name = output_file_name + "_" + to_hex(r.rand()) + to_hex(r.rand()); } @@ -982,7 +982,7 @@ void gen_sfen(Position&, istringstream& is) << " save_every = " << save_every << endl << " random_file_name = " << random_file_name << endl; - // Options["Threads"]の数だけスレッドを作って実行。 + // Create and execute threads as many as Options["Threads"]. { SfenWriter sw(output_file_name, thread_num); sw.save_every = save_every; @@ -1002,30 +1002,30 @@ void gen_sfen(Position&, istringstream& is) multi_think.start_file_write_worker(); multi_think.go_think(); - // SfenWriterのデストラクタでjoinするので、joinが終わってから終了したというメッセージを - // 表示させるべきなのでここをブロックで囲む。 + // Since we are joining with the destructor of SfenWriter, please give a message that it has finished after the join + // Enclose this in a block because it should be displayed. } std::cout << "gensfen finished." << endl; #if defined(USE_GLOBAL_OPTIONS) - // GlobalOptionsの復元。 + // Restore Global Options. GlobalOptions = oldGlobalOptions; #endif } // ----------------------------------- -// 生成した棋譜から学習させるコマンド(learn) +// command to learn from the generated game (learn) // ----------------------------------- -// 普通のシグモイド関数 +// ordinary sigmoid function double sigmoid(double x) { return 1.0 / (1.0 + std::exp(-x)); } -// 評価値を勝率[0,1]に変換する関数 +// A function that converts the evaluation value to the winning rate [0,1] double winning_percentage(double value) { // 1/(1+10^(-Eval/4)) @@ -1033,43 +1033,41 @@ double winning_percentage(double value) // = sigmoid(Eval/4*ln(10)) return sigmoid(value / PawnValueEg / 4.0 * log(10.0)); } - -// 普通のシグモイド関数の導関数。 double dsigmoid(double x) { - // シグモイド関数 - // f(x) = 1/(1+exp(-x)) - // に対して1階微分は、 - // f'(x) = df/dx = f(x)・{ 1 - f(x) } - // となる。 + // Sigmoid function + // f(x) = 1/(1+exp(-x)) + // the first derivative is + // f'(x) = df/dx = f(x)・{ 1-f(x)} + // becomes return sigmoid(x) * (1.0 - sigmoid(x)); } -// 目的関数が勝率の差の二乗和のとき +// When the objective function is the sum of squares of the difference in winning percentage #if defined (LOSS_FUNCTION_IS_WINNING_PERCENTAGE) -// 勾配を計算する関数 +// function to calculate the gradient double calc_grad(Value deep, Value shallow, PackedSfenValue& psv) { - // 勝率の差の2乗が目的関数それを最小化する。 - // 目的関数 J = 1/2m Σ ( win_rate(shallow) - win_rate(deep) ) ^2 - // ただし、σはシグモイド関数で、評価値を勝率の差に変換するもの。 - // mはサンプルの件数。shallowは浅い探索(qsearch())のときの評価値。deepは深い探索のときの評価値。 - // また、Wを特徴ベクトル(評価関数のパラメーター)、Xi,Yiを教師とすると - // shallow = W*Xi // *はアダマール積で、Wの転置・X の意味 + // The square of the win rate difference minimizes it in the objective function. + // Objective function J = 1/2m Σ (win_rate(shallow)-win_rate(deep) )^2 + // However, σ is a sigmoid function that converts the evaluation value into the difference in the winning percentage. + // m is the number of samples. shallow is the evaluation value for a shallow search (qsearch()). deep is the evaluation value for deep search. + // If W is the feature vector (parameter of the evaluation function) and Xi and Yi are teachers + // shallow = W*Xi // * is the Hadamard product, transposing W and meaning X // f(Xi) = win_rate(W*Xi) - // σ(i番目のdeep) = Yi とおくと、 - // J = m/2 Σ ( f(Xi) - Yi )^2 - // とよくある式になる。 - // Wはベクトルで、j番目の要素をWjと書くとすると、連鎖律から - // ∂J/∂Wj = ∂J/∂f ・ ∂f/∂W ・ ∂W/∂Wj - // = 1/m Σ ( f(Xi) - y ) ・ f'(Xi) ・ 1 + // If σ(i th deep) = Yi, + // J = m/2 Σ (f(Xi)-Yi )^2 + // becomes a common expression. + // W is a vector, and if we write the jth element as Wj, from the chain rule + // ∂J/∂Wj = ∂J/∂f ・∂f/∂W ・∂W/∂Wj + // = 1/m Σ (f(Xi)-y) ・f'(Xi) ・ 1 - // 1/mはあとで掛けるとして、勾配の値としてはΣの中身を配列に保持しておけば良い。 + // 1/m will be multiplied later, but the contents of Σ can be retained in the array as the value of the gradient. // f'(Xi) = win_rate'(shallow) = sigmoid'(shallow/600) = dsigmoid(shallow / 600) / 600 - // この末尾の /600 は学習率で調整するから書かなくていいか.. - // また1/mという係数も、Adam , AdaGradのような勾配の自動調整機能を持つ更新式を用いるなら不要。 - // ゆえにメモリ上に保存しておく必要はない。 + // This /600 at the end is adjusted by the learning rate, so do not write it.. + // Also, the coefficient of 1/m is unnecessary if you use the update formula that has the automatic gradient adjustment function like Adam and AdaGrad. + // Therefore, it is not necessary to save it in memory. double p = winning_percentage(deep); double q = winning_percentage(shallow); @@ -1080,22 +1078,22 @@ double calc_grad(Value deep, Value shallow, PackedSfenValue& psv) #if defined (LOSS_FUNCTION_IS_CROSS_ENTOROPY) double calc_grad(Value deep, Value shallow, const PackedSfenValue& psv) { - // 交差エントロピーを用いた目的関数 + // Objective function with cross entropy - // 交差エントロピーの概念と性質については、 + // For the concept and nature of cross entropy, // http://nnadl-ja.github.io/nnadl_site_ja/chap3.html#the_cross-entropy_cost_function // http://postd.cc/visual-information-theory-3/ - // などを参考に。 + // Refer to etc. - // 目的関数の設計) - // pの分布をqの分布に近づけたい → pとqの確率分布間の交差エントロピーの最小化問題と考える。 - // J = H(p,q) = - Σ p(x) log(q(x)) = -p log q - (1-p) log(1-q) - // x + // Objective function design) + // We want to make the distribution of p closer to the distribution of q → Think of it as the problem of minimizing the cross entropy between the probability distributions of p and q. + // J = H(p,q) =-Σ p(x) log(q(x)) = -p log q-(1-p) log(1-q) + // x - // pは定数、qはWiの関数(q = σ(W・Xi) )としてWiに対する偏微分を求める。 - // ∂J/∂Wi = -p・q'/q - (1-p)(1-q)'/(1-q) - // = ... - // = q - p. + // p is a constant and q is a Wi function (q = σ(W・Xi) ). + // ∂J/∂Wi = -p・q'/q-(1-p)(1-q)'/(1-q) + // = ... + // = q-p. double p = winning_percentage(deep); double q = winning_percentage(shallow); @@ -1107,47 +1105,47 @@ double calc_grad(Value deep, Value shallow, const PackedSfenValue& psv) #if defined ( LOSS_FUNCTION_IS_CROSS_ENTOROPY_FOR_VALUE ) double calc_grad(Value deep, Value shallow, const PackedSfenValue& psv) { - // 勝率の関数を通さない版 - // これ、EVAL_LIMITを低くしておかないと、終盤の形に対して評価値を一致させようとして - // evalがevalの範囲を超えかねない。 + // Version that does not pass the winning percentage function + // This, unless EVAL_LIMIT is set low, trying to match the evaluation value with the shape of the end stage + // eval may exceed the range of eval. return shallow - deep; } #endif #if defined ( LOSS_FUNCTION_IS_ELMO_METHOD ) -// elmo(WCSC27)で使われている定数。要調整。 -// elmoのほうは式を内分していないので値が違う。 -// learnコマンドでこの値を設定できる。 -// 0.33は、elmo(WCSC27)で使われていた定数(0.5)相当 +// A constant used in elmo (WCSC27). Adjustment required. +// Since elmo does not internally divide the expression, the value is different. +// You can set this value with the learn command. +// 0.33 is equivalent to the constant (0.5) used in elmo (WCSC27) double ELMO_LAMBDA = 0.33; double ELMO_LAMBDA2 = 0.33; double ELMO_LAMBDA_LIMIT = 32000; double calc_grad(Value deep, Value shallow , const PackedSfenValue& psv) { - // elmo(WCSC27)方式 - // 実際のゲームの勝敗で補正する。 + // elmo (WCSC27) method + // Correct with the actual game wins and losses. const double q = winning_percentage(shallow); const double p = winning_percentage(deep); - // 期待勝率を勝っていれば1、負けていれば 0、引き分けなら0.5として補正項として用いる。 - // game_result = 1,0,-1なので1足して2で割る。 + // Use 1 as the correction term if the expected win rate is 1, 0 if you lose, and 0.5 if you draw. + // game_result = 1,0,-1 so add 1 and divide by 2. const double t = double(psv.game_result + 1) / 2; - // 深い探索での評価値がELMO_LAMBDA_LIMITを超えているならELMO_LAMBDAではなくELMO_LAMBDA2を適用する。 + // If the evaluation value in deep search exceeds ELMO_LAMBDA_LIMIT, apply ELMO_LAMBDA2 instead of ELMO_LAMBDA. const double lambda = (abs(deep) >= ELMO_LAMBDA_LIMIT) ? ELMO_LAMBDA2 : ELMO_LAMBDA; - // 実際の勝率を補正項として使っている。 - // これがelmo(WCSC27)のアイデアで、現代のオーパーツ。 + // Use the actual win rate as a correction term. + // This is the idea of ​​elmo (WCSC27), modern O-parts. const double grad = lambda * (q - p) + (1.0 - lambda) * (q - t); return grad; } -// 学習時の交差エントロピーの計算 -// elmo式の勝敗項と勝率項との個別の交差エントロピーが引数であるcross_entropy_evalとcross_entropy_winに返る。 +// Calculate cross entropy during learning +// The individual cross entropy of the win/loss term and win rate term of the elmo expression is returned to the arguments cross_entropy_eval and cross_entropy_win. void calc_cross_entropy(Value deep, Value shallow, const PackedSfenValue& psv, double& cross_entropy_eval, double& cross_entropy_win, double& cross_entropy, double& entropy_eval, double& entropy_win, double& entropy) @@ -1158,7 +1156,7 @@ void calc_cross_entropy(Value deep, Value shallow, const PackedSfenValue& psv, constexpr double epsilon = 0.000001; - // 深い探索での評価値がELMO_LAMBDA_LIMITを超えているならELMO_LAMBDAではなくELMO_LAMBDA2を適用する。 + // If the evaluation value in deep search exceeds ELMO_LAMBDA_LIMIT, apply ELMO_LAMBDA2 instead of ELMO_LAMBDA. const double lambda = (abs(deep) >= ELMO_LAMBDA_LIMIT) ? ELMO_LAMBDA2 : ELMO_LAMBDA; const double m = (1.0 - lambda) * t + lambda * p; @@ -1181,13 +1179,14 @@ void calc_cross_entropy(Value deep, Value shallow, const PackedSfenValue& psv, #endif -// 目的関数として他のバリエーションも色々用意するかも.. +// Other variations may be prepared as the objective function.. + double calc_grad(Value shallow, const PackedSfenValue& psv) { return calc_grad((Value)psv.score, shallow, psv); } -// Sfenの読み込み機 +// Sfen reader struct SfenReader { SfenReader(int thread_num) : prng((std::random_device())()) @@ -1216,12 +1215,12 @@ struct SfenReader delete p; } - // mseなどの計算用に用いる局面数 - // mini-batch size = 1Mが標準的なので、その0.2%程度なら時間的には無視できるはず。 - // 指し手一致率の計算でdepth = 1でsearch()をするので、単純比較はできないが…。 + // number of phases used for calculation such as mse + // mini-batch size = 1M is standard, so 0.2% of that should be negligible in terms of time. + //Since search() is performed with depth = 1 in calculation of move match rate, simple comparison is not possible... const uint64_t sfen_for_mse_size = 2000; - // mseなどの計算用に局面を読み込んでおく。 + // Load the phase for calculation such as mse. void read_for_mse() { auto th = Threads.main(); @@ -1236,7 +1235,7 @@ struct SfenReader } sfen_for_mse.push_back(ps); - // hash keyを求める。 + // Get the hash key. StateInfo si; pos.set_from_packed_sfen(ps.sfen,&si,th); sfen_for_mse_hash.insert(pos.key()); @@ -1263,35 +1262,36 @@ struct SfenReader } } - // 各スレッドがバッファリングしている局面数 0.1M局面。40HTで4M局面 + // Number of phases buffered by each thread 0.1M phases. 4M phase at 40HT const size_t THREAD_BUFFER_SIZE = 10 * 1000; - // ファイル読み込み用のバッファ(これ大きくしたほうが局面がshuffleが大きくなるので局面がバラけていいと思うが - // あまり大きいとメモリ消費量も上がる。 - // SFEN_READ_SIZEはTHREAD_BUFFER_SIZEの倍数であるものとする。 + // Buffer for reading files (If this is made larger, the shuffle becomes larger and the phases may vary. + // If it is too large, the memory consumption will increase. + // SFEN_READ_SIZE is a multiple of THREAD_BUFFER_SIZE. const size_t SFEN_READ_SIZE = LEARN_SFEN_READ_SIZE; - // [ASYNC] スレッドが局面を一つ返す。なければfalseが返る。 + // [ASYNC] Thread returns one aspect. Otherwise returns false. bool read_to_thread_buffer(size_t thread_id, PackedSfenValue& ps) { - // スレッドバッファに局面が残っているなら、それを1つ取り出して返す。 + // If there are any positions left in the thread buffer, retrieve one and return it. auto& thread_ps = packed_sfens[thread_id]; - // バッファに残りがなかったらread bufferから充填するが、それすらなかったらもう終了。 - if ((thread_ps == nullptr || thread_ps->size() == 0) // バッファが空なら充填する。 + // Fill the read buffer if there is no remaining buffer, but if it doesn't even exist, finish. + if ((thread_ps == nullptr || thread_ps->size() == 0) // If the buffer is empty, fill it. && !read_to_thread_buffer_impl(thread_id)) return false; - // read_to_thread_buffer_impl()がtrueを返したというこは、 - // スレッドバッファへの局面の充填が無事完了したということなので - // thread_ps->rbegin()は健在。 + // read_to_thread_buffer_impl() returned true, + // Since the filling of the thread buffer with the phase has been completed successfully + // thread_ps->rbegin() is alive. ps = *(thread_ps->rbegin()); thread_ps->pop_back(); - - // バッファを使いきったのであれば自らdeleteを呼び出してこのバッファを開放する。 + + // If you've run out of buffers, call delete yourself to free this buffer. if (thread_ps->size() == 0) { + delete thread_ps; thread_ps = nullptr; } @@ -1299,17 +1299,17 @@ struct SfenReader return true; } - // [ASYNC] スレッドバッファに局面をある程度読み込む。 + // [ASYNC] Read some aspects into thread buffer. bool read_to_thread_buffer_impl(size_t thread_id) { while (true) { { std::unique_lock lk(mutex); - // ファイルバッファから充填できたなら、それで良し。 + // If you can fill from the file buffer, that's fine. if (packed_sfens_pool.size() != 0) { - // 充填可能なようなので充填して終了。 + // It seems that filling is possible, so fill and finish. packed_sfens[thread_id] = packed_sfens_pool.front(); packed_sfens_pool.pop_front(); @@ -1320,24 +1320,24 @@ struct SfenReader } } - // もうすでに読み込むファイルは無くなっている。もうダメぽ。 + // The file to read is already gone. No more use. if (end_of_files) return false; - // file workerがpacked_sfens_poolに充填してくれるのを待っている。 - // mutexはlockしていないのでいずれ充填してくれるはずだ。 + // Waiting for file worker to fill packed_sfens_pool. + // The mutex isn't locked, so it should fill up soon. sleep(1); } } - - // 局面ファイルをバックグラウンドで読み込むスレッドを起動する。 + + // Start a thread that loads the phase file in the background. void start_file_read_worker() { file_worker_thread = std::thread([&] { this->file_read_worker(); }); } - // ファイルの読み込み専用スレッド用 + // for file read-only threads void file_read_worker() { auto open_next_file = [&]() @@ -1345,11 +1345,11 @@ struct SfenReader if (fs.is_open()) fs.close(); - // もう無い + // no more if (filenames.size() == 0) return false; - // 次のファイル名ひとつ取得。 + // Get the next file name. string filename = *filenames.rbegin(); filenames.pop_back(); @@ -1362,8 +1362,8 @@ struct SfenReader while (true) { - // バッファが減ってくるのを待つ。 - // このsize()の読み取りはread onlyなのでlockしなくていいだろう。 + // Wait for the buffer to run out. + // This size() is read only, so you don't need to lock it. while (!stop_flag && packed_sfens_pool.size() >= SFEN_READ_SIZE / THREAD_BUFFER_SIZE) sleep(100); if (stop_flag) @@ -1372,7 +1372,7 @@ struct SfenReader PSVector sfens; sfens.reserve(SFEN_READ_SIZE); - // ファイルバッファにファイルから読み込む。 + // Read from the file into the file buffer. while (sfens.size() < SFEN_READ_SIZE) { PackedSfenValue p; @@ -1381,10 +1381,10 @@ struct SfenReader sfens.push_back(p); } else { - // 読み込み失敗 + // read failure if (!open_next_file()) { - // 次のファイルもなかった。あぼーん。 + // There was no next file. Abon. cout << "..end of files." << endl; end_of_files = true; return; @@ -1392,7 +1392,7 @@ struct SfenReader } } - // この読み込んだ局面データをshuffleする。 + // Shuffle the read phase data. // random shuffle by Fisher-Yates algorithm if (!no_shuffle) @@ -1402,8 +1402,8 @@ struct SfenReader swap(sfens[i], sfens[(size_t)(prng.rand((uint64_t)size - i) + i)]); } - // これをTHREAD_BUFFER_SIZEごとの細切れにする。それがsize個あるはず。 - // SFEN_READ_SIZEはTHREAD_BUFFER_SIZEの倍数であるものとする。 + // Divide this by THREAD_BUFFER_SIZE. There should be size pieces. + // SFEN_READ_SIZE shall be a multiple of THREAD_BUFFER_SIZE. assert((SFEN_READ_SIZE % THREAD_BUFFER_SIZE)==0); auto size = size_t(SFEN_READ_SIZE / THREAD_BUFFER_SIZE); @@ -1412,7 +1412,7 @@ struct SfenReader for (size_t i = 0; i < size; ++i) { - // このポインターのdeleteは、受け側で行なう。 + // Delete this pointer on the receiving side. PSVector* ptr = new PSVector(); ptr->resize(THREAD_BUFFER_SIZE); memcpy(&((*ptr)[0]), &sfens[i * THREAD_BUFFER_SIZE], sizeof(PackedSfenValue) * THREAD_BUFFER_SIZE); @@ -1420,12 +1420,12 @@ struct SfenReader ptrs.push_back(ptr); } - // sfensの用意が出来たので、折を見てコピー + // Since sfens is ready, look at the occasion and copy { std::unique_lock lk(mutex); - // ポインタをコピーするだけなのでこの時間は無視できるはず…。 - // packed_sfens_poolの内容を変更するのでmutexのlockが必要。 + // You can ignore this time because you just copy the pointer... + // The mutex lock is required because the contents of packed_sfens_pool are changed. for (size_t i = 0; i < size; ++i) packed_sfens_pool.push_back(ptrs[i]); @@ -1433,76 +1433,76 @@ struct SfenReader } } - // sfenファイル群 + // sfen files vector filenames; - // 読み込んだ局面数(ファイルからメモリ上のバッファへ) + // number of phases read (file to memory buffer) atomic total_read; - // 処理した局面数 + // number of processed phases atomic total_done; - // 前回までに処理した件数 + // number of cases processed so far uint64_t last_done; - // total_readがこの値を超えたらupdate_weights()してmseの計算をする。 + // If total_read exceeds this value, update_weights() and calculate mse. uint64_t next_update_weights; uint64_t save_count; - // 局面読み込み時のシャッフルを行わない。 + // Do not shuffle when reading the phase. bool no_shuffle; bool stop_flag; - // rmseの計算用の局面であるかどうかを判定する。 - // (rmseの計算用の局面は学習のために使うべきではない。) + // Determine if it is a phase for calculating rmse. + // (The computational aspects of rmse should not be used for learning.) bool is_for_rmse(Key key) const { - return sfen_for_mse_hash.count(key) != 0; + return sfen_for_mse_hash.count(key) != 0; } - // 同一局面の読み出しを制限するためのhash - // 6400万局面って多すぎるか?そうでもないか.. - // hash_indexを求めるためのmaskに使うので、2**Nでなければならない。 + // hash to limit the reading of the same situation + // Is there too many 64 million phases? Or Not really.. + // It must be 2**N because it will be used as the mask to calculate hash_index. static const uint64_t READ_SFEN_HASH_SIZE = 64 * 1024 * 1024; vector hash; // 64MB*8 = 512MB - // mse計算用のtest局面 + // test phase for mse calculation PSVector sfen_for_mse; protected: - // fileをバックグラウンドで読み込みしているworker thread + // worker thread reading file in background std::thread file_worker_thread; - // 局面の読み込み時にshuffleするための乱数 + // Random number to shuffle when reading the phase PRNG prng; - // ファイル群を読み込んでいき、最後まで到達したか。 + // Did you read the files and reached the end? atomic end_of_files; - // sfenファイルのハンドル + // handle of sfen file std::fstream fs; - // 各スレッド用のsfen - // (使いきったときにスレッドが自らdeleteを呼び出して開放すべし。) + // sfen for each thread + // (When the thread is used up, the thread should call delete to release it.) std::vector packed_sfens; - // packed_sfens_poolにアクセスするときのmutex + // Mutex when accessing packed_sfens_pool std::mutex mutex; - // sfenのpool。fileから読み込むworker threadはここに補充する。 - // 各worker threadはここから自分のpacked_sfens[thread_id]に充填する。 - // ※ mutexをlockしてアクセスすること。 + // pool of sfen. The worker thread read from the file is added here. + // Each worker thread fills its own packed_sfens[thread_id] from here. + // * Lock and access the mutex. std::list packed_sfens_pool; - // mse計算用の局面を学習に用いないためにhash keyを保持しておく。 + // Hold the hash key so that the mse calculation phase is not used for learning. std::unordered_set sfen_for_mse_hash; }; -// 複数スレッドでsfenを生成するためのクラス +// Class to generate sfen with multiple threads struct LearnerThink: public MultiThink { LearnerThink(SfenReader& sr_):sr(sr_),stop_flag(false), save_only_once(false) @@ -1527,43 +1527,43 @@ struct LearnerThink: public MultiThink virtual void thread_worker(size_t thread_id); - // 局面ファイルをバックグラウンドで読み込むスレッドを起動する。 + // Start a thread that loads the phase file in the background. void start_file_read_worker() { sr.start_file_read_worker(); } - // 評価関数パラメーターをファイルに保存 + // save merit function parameters to a file bool save(bool is_final=false); - // sfenの読み出し器 + // sfen reader SfenReader& sr; - // 学習の反復回数のカウンター + // Learning iteration counter uint64_t epoch = 0; - // ミニバッチサイズのサイズ。必ずこのclassを使う側で設定すること。 + // Mini batch size size. Be sure to set it on the side that uses this class. uint64_t mini_batch_size = 1000*1000; bool stop_flag; - // 割引率 + // Discount rate double discount_rate; - // 序盤を学習対象から外すオプション + // Option to exclude early stage from learning int reduction_gameply; - // kk/kkp/kpp/kpppを学習させないオプション + // Option not to learn kk/kkp/kpp/kppp std::array freeze; - // 教師局面の深い探索の評価値の絶対値がこの値を超えていたらその教師局面を捨てる。 + // If the absolute value of the evaluation value of the deep search of the teacher phase exceeds this value, discard the teacher phase. int eval_limit; - // 評価関数の保存するときに都度フォルダを掘るかのフラグ。 - // trueだとフォルダを掘らない。 + // Flag whether to dig a folder each time the evaluation function is saved. + // If true, do not dig the folder. bool save_only_once; - // --- lossの計算 + // --- loss calculation -#if defined ( LOSS_FUNCTION_IS_ELMO_METHOD ) - // 学習用データのロスの計算用 +#if defined (LOSS_FUNCTION_IS_ELMO_METHOD) + // For calculation of learning data loss atomic learn_sum_cross_entropy_eval; atomic learn_sum_cross_entropy_win; atomic learn_sum_cross_entropy; @@ -1587,20 +1587,21 @@ struct LearnerThink: public MultiThink uint64_t loss_output_interval; uint64_t mirror_percentage; - // ロスの計算。 - // done : 今回対象とした局面数 + // Loss calculation. + // done: Number of phases targeted this time void calc_loss(size_t thread_id , uint64_t done); - // ↑のlossの計算をタスクとして定義してやり、それを実行する + // Define the loss calculation in ↑ as a task and execute it TaskDispatcher task_dispatcher; }; void LearnerThink::calc_loss(size_t thread_id, uint64_t done) { - // 置換表にhitされてもかなわんので、このタイミングで置換表の世代を新しくする。 - // 置換表を無効にしているなら関係ないのだが。 + // There is no point in hitting the replacement table, so at this timing the generation of the replacement table is updated. + // It doesn't matter if you have disabled the substitution table. TT.new_search(); + #if defined(EVAL_NNUE) std::cout << "PROGRESS: " << now_string() << ", "; std::cout << sr.total_done << " sfens"; @@ -1614,8 +1615,8 @@ void LearnerThink::calc_loss(size_t thread_id, uint64_t done) double sum_error3 = 0; #endif -#if defined ( LOSS_FUNCTION_IS_ELMO_METHOD ) - // 検証用データのロスの計算用 +#if defined (LOSS_FUNCTION_IS_ELMO_METHOD) + // For calculation of verification data loss atomic test_sum_cross_entropy_eval,test_sum_cross_entropy_win,test_sum_cross_entropy; atomic test_sum_entropy_eval,test_sum_entropy_win,test_sum_entropy; test_sum_cross_entropy_eval = 0; @@ -1625,16 +1626,16 @@ void LearnerThink::calc_loss(size_t thread_id, uint64_t done) test_sum_entropy_win = 0; test_sum_entropy = 0; - // 学習時のnorm + // norm for learning atomic sum_norm; sum_norm = 0; #endif - // 深い探索のpvの初手と、search(1)のpvの初手の指し手が一致した回数。 + // The number of times the pv first move of deep search matches the pv first move of search(1). atomic move_accord_count; move_accord_count = 0; - // 平手の初期局面のeval()の値を表示させて、揺れを見る。 + // Display the value of eval() in the initial stage of Hirate and see the shaking. auto th = Threads[thread_id]; auto& pos = th->rootPos; StateInfo si; @@ -1643,36 +1644,36 @@ void LearnerThink::calc_loss(size_t thread_id, uint64_t done) //Eval::print_eval_stat(pos); - // ここ、並列化したほうが良いのだがslaveの前の探索が終わってなかったりしてちょっと面倒。 - // taskを呼び出すための仕組みを作ったのでそれを用いる。 + // It's better to parallelize here, but it's a bit troublesome because the search before slave has not finished. + // I created a mechanism to call task, so I will use it. - // こなすべきtaskの数。 + // The number of tasks to do. atomic task_count; task_count = (int)sr.sfen_for_mse.size(); task_dispatcher.task_reserve(task_count); - // 局面の探索をするtaskを生成して各スレッドに振ってやる。 + // Create a task to search for the situation and give it to each thread. for (const auto& ps : sr.sfen_for_mse) { - // TaskDispatcherを用いて各スレッドに作業を振る。 - // そのためのタスクの定義。 - // ↑で使っているposをcaptureされるとたまらんのでcaptureしたい変数は一つずつ指定しておく。 + // Assign work to each thread using TaskDispatcher. + // A task definition for that. + // It is not possible to capture pos used in ↑, so specify the variables you want to capture one by one. auto task = [&ps,&test_sum_cross_entropy_eval,&test_sum_cross_entropy_win,&test_sum_cross_entropy,&test_sum_entropy_eval,&test_sum_entropy_win,&test_sum_entropy, &sum_norm,&task_count ,&move_accord_count](size_t thread_id) { - // これ、C++ではループごとに新たなpsのインスタンスをちゃんとcaptureするのだろうか.. → するようだ。 + // Does C++ properly capture a new ps instance for each loop?. auto th = Threads[thread_id]; auto& pos = th->rootPos; StateInfo si; if (pos.set_from_packed_sfen(ps.sfen ,&si, th) != 0) { - // 運悪くrmse計算用のsfenとして、不正なsfenを引いてしまっていた。 + // Unfortunately, as an sfen for rmse calculation, an invalid sfen was drawn. cout << "Error! : illegal packed sfen " << pos.fen() << endl; } - // 浅い探索の評価値 - // evaluate()の値を用いても良いのだが、ロスを計算するときにlearn_cross_entropyと - // 値が比較しにくくて困るのでqsearch()を用いる。 - // EvalHashは事前に無効化してある。(そうしないと毎回同じ値が返ってしまう) + // Evaluation value for shallow search + // The value of evaluate() may be used, but when calculating loss, learn_cross_entropy and + // Use qsearch() because it is difficult to compare the values. + // EvalHash has been disabled in advance. (If not, the same value will be returned every time) auto r = qsearch(pos); auto shallow_value = r.first; @@ -1690,34 +1691,34 @@ void LearnerThink::calc_loss(size_t thread_id, uint64_t done) pos.undo_move(*it); } - // 深い探索の評価値 + // Evaluation value of deep search auto deep_value = (Value)ps.score; - // 注) このコードは、learnコマンドでeval_limitを指定しているときのことを考慮してない。 + // Note) This code does not consider when eval_limit is specified in the learn command. - // --- 誤差の計算 + // --- error calculation #if !defined(LOSS_FUNCTION_IS_ELMO_METHOD) auto grad = calc_grad(deep_value, shallow_value, ps); - // rmse的なもの + // something like rmse sum_error += grad*grad; - // 勾配の絶対値を足したもの + // Add the absolute value of the gradient sum_error2 += abs(grad); - // 評価値の差の絶対値を足したもの + // Add the absolute value of the difference between the evaluation values sum_error3 += abs(shallow_value - deep_value); #endif - // --- 交差エントロピーの計算 + // --- calculation of cross entropy - // とりあえずelmo methodの時だけ勝率項と勝敗項に関して - // 交差エントロピーを計算して表示させる。 + // For the time being, regarding the win rate and loss terms only in the elmo method + // Calculate and display the cross entropy. -#if defined ( LOSS_FUNCTION_IS_ELMO_METHOD ) +#if defined (LOSS_FUNCTION_IS_ELMO_METHOD) double test_cross_entropy_eval, test_cross_entropy_win, test_cross_entropy; double test_entropy_eval, test_entropy_win, test_entropy; calc_cross_entropy(deep_value, shallow_value, ps, test_cross_entropy_eval, test_cross_entropy_win, test_cross_entropy, test_entropy_eval, test_entropy_win, test_entropy); - // 交差エントロピーの合計は定義的にabs()をとる必要がない。 + // The total cross entropy need not be abs() by definition. test_sum_cross_entropy_eval += test_cross_entropy_eval; test_sum_cross_entropy_win += test_cross_entropy_win; test_sum_cross_entropy += test_cross_entropy; @@ -1727,31 +1728,31 @@ void LearnerThink::calc_loss(size_t thread_id, uint64_t done) sum_norm += (double)abs(shallow_value); #endif - // 教師の指し手と浅い探索のスコアが一致するかの判定 + // Determine if the teacher's move and the score of the shallow search match { auto r = search(pos,1); if ((uint16_t)r.second[0] == ps.move) move_accord_count.fetch_add(1, std::memory_order_relaxed); } - // こなしたのでタスク一つ減る + // Reduced one task because I did it --task_count; }; - // 定義したタスクをslaveに投げる。 + // Throw the defined task to slave. task_dispatcher.push_task_async(task); } - // 自分自身もslaveとして参加する + // join yourself as a slave task_dispatcher.on_idle(thread_id); - // すべてのtaskの完了を待つ + // wait for all tasks to complete while (task_count) sleep(1); #if !defined(LOSS_FUNCTION_IS_ELMO_METHOD) - // rmse = root mean square error : 平均二乗誤差 - // mae = mean absolute error : 平均絶対誤差 + // rmse = root mean square error: mean square error + // mae = mean absolute error: mean absolute error auto dsig_rmse = std::sqrt(sum_error / (sfen_for_mse.size() + epsilon)); auto dsig_mae = sum_error2 / (sfen_for_mse.size() + epsilon); auto eval_mae = sum_error3 / (sfen_for_mse.size() + epsilon); @@ -1765,8 +1766,8 @@ void LearnerThink::calc_loss(size_t thread_id, uint64_t done) latest_loss_count += sr.sfen_for_mse.size(); #endif - // learn_cross_entropyは、機械学習の世界ではtrain cross entropyと呼ぶべきかも知れないが、 - // 頭文字を略するときに、lceと書いて、test cross entropy(tce)と区別出来たほうが嬉しいのでこうしてある。 +// learn_cross_entropy may be called train cross entropy in the world of machine learning, +// When omitting the acronym, it is nice to be able to distinguish it from test cross entropy(tce) by writing it as lce. if (sr.sfen_for_mse.size() && done) { @@ -1795,7 +1796,7 @@ void LearnerThink::calc_loss(size_t thread_id, uint64_t done) cout << "Error! : sr.sfen_for_mse.size() = " << sr.sfen_for_mse.size() << " , done = " << done << endl; } - // 次回のために0クリアしておく。 + // Clear 0 for next time. learn_sum_cross_entropy_eval = 0.0; learn_sum_cross_entropy_win = 0.0; learn_sum_cross_entropy = 0.0; @@ -1819,11 +1820,11 @@ void LearnerThink::thread_worker(size_t thread_id) while (true) { - // mseの表示(これはthread 0のみときどき行う) - // ファイルから読み込んだ直後とかでいいような…。 + // display mse (this is sometimes done only for thread 0) + // Immediately after being read from the file... #if defined(EVAL_NNUE) - // 更新中に評価関数を使わないようにロックする。 + // Lock the evaluation function so that it is not used during updating. shared_lock read_lock(nn_mutex, defer_lock); if (sr.next_update_weights <= sr.total_done || (thread_id != 0 && !read_lock.try_lock())) @@ -1833,20 +1834,20 @@ void LearnerThink::thread_worker(size_t thread_id) { if (thread_id != 0) { - // thread_id == 0以外は、待機。 + // Wait except thread_id == 0. if (stop_flag) break; - // rmseの計算などを並列化したいのでtask()が積まれていればそれを処理する。 + // I want to parallelize rmse calculation etc., so if task() is loaded, process it. task_dispatcher.on_idle(thread_id); continue; } else { - // thread_id == 0だけが以下の更新処理を行なう。 + // Only thread_id == 0 performs the following update process. - // 初回はweight配列の更新は行わない。 + // The weight array is not updated for the first time. if (sr.next_update_weights == 0) { sr.next_update_weights += mini_batch_size; @@ -1854,33 +1855,33 @@ void LearnerThink::thread_worker(size_t thread_id) } #if !defined(EVAL_NNUE) - // 現在時刻を出力。毎回出力する。 + // Output the current time. Output every time. std::cout << sr.total_done << " sfens , at " << now_string() << std::endl; - // このタイミングで勾配をweight配列に反映。勾配の計算も1M局面ごとでmini-batch的にはちょうどいいのでは。 + // Reflect the gradient in the weight array at this timing. The calculation of the gradient is just right for each 1M phase in terms of mini-batch. Eval::update_weights(epoch , freeze); - // デバッグ用にepochと現在のetaを表示してやる。 + // Display epoch and current eta for debugging. std::cout << "epoch = " << epoch << " , eta = " << Eval::get_eta() << std::endl; #else { - // パラメータの更新 + // update parameters - // 更新中に評価関数を使わないようにロックする。 + // Lock the evaluation function so that it is not used during updating. lock_guard write_lock(nn_mutex); Eval::NNUE::UpdateParameters(epoch); } #endif ++epoch; - // 10億局面ごとに1回保存、ぐらいの感じで。 + // Save once every 1 billion phases. - // ただし、update_weights(),calc_rmse()している間の時間経過は無視するものとする。 + // However, the elapsed time during update_weights() and calc_rmse() is ignored. if (++sr.save_count * mini_batch_size >= eval_save_interval) { sr.save_count = 0; - // この間、gradientの計算が進むと値が大きくなりすぎて困る気がするので他のスレッドを停止させる。 + // During this time, as the gradient calculation proceeds, the value becomes too large and I feel annoyed, so stop other threads. const bool converged = save(); if (converged) { @@ -1890,33 +1891,33 @@ void LearnerThink::thread_worker(size_t thread_id) } } - // rmseを計算する。1万局面のサンプルに対して行う。 - // 40コアでやると100万局面ごとにupdate_weightsするとして、特定のスレッドが - // つきっきりになってしまうのあまりよくないような気も…。 + // Calculate rmse. This is done for samples of 10,000 phases. + // If you do with 40 cores, update_weights every 1 million phases + // I don't think it's so good to be tiring. static uint64_t loss_output_count = 0; if (++loss_output_count * mini_batch_size >= loss_output_interval) { loss_output_count = 0; - // 今回処理した件数 + // Number of cases processed this time uint64_t done = sr.total_done - sr.last_done; - // lossの計算 + // loss calculation calc_loss(thread_id , done); #if defined(EVAL_NNUE) Eval::NNUE::CheckHealth(); #endif - // どこまで集計したかを記録しておく。 + // Make a note of how far you have totaled. sr.last_done = sr.total_done; } - // 次回、この一連の処理は、次回、mini_batch_sizeだけ処理したときに再度やって欲しい。 + // Next time, I want you to do this series of processing again when you process only mini_batch_size. sr.next_update_weights += mini_batch_size; - // main thread以外は、このsr.next_update_weightsの更新を待っていたので - // この値が更新されると再度動き始める。 + // Since I was waiting for the update of this sr.next_update_weights except the main thread, + // Once this value is updated, it will start moving again. } } @@ -1924,17 +1925,17 @@ void LearnerThink::thread_worker(size_t thread_id) RetryRead:; if (!sr.read_to_thread_buffer(thread_id, ps)) { - // 自分のスレッド用の局面poolを使い尽くした。 - // 局面がもうほとんど残っていないということだから、 - // 他のスレッドもすべて終了させる。 + // ran out of thread pool for my thread. + // Because there are almost no phases left, + // Terminate all other threads. stop_flag = true; break; } - // 評価値が学習対象の値を超えている。 - // この局面情報を無視する。 - if (eval_limit < abs(ps.score)) + // The evaluation value exceeds the learning target value. + // Ignore this aspect information. + if (eval_limit & afs , vector& a_count) { uint64_t total_sfen_count = 0; for (auto c : a_count) total_sfen_count += c; - // 書き出した局面数 + // number of exported phases uint64_t write_sfen_count = 0; - // 進捗をこの局面数ごとに画面に出力する。 + // Output the progress on the screen for each phase. const uint64_t buffer_size = 10000000; auto print_status = [&]() { - // 10M局面ごと、もしくは、すべての書き出しが終わったときに進捗を出力する + // Output progress every 10M phase or when all writing is completed if (((write_sfen_count % buffer_size) == 0) || (write_sfen_count == total_sfen_count)) cout << write_sfen_count << " / " << total_sfen_count << endl; @@ -2209,7 +2210,7 @@ void shuffle_write(const string& output_file_name , PRNG& prng , vector fstream fs(output_file_name, ios::out | ios::binary); - // 教師局面の合計 + // total teacher positions uint64_t sum = 0; for (auto c : a_count) sum += c; @@ -2218,22 +2219,22 @@ void shuffle_write(const string& output_file_name , PRNG& prng , vector { auto r = prng.rand(sum); - // fs[0]のファイルに格納されている局面 ... fs[1]のファイルに格納されている局面 ... - // のようにひと続きになっているものと考えて、rがどのファイルに格納されている局面を指しているかを確定させる。 - // ファイルの中身はシャッフルされているので、そのファイルから次の要素を1つ取ってくれば良い。 - // それぞれのファイルにはa_count[x]ずつ局面が残っているので、この処理は以下のように書ける。 + // Aspects stored in fs[0] file ... Aspects stored in fs[1] file ... + //Think of it as a series like, and determine in which file r is pointing. + // The contents of the file are shuffled, so you can take the next element from that file. + // Each file has a_count[x] phases, so this process can be written as follows. uint64_t n = 0; while (a_count[n] <= r) r -= a_count[n++]; - // これでnが確定した。忘れないうちに残り件数を減らしておく。 + // This confirms n. Before you forget it, reduce the remaining number. --a_count[n]; --sum; PackedSfenValue psv; - // これ、パフォーマンスあんまりよくないまでまとめて読み書きしたほうが良いのだが…。 + // It's better to read and write all at once until the performance is not so good... if (afs[n].read((char*)&psv, sizeof(PackedSfenValue))) { fs.write((char*)&psv, sizeof(PackedSfenValue)); @@ -2246,47 +2247,47 @@ void shuffle_write(const string& output_file_name , PRNG& prng , vector cout << "done!" << endl; } -// 教師局面のシャッフル "learn shuffle"コマンドの下請け。 -// output_file_name : シャッフルされた教師局面が書き出される出力ファイル名 +// Subcontracting the teacher shuffle "learn shuffle" command. +// output_file_name: name of the output file where the shuffled teacher positions will be written void shuffle_files(const vector& filenames , const string& output_file_name , uint64_t buffer_size ) { - // 出力先のフォルダは - // tmp/ 一時書き出し用 + // The destination folder is + // tmp/ for temporary writing - // テンポラリファイルはbuffer_size局面ずつtmp/フォルダにいったん書き出す。 - // 例えば、buffer_size = 20Mならば 20M*40bytes = 800MBのバッファが必要。 - // メモリが少ないPCでは、ここを減らすと良いと思う。 - // ただし、あまりファイル数が増えるとOSの制限などから同時にopen出来なくなる。 - // Windowsだと1プロセス512という制約があったはずなので、ここでopen出来るのが500として、 - // 現在の設定で500ファイル×20M = 10G = 100億局面が限度。 + // Temporary file is written to tmp/ folder for each buffer_size phase. + // For example, if buffer_size = 20M, you need a buffer of 20M*40bytes = 800MB. + // In a PC with a small memory, it would be better to reduce this. + // However, if the number of files increases too much, it will not be possible to open at the same time due to OS restrictions. + // There should have been a limit of 512 per process on Windows, so you can open here as 500, + // The current setting is 500 files x 20M = 10G = 10 billion phases. PSVector buf; buf.resize(buffer_size); - // ↑のバッファ、どこまで使ったかを示すマーカー + // ↑ buffer, a marker that indicates how much you have used uint64_t buf_write_marker = 0; - // 書き出すファイル名(連番なのでインクリメンタルカウンター) + // File name to write (incremental counter because it is a serial number) uint64_t write_file_count = 0; - // シャッフルするための乱数 + // random number to shuffle PRNG prng((std::random_device())()); - // テンポラリファイルの名前を生成する + // generate the name of the temporary file auto make_filename = [](uint64_t i) { return "tmp/" + to_string(i) + ".bin"; }; - // 書き出したtmp/フォルダのファイル、それぞれに格納されている教師局面の数 + // Exported files in tmp/ folder, number of teacher positions stored in each vector a_count; auto write_buffer = [&](uint64_t size) { - // buf[0]~buf[size-1]までをshuffle + // shuffle from buf[0] to buf[size-1] for (uint64_t i = 0; i < size; ++i) swap(buf[i], buf[(uint64_t)(prng.rand(size - i) + i)]); - // ファイルに書き出す + // write to a file fstream fs; fs.open(make_filename(write_file_count++), ios::out | ios::binary); fs.write((char*)&buf[0], size * sizeof(PackedSfenValue)); @@ -2299,7 +2300,7 @@ void shuffle_files(const vector& filenames , const string& output_file_n Dependency::mkdir("tmp"); - // 10M局面の細切れファイルとしてシャッフルして書き出す。 + // Shuffle and export as a 10M phase shredded file. for (auto filename : filenames) { fstream fs(filename, ios::in | ios::binary); @@ -2308,57 +2309,57 @@ void shuffle_files(const vector& filenames , const string& output_file_n if (++buf_write_marker == buffer_size) write_buffer(buffer_size); - // sizeof(PackedSfenValue)単位で読み込んでいき、 - // 最後に残っている端数は無視する。(fs.readで失敗するのでwhileを抜ける) - // (最後に残っている端数は、教師生成時に途中で停止させたために出来た中途半端なデータだと思われる。) + // Read in units of sizeof(PackedSfenValue), + // Ignore the last remaining fraction. (Fails in fs.read, so exit while) + // (The remaining fraction seems to be half-finished data that was created because it was stopped halfway during teacher generation.) } if (buf_write_marker != 0) write_buffer(buf_write_marker); - // シャッフルされたファイルがwrite_file_count個だけ書き出された。 - // 2pass目として、これをすべて同時にオープンし、ランダムに1つずつ選択して1局面ずつ読み込めば - // これにてシャッフルされたことになる。 + // Only shuffled files have been written write_file_count. + // As a second pass, if you open all of them at the same time, select one at random and load one phase at a time + // Now you have shuffled. - // シャツフルする元ファイル+tmpファイル+書き出すファイルで元ファイルの3倍のストレージ容量が必要になる。 - // 100億局面400GBなのでシャッフルするために1TBのSSDでは足りない。 - // tmpに書き出しが終わったこのタイミングで元ファイルを消す(あるいは手で削除してしまう)なら、 - // 元ファイルの2倍程度のストレージ容量で済む。 - // だから、元ファイルを消すためのオプションを用意すべきかも知れない。 + // Original file for shirt full + tmp file + file to write requires 3 times the storage capacity of the original file. + // 1 billion SSD is not enough for shuffling because it is 400GB for 10 billion phases. + // If you want to delete (or delete by hand) the original file at this point after writing to tmp, + // The storage capacity is about twice that of the original file. + // So, maybe we should have an option to delete the original file. - // ファイルの同時openをしている。これがFOPEN_MAXなどを超える可能性は高い。 - // その場合、buffer_sizeを調整して、ファイルの数を減らすよりない。 + // Files are opened at the same time. It is highly possible that this will exceed FOPEN_MAX. + // In that case, rather than adjusting buffer_size to reduce the number of files. vector afs; for (uint64_t i = 0; i < write_file_count; ++i) afs.emplace_back(fstream(make_filename(i),ios::in | ios::binary)); - // 下請け関数に丸投げして終わり。 + // Throw to the subcontract function and end. shuffle_write(output_file_name, prng, afs, a_count); } -// 教師局面のシャッフル "learn shuffleq"コマンドの下請け。 -// こちらは1passで書き出す。 -// output_file_name : シャッフルされた教師局面が書き出される出力ファイル名 +// Subcontracting the teacher shuffle "learn shuffleq" command. +// This is written in 1 pass. +// output_file_name: name of the output file where the shuffled teacher positions will be written void shuffle_files_quick(const vector& filenames, const string& output_file_name) { - // 読み込んだ局面数 + // number of phases read uint64_t read_sfen_count = 0; - // シャッフルするための乱数 + // random number to shuffle PRNG prng((std::random_device())()); - // ファイルの数 + // number of files size_t file_count = filenames.size(); - // filenamesのファイルそれぞれに格納されている教師局面の数 + // Number of teacher positions stored in each file in filenames vector a_count(file_count); - // それぞれのファイルの教師局面の数をカウントする。 + // Count the number of teacher aspects in each file. vector afs(file_count); - for (size_t i = 0; i < file_count ; ++i) + for (size_t i = 0; i & filenames, const string& output_f fs.open(filename, ios::in | ios::binary); fs.seekg(0, fstream::end); uint64_t eofPos = (uint64_t)fs.tellg(); - fs.clear(); // これをしないと次のseekに失敗することがある。 + fs.clear(); // Otherwise, the next seek may fail. fs.seekg(0, fstream::beg); uint64_t begPos = (uint64_t)fs.tellg(); uint64_t file_size = eofPos - begPos; uint64_t sfen_count = file_size / sizeof(PackedSfenValue); a_count[i] = sfen_count; - // 各ファイルに格納されていたsfenの数を出力する。 + // Output the number of sfen stored in each file. cout << filename << " = " << sfen_count << " sfens." << endl; } - // それぞれのファイルのファイルサイズがわかったので、 - // これらをすべて同時にオープンし(すでにオープンされている)、 - // ランダムに1つずつ選択して1局面ずつ読み込めば - // これにてシャッフルされたことになる。 + // Since we know the file size of each file, + // open them all at once (already open), + // Select one at a time and load one phase at a time + // Now you have shuffled. - // 下請け関数に丸投げして終わり。 + // Throw to the subcontract function and end. shuffle_write(output_file_name, prng, afs, a_count); } -// 教師局面のシャッフル "learn shufflem"コマンドの下請け。 -// メモリに丸読みして指定ファイル名で書き出す。 +// Subcontracting the teacher shuffle "learn shufflem" command. +// Read the whole memory and write it out with the specified file name. void shuffle_files_on_memory(const vector& filenames,const string output_file_name) { PSVector buf; @@ -2397,14 +2398,14 @@ void shuffle_files_on_memory(const vector& filenames,const string output std::cout << "read : " << filename << std::endl; read_file_to_memory(filename, [&buf](uint64_t size) { assert((size % sizeof(PackedSfenValue)) == 0); - // バッファを拡充して、前回の末尾以降に読み込む。 + // Expand the buffer and read after the last end. uint64_t last = buf.size(); buf.resize(last + size / sizeof(PackedSfenValue)); return (void*)&buf[last]; }); } - // buf[0]~buf[size-1]までをshuffle + // shuffle from buf[0] to buf[size-1] PRNG prng((std::random_device())()); uint64_t size = (uint64_t)buf.size(); std::cout << "shuffle buf.size() = " << size << std::endl; @@ -2413,7 +2414,7 @@ void shuffle_files_on_memory(const vector& filenames,const string output std::cout << "write : " << output_file_name << endl; - // 書き出すファイルが2GBを超えるとfstream::write一発では書き出せないのでwrapperを用いる。 + // If the file to be written exceeds 2GB, it cannot be written in one shot with fstream::write, so use wrapper. write_memory_to_file(output_file_name, (void*)&buf[0], (uint64_t)sizeof(PackedSfenValue)*(uint64_t)buf.size()); std::cout << "..shuffle_on_memory done." << std::endl; @@ -2426,7 +2427,7 @@ void convert_bin(const vector& filenames, const string& output_file_name uint64_t filtered_size = 0; auto th = Threads.main(); auto &tpos = th->rootPos; - // plain形式の雑巾をやねうら王用のpackedsfenvalueに変換する + // convert plain rag to packed sfenvalue for Yaneura king fs.open(output_file_name, ios::app | ios::binary); StateListPtr states; for (auto filename : filenames) { @@ -2437,9 +2438,8 @@ void convert_bin(const vector& filenames, const string& output_file_name PackedSfenValue p; data_size = 0; filtered_size = 0; - p.gamePly = 1; // apery形式では含まれない。一応初期化するべし + p.gamePly = 1; // Not included in apery format. Should be initialized bool ignore_flag = false; - while (std::getline(ifs, line)) { std::stringstream ss(line); std::string token; @@ -2463,7 +2463,7 @@ void convert_bin(const vector& filenames, const string& output_file_name if(temp < ply_minimum || temp > ply_maximum){ ignore_flag = true; } - p.gamePly = uint16_t(temp); // 此処のキャストいらない? + p.gamePly = uint16_t(temp); // No cast here? if (interpolate_eval != 0){ p.score = min(3000, interpolate_eval * temp); } @@ -2471,7 +2471,7 @@ void convert_bin(const vector& filenames, const string& output_file_name else if (token == "result") { int temp; ss >> temp; - p.game_result = int8_t(temp); // 此処のキャストいらない? + p.game_result = int8_t(temp); // Do you need a cast here? if (interpolate_eval){ p.score = p.score * p.game_result; } @@ -2685,7 +2685,6 @@ void convert_bin_from_pgn_extract(const vector& filenames, const string& std::cout << now_string() << " all done" << std::endl; ofs.close(); } - //void convert_plain(const vector& filenames , const string& output_file_name) //{ // Position tpos; @@ -2694,14 +2693,14 @@ void convert_bin_from_pgn_extract(const vector& filenames, const string& // for (auto filename : filenames) { // std::cout << "convert " << filename << " ... "; // -// // ひたすらpackedsfenvalueをテキストに変換する +// // Just convert packedsfenvalue to text // std::fstream fs; // fs.open(filename, ios::in | ios::binary); // PackedSfenValue p; // while (true) // { // if (fs.read((char*)&p, sizeof(PackedSfenValue))) { -// // plain textとして書き込む +// // write as plain text // ofs << "sfen " << tpos.sfen_unpack(p.sfen) << std::endl; // ofs << "move " << to_usi_string(Move(p.move)) << std::endl; // ofs << "score " << p.score << std::endl; @@ -2720,7 +2719,7 @@ void convert_bin_from_pgn_extract(const vector& filenames, const string& // std::cout << "all done" << std::endl; //} -// 生成した棋譜からの学習 +// Learning from the generated game record void learn(Position&, istringstream& is) { auto thread_num = (int)Options["Threads"]; @@ -2729,62 +2728,62 @@ void learn(Position&, istringstream& is) LearnerThink learn_think(sr); vector filenames; - // mini_batch_size デフォルトで1M局面。これを大きくできる。 + // mini_batch_size 1M aspect by default. This can be increased. auto mini_batch_size = LEARN_MINI_BATCH_SIZE; - // ループ回数(この回数だけ棋譜ファイルを読み込む) + // Number of loops (read the game record file this number of times) int loop = 1; - // 棋譜ファイル格納フォルダ(ここから相対pathで棋譜ファイルを取得) + // Game file storage folder (get game file with relative path from here) string base_dir; string target_dir; - // 0であれば、デフォルト値になる。 + // If 0, it will be the default value. double eta1 = 0.0; double eta2 = 0.0; double eta3 = 0.0; - uint64_t eta1_epoch = 0; // defaultではeta2は適用されない - uint64_t eta2_epoch = 0; // defaultではeta3は適用されない + uint64_t eta1_epoch = 0; // eta2 is not applied by default + uint64_t eta2_epoch = 0; // eta3 is not applied by default #if defined(USE_GLOBAL_OPTIONS) - // あとで復元するために保存しておく。 + // Save it for later restore. auto oldGlobalOptions = GlobalOptions; - // eval hashにhitするとrmseなどの計算ができなくなるのでオフにしておく。 + // If you hit the eval hash, you can not calculate rmse etc. so turn it off. GlobalOptions.use_eval_hash = false; - // 置換表にhitするとそこで以前の評価値で枝刈りがされることがあるのでオフにしておく。 + // If you hit the replacement table, pruning may occur at the previous evaluation value, so turn it off. GlobalOptions.use_hash_probe = false; #endif - // --- 教師局面をシャッフルするだけの機能 + // --- Function that only shuffles the teacher aspect - // 通常シャッフル + // normal shuffle bool shuffle_normal = false; uint64_t buffer_size = 20000000; - // それぞれのファイルがシャッフルされていると仮定しての高速シャッフル + // fast shuffling assuming each file is shuffled bool shuffle_quick = false; - // メモリにファイルを丸読みしてシャッフルする機能。(要、ファイルサイズのメモリ) + // A function to read the entire file in memory and shuffle it. (Requires file size memory) bool shuffle_on_memory = false; - // packed sfenの変換。plainではsfen(string), 評価値(整数), 指し手(例:7g7f, string)、結果(負け-1、勝ち1、引き分け0)からなる + // Conversion of packed sfen. In plain, it consists of sfen(string), evaluation value (integer), move (eg 7g7f, string), result (loss-1, win 1, draw 0) bool use_convert_plain = false; - // plain形式の教師をやねうら王のbinに変換する + // convert plain format teacher to Yaneura King's bin bool use_convert_bin = false; int ply_minimum = 0; int ply_maximum = 114514; bool interpolate_eval = 0; - // pgn-extract形式の教師をやねうら王のbinに変換する + // convert teacher in pgn-extract format to Yaneura King's bin bool use_convert_bin_from_pgn_extract = false; - // それらのときに書き出すファイル名(デフォルトでは"shuffled_sfen.bin") + // File name to write in those cases (default is "shuffled_sfen.bin") string output_file_name = "shuffled_sfen.bin"; - // 教師局面の深い探索での評価値の絶対値が、この値を超えていたらその局面は捨てる。 + // If the absolute value of the evaluation value in the deep search of the teacher phase exceeds this value, that phase is discarded. int eval_limit = 32000; - // 評価関数ファイルの保存は終了間際の1回に限定するかのフラグ。 + // Flag to save the evaluation function file only once near the end. bool save_only_once = false; - // 教師局面を先読みしている分に関してシャッフルする。(1000万局面単位ぐらいのシャッフル) - // 事前にシャッフルされているファイルを渡すならオンにすれば良い。 + // Shuffle about what you are pre-reading on the teacher aspect. (Shuffle of about 10 million phases) + // Turn on if you want to pass a pre-shuffled file. bool no_shuffle = false; #if defined (LOSS_FUNCTION_IS_ELMO_METHOD) @@ -2794,15 +2793,15 @@ void learn(Position&, istringstream& is) ELMO_LAMBDA_LIMIT = 32000; #endif - // 割引率。これを0以外にすると、PV終端以外でも勾配を加算する。(そのとき、この割引率を適用する) + // Discount rate. If this is set to a value other than 0, the slope will be added even at other than the PV termination. (At that time, apply this discount rate) double discount_rate = 0; - // if (gamePly < rand(reduction_gameply)) continue; - // のようにして、序盤を学習対象から程よく除外するためのオプション - // 1にしてあるとrand(1)==0なので、何も除外されない。 + // if (gamePly freeze = {}; #if defined(EVAL_NNUE) @@ -2818,7 +2817,7 @@ void learn(Position&, istringstream& is) string validation_set_file_name; - // ファイル名が後ろにずらずらと書かれていると仮定している。 + // Assume the filenames are staggered. while (true) { string option; @@ -2827,26 +2826,26 @@ void learn(Position&, istringstream& is) if (option == "") break; - // mini-batchの局面数を指定 + // specify the number of phases of mini-batch if (option == "bat") { is >> mini_batch_size; - mini_batch_size *= 10000; // 単位は万 + mini_batch_size *= 10000; // Unit is ten thousand } - // 棋譜が格納されているフォルダを指定して、根こそぎ対象とする。 + // Specify the folder in which the game record is stored and make it the rooting target. else if (option == "targetdir") is >> target_dir; - // ループ回数の指定 + // Specify the number of loops else if (option == "loop") is >> loop; - // 棋譜ファイル格納フォルダ(ここから相対pathで棋譜ファイルを取得) + // Game file storage folder (get game file with relative path from here) else if (option == "basedir") is >> base_dir; - // ミニバッチのサイズ + // Mini batch size else if (option == "batchsize") is >> mini_batch_size; - // 学習率 + // learning rate else if (option == "eta") is >> eta1; else if (option == "eta1") is >> eta1; // alias else if (option == "eta2") is >> eta2; @@ -2857,10 +2856,10 @@ void learn(Position&, istringstream& is) else if (option == "use_draw_in_training") is >> use_draw_in_training; else if (option == "use_draw_in_validation") is >> use_draw_in_validation; else if (option == "use_hash_in_training") is >> use_hash_in_training; - // 割引率 + // Discount rate else if (option == "discount_rate") is >> discount_rate; - // KK/KKP/KPP/KPPPの学習なし。 + // No learning of KK/KKP/KPP/KPPP. else if (option == "freeze_kk") is >> freeze[0]; else if (option == "freeze_kkp") is >> freeze[1]; else if (option == "freeze_kpp") is >> freeze[2]; @@ -2882,7 +2881,7 @@ void learn(Position&, istringstream& is) #endif else if (option == "reduction_gameply") is >> reduction_gameply; - // シャッフル関連 + // shuffle related else if (option == "shuffle") shuffle_normal = true; else if (option == "buffer_size") is >> buffer_size; else if (option == "shuffleq") shuffle_quick = true; @@ -2892,7 +2891,7 @@ void learn(Position&, istringstream& is) else if (option == "eval_limit") is >> eval_limit; else if (option == "save_only_once") save_only_once = true; else if (option == "no_shuffle") no_shuffle = true; - + #if defined(EVAL_NNUE) else if (option == "nn_batch_size") is >> nn_batch_size; else if (option == "newbob_decay") is >> newbob_decay; @@ -2903,13 +2902,13 @@ void learn(Position&, istringstream& is) else if (option == "loss_output_interval") is >> loss_output_interval; else if (option == "mirror_percentage") is >> mirror_percentage; else if (option == "validation_set_file_name") is >> validation_set_file_name; - - // 雑巾のconvert関連 + + // Rabbit convert related else if (option == "convert_plain") use_convert_plain = true; else if (option == "convert_bin") use_convert_bin = true; else if (option == "interpolate_eval") is >> interpolate_eval; - else if (option == "convert_bin_from_pgn-extract") use_convert_bin_from_pgn_extract = true; - // さもなくば、それはファイル名である。 + else if (option == "convert_bin_from_pgn-extract") use_convert_bin_from_pgn_extract = true; + // Otherwise, it's a filename. else filenames.push_back(option); } @@ -2918,25 +2917,25 @@ void learn(Position&, istringstream& is) cout << "learn command , "; - // OpenMP無効なら警告を出すように。 + // Issue a warning if OpenMP is disabled. #if !defined(_OPENMP) cout << "Warning! OpenMP disabled." << endl; #endif - // 学習棋譜ファイルの表示 + // Display learning game file if (target_dir != "") { string kif_base_dir = Path::Combine(base_dir, target_dir); - // このフォルダを根こそぎ取る。base_dir相対にしておく。 + // Remove this folder. Keep it relative to base_dir. #if defined(_MSC_VER) - // std::tr2を使用するとwaring C4996が出るので抑制。 - // ※ std::tr2は、std:c++14 の下では既定で非推奨の警告を出し、/std:c++17 では既定で削除された。 + // If you use std::tr2, warning C4996 will appear, so suppress it. + // * std::tr2 issued a deprecation warning by default under std:c++14, and was deleted by default in /std:c++17. #pragma warning(push) #pragma warning(disable:4996) namespace sys = std::filesystem; - sys::path p(kif_base_dir); // 列挙の起点 + sys::path p(kif_base_dir); // Origin of enumeration std::for_each(sys::directory_iterator(p), sys::directory_iterator(), [&](const sys::path& p) { if (sys::is_regular_file(p)) @@ -2952,17 +2951,17 @@ void learn(Position&, istringstream& is) return std::equal(ending.rbegin(), ending.rend(), value.rbegin()); }; - // 仕方ないのでdirent.hを用いて読み込む。 - DIR *dp; // ディレクトリへのポインタ - dirent* entry; // readdir() で返されるエントリーポイント + // It can't be helped, so read it using dirent.h. + DIR *dp; // pointer to directory + dirent* entry; // entry point returned by readdir() dp = opendir(kif_base_dir.c_str()); if (dp != NULL) { do { entry = readdir(dp); - // ".bin"で終わるファイルのみを列挙 - // → 連番でファイル生成するときにこの制約ちょっと嫌だな…。 + // Only list files ending with ".bin" + // →I hate this restriction when generating files with serial numbers... if (entry != NULL && ends_with(entry->d_name, ".bin") ) { //cout << entry->d_name << endl; @@ -2986,7 +2985,7 @@ void learn(Position&, istringstream& is) cout << "base dir : " << base_dir << endl; cout << "target dir : " << target_dir << endl; - // シャッフルモード + // shuffle mode if (shuffle_normal) { cout << "buffer_size : " << buffer_size << endl; @@ -3008,11 +3007,11 @@ void learn(Position&, istringstream& is) } //if (use_convert_plain) //{ - // is_ready(true); - // cout << "convert_plain.." << endl; - // convert_plain(filenames,output_file_name); - // return; - // + // is_ready(true); + // cout << "convert_plain.." << endl; + // convert_plain(filenames,output_file_name); + // return; + // //} if (use_convert_bin) { @@ -3035,9 +3034,9 @@ void learn(Position&, istringstream& is) cout << "save_only_once : " << (save_only_once ? "true" : "false") << endl; cout << "no_shuffle : " << (no_shuffle ? "true" : "false") << endl; - // ループ回数分だけファイル名を突っ込む。 + // Insert the file name for the number of loops. for (int i = 0; i < loop; ++i) - // sfen reader、逆順で読むからここでreverseしておく。すまんな。 + // sfen reader, I'll read it in reverse order so I'll reverse it here. I'm sorry. for (auto it = filenames.rbegin(); it != filenames.rend(); ++it) sr.filenames.push_back(Path::Combine(base_dir, *it)); @@ -3062,7 +3061,7 @@ void learn(Position&, istringstream& is) #endif cout << "discount rate : " << discount_rate << endl; - // reduction_gameplyに0を設定されるとrand(0)が0除算になってしまうので1に補正。 + // If reduction_gameply is set to 0, rand(0) will be divided by 0, so correct it to 1. reduction_gameply = max(reduction_gameply, 1); cout << "reduction_gameply : " << reduction_gameply << endl; @@ -3084,18 +3083,18 @@ void learn(Position&, istringstream& is) #endif // ----------------------------------- - // 各種初期化 + // various initialization // ----------------------------------- cout << "init.." << endl; - // 評価関数パラメーターの読み込み + // Read evaluation function parameters is_ready(true); #if !defined(EVAL_NNUE) cout << "init_grad.." << endl; - // 評価関数パラメーターの勾配配列の初期化 + // Initialize gradient array of merit function parameters Eval::init_grad(eta1,eta1_epoch,eta2,eta2_epoch,eta3); #else cout << "init_training.." << endl; @@ -3108,7 +3107,7 @@ void learn(Position&, istringstream& is) #endif #if 0 - // 平手の初期局面に対して1.0の勾配を与えてみるテスト。 + // A test to give a gradient of 1.0 to the initial stage of Hirate. pos.set_hirate(); cout << Eval::evaluate(pos) << endl; //Eval::print_eval_stat(pos); @@ -3121,7 +3120,7 @@ void learn(Position&, istringstream& is) cout << "init done." << endl; - // その他、オプション設定を反映させる。 + // Reflect other option settings. learn_think.discount_rate = discount_rate; learn_think.eval_limit = eval_limit; learn_think.save_only_once = save_only_once; @@ -3137,20 +3136,20 @@ void learn(Position&, istringstream& is) learn_think.loss_output_interval = loss_output_interval; learn_think.mirror_percentage = mirror_percentage; - // 局面ファイルをバックグラウンドで読み込むスレッドを起動 - // (これを開始しないとmseの計算が出来ない。) + // Start a thread that loads the phase file in the background + // (If this is not started, mse cannot be calculated.) learn_think.start_file_read_worker(); learn_think.mini_batch_size = mini_batch_size; if (validation_set_file_name.empty()) { - // mse計算用にデータ1万件ほど取得しておく。 + // Get about 10,000 data for mse calculation. sr.read_for_mse(); } else { sr.read_validation_set(validation_set_file_name, eval_limit); } - // この時点で一度rmseを計算(0 sfenのタイミング) + // Calculate rmse once at this point (timing of 0 sfen) // sr.calc_rmse(); #if defined(EVAL_NNUE) if (newbob_decay != 1.0) { @@ -3163,17 +3162,17 @@ void learn(Position&, istringstream& is) #endif // ----------------------------------- - // 評価関数パラメーターの学習の開始 + // start learning evaluation function parameters // ----------------------------------- - // 学習開始。 + // Start learning. learn_think.go_think(); - // 最後に一度保存。 + // Save once at the end. learn_think.save(true); #if defined(USE_GLOBAL_OPTIONS) - // GlobalOptionsの復元。 + // Restore Global Options. GlobalOptions = oldGlobalOptions; #endif } @@ -3186,4 +3185,4 @@ void learn(Position&, istringstream& is) #endif -#endif // EVAL_LEARN +#endif // EVAL_LEARN \ No newline at end of file diff --git a/src/learn/learning_tools.cpp b/src/learn/learning_tools.cpp index d3a7858f..e3bd6f68 100644 --- a/src/learn/learning_tools.cpp +++ b/src/learn/learning_tools.cpp @@ -23,15 +23,15 @@ namespace EvalLearningTools std::vector 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が2つあるときに、論理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 min_index_flag; // ------------------------------------------------- - // 勾配等を格納している学習用の配列 + // Array for learning that stores gradients etc. // ------------------------------------------------- #if defined(_MSC_VER) @@ -49,21 +49,21 @@ namespace EvalLearningTools #endif struct Weight { - // mini-batch 1回分の勾配の累積値 + // cumulative value of one mini-batch gradient LearnFloatType g = LearnFloatType(0); - // ADA_GRAD_UPDATEのとき。LearnFloatType == floatとして、 - // 合計 4*2 + 4*2 + 1*2 = 18 bytes - // 1GBの評価関数パラメーターに対してその4.5倍のサイズのWeight配列が確保できれば良い。 - // ただし、構造体のアライメントが4バイト単位になっているとsizeof(Weight)==20なコードが生成されるので - // pragma pack(2)を指定しておく。 + // When ADA_GRAD_UPDATE. LearnFloatType == float, + // total 4*2 + 4*2 + 1*2 = 18 bytes + // It suffices to secure a Weight array that is 4.5 times the size of the evaluation function parameter of 1GB. + // However, sizeof(Weight)==20 code is generated if the structure alignment is in 4-byte units, so + // Specify pragma pack(2). - // SGD_UPDATE の場合、この構造体はさらに10バイト減って、8バイトで済む。 + // For SGD_UPDATE, this structure is reduced by 10 bytes to 8 bytes. - // AdaGradなどの学習率η(eta)。 - // updateFV()が呼び出されるまでにeta1,2,3,eta1_epoch,eta2_epochは設定されているものとする。 - // update_weights()のepochが、eta1_epochまでeta1から徐々にeta2に変化する。 - // eta2_epoch以降は、eta2から徐々にeta3に変化する。 + // Learning rate η(eta) such as AdaGrad. + // It is assumed that eta1,2,3,eta1_epoch,eta2_epoch have been set by the time updateFV() is called. + // The epoch of update_weights() gradually changes from eta1 to eta2 until eta1_epoch. + // After eta2_epoch, gradually change from eta2 to eta3. static double eta; static double eta1; static double eta2; @@ -71,7 +71,7 @@ namespace EvalLearningTools static uint64_t eta1_epoch; static uint64_t eta2_epoch; - // etaの一括初期化。0が渡された場合、デフォルト値が設定される。 + // Batch initialization of eta. If 0 is passed, the default value will be set. static void init_eta(double eta1, double eta2, double eta3, uint64_t eta1_epoch, uint64_t eta2_epoch) { Weight::eta1 = (eta1 != 0) ? eta1 : 30.0; @@ -81,15 +81,15 @@ namespace EvalLearningTools Weight::eta2_epoch = (eta2_epoch != 0) ? eta2_epoch : 0; } - // epochに応じたetaを設定してやる。 + // Set eta according to epoch. static void calc_eta(uint64_t epoch) { - if (Weight::eta1_epoch == 0) // eta2適用除外 + if (Weight::eta1_epoch == 0) // Exclude eta2 Weight::eta = Weight::eta1; else if (epoch < Weight::eta1_epoch) - // 按分する + // apportion Weight::eta = Weight::eta1 + (Weight::eta2 - Weight::eta1) * epoch / Weight::eta1_epoch; - else if (Weight::eta2_epoch == 0) // eta3適用除外 + else if (Weight::eta2_epoch == 0) // Exclude eta3 Weight::eta = Weight::eta2; else if (epoch < Weight::eta2_epoch) Weight::eta = Weight::eta2 + (Weight::eta3 - Weight::eta2) * (epoch - Weight::eta1_epoch) / (Weight::eta2_epoch - Weight::eta1_epoch); @@ -101,26 +101,26 @@ namespace EvalLearningTools #if defined (ADA_GRAD_UPDATE) - // floatで正確に計算できる最大値はINT16_MAX*256-1なのでそれより - // 小さい値をマーカーにしておく。 + // Since the maximum value that can be accurately calculated with float is INT16_MAX*256-1 + // Keep the small value as a marker. const LearnFloatType V0_NOT_INIT = (INT16_MAX * 128); - // vを内部的に保持しているもの。以前の実装ではメモリの節約のために固定小数で小数部だけを保持していたが - // 精度的に怪しいし、見通しが悪くなるので廃止した。 + // What holds v internally. The previous implementation kept a fixed decimal with only a fractional part to save memory, + // Since it is doubtful in accuracy and the visibility is bad, it was abolished. LearnFloatType v0 = LearnFloatType(V0_NOT_INIT); - // AdaGradのg2 + // AdaGrad g2 LearnFloatType g2 = LearnFloatType(0); - // AdaGradでupdateする - // この関数を実行しているときにgの値やメンバーが書き変わらないことは - // 呼び出し側で保証されている。atomic演算である必要はない。 - // kはetaに掛かる係数。普通は1.0で良い。手番項に対してetaを下げたいときにここを1/8.0などとする。 + // update with AdaGrad + // When executing this function, the value of g and the member do not change + // Guaranteed by the caller. It does not have to be an atomic operation. + // k is a coefficient for eta. 1.0 is usually sufficient. If you want to lower eta for your turn item, set this to 1/8.0 etc. template void updateFV(T& v,double k) { - // AdaGradの更新式 - // 勾配ベクトルをg、更新したいベクトルをv、η(eta)は定数として、 + // AdaGrad update formula + // Gradient vector is g, vector to be updated is v, η(eta) is a constant, // g2 = g2 + g^2 // v = v - ηg/sqrt(g2) @@ -131,48 +131,48 @@ namespace EvalLearningTools g2 += g * g; - // v0がV0_NOT_INITであるなら、値がKK/KKP/KPP配列の値で初期化されていないということだから、 - // この場合、vの値を引数で渡されたものから読み込む。 + // If v0 is V0_NOT_INIT, it means that the value is not initialized with the value of KK/KKP/KPP array, + // In this case, read the value of v from the one passed in the argument. double V = (v0 == V0_NOT_INIT) ? v : v0; V -= k * eta * (double)g / sqrt((double)g2 + epsilon); - // Vの値を型の範囲に収まるように制限する。 - // ちなみに、windows.hがmin,maxマクロを定義してしまうのでそれを回避するために、 - // ここでは括弧で括ることで関数形式マクロとして扱われないようにしている。 + // Limit the value of V to be within the range of types. + // By the way, windows.h defines the min and max macros, so to avoid it, + // Here, it is enclosed in parentheses so that it is not treated as a function-like macro. V = (std::min)((double)(std::numeric_limits::max)() , V); V = (std::max)((double)(std::numeric_limits::min)() , V); v0 = (LearnFloatType)V; v = (T)round(V); - // この要素に関するmini-batchの1回分の更新が終わったのでgをクリア + // Clear g because one update of mini-batch for this element is over // g[i] = 0; - // →次元下げの問題があるので、これは呼び出し側で行なうことにする。 + // → There is a problem of dimension reduction, so this will be done by the caller. } #elif defined(SGD_UPDATE) - // 勾配の符号だけ見るSGDでupdateする - // この関数を実行しているときにgの値やメンバーが書き変わらないことは - // 呼び出し側で保証されている。atomic演算である必要はない。 + // See only the sign of the gradient Update with SGD + // When executing this function, the value of g and the member do not change + // Guaranteed by the caller. It does not have to be an atomic operation. template void updateFV(T & v , double k) { if (g == 0) return; - // gの符号だけ見てupdateする。 - // g < 0 なら vを少し足す。 - // g > 0 なら vを少し引く。 + // See only the sign of g and update. + // If g <0, add v a little. + // If g> 0, subtract v slightly. - // 整数しか足さないので小数部不要。 + // Since we only add integers, no decimal part is required. - // 0~5ぐらいずつ動かすのがよさげ。 - // ガウス分布っぽいほうが良いので5bitの乱数を発生させて(それぞれのbitは1/2の確率で1である)、 - // それをpop_count()する。このとき、二項分布になっている。 + // It's a good idea to move around 0-5. + // It is better to have a Gaussian distribution, so generate a 5-bit random number (each bit has a 1/2 probability of 1), + // Pop_count() it. At this time, it has a binomial distribution. //int16_t diff = (int16_t)POPCNT32((u32)prng.rand(31)); - // → これ80スレッドでやったら、このAsyncPRNG::rand()がlockするのでslow downした。この実装良くない。 + // → If I do this with 80 threads, this AsyncPRNG::rand() locks, so I slowed down. This implementation is not good. int16_t diff = 1; double V = v; @@ -189,10 +189,10 @@ namespace EvalLearningTools #endif - // gradの設定 + // grad setting template void set_grad(const T& g_) { g = g_; } - // gradの加算 + // Add grad template void add_grad(const T& g_) { g += g_; } LearnFloatType get_grad() const { return g; } @@ -203,13 +203,13 @@ namespace EvalLearningTools #pragma pack(0) #endif - // 手番つきのweight配列 - // 透過的に扱えるようにするために、Weightと同じメンバを持たせておいてやる。 + // Turned weight array + // In order to be able to handle it transparently, let's have the same member as Weight. struct Weight2 { Weight w[2]; - // 手番評価、etaを1/8に評価しておく。 + //Evaluate your turn, eta 1/8. template void updateFV(std::array& v) { w[0].updateFV(v[0] , 1.0); w[1].updateFV(v[1],1.0/8.0); } template void set_grad(const std::array& g) { for (int i = 0; i<2; ++i) w[i].set_grad(g[i]); } @@ -218,42 +218,42 @@ namespace EvalLearningTools std::array get_grad() const { return std::array{w[0].get_grad(), w[1].get_grad()}; } }; - // ------------------------------------------------- - // Weight配列を直列化したときのindexを計算したりするヘルパー。 - // ------------------------------------------------- + // ------------------------------------------------ - + // A helper that calculates the index when the Weight array is serialized. + // ------------------------------------------------ - - // KK,KKP,KPP,KKPPの基底クラス - // これらのクラスの使い方 - // - // 1. まずset()で初期化する。例) KK g_kk; g_kk.set(SQUARE_NB,fe_end,0); - // 2. 次にfromIndex(),fromKK()などでインスタンスを生成 - // 3. king(),piece0(),piece1()などのプロパティを用いてアクセス。 - // - // この説明だけではわかりにくいかも知れないが、学習部のinit_grad(),add_grad(),update_weights()などを見れば - // 必要性を含めて理解できると思う。 + // Base class for KK,KKP,KPP,KKPP + // How to use these classes // - // 注意 : この派生クラスでは次元下げのために上記のinv_piece/mir_pieceを間接的に参照することがあるので、 - // 最初にEvalLearningTools::init()かinit_mir_inv_tables()を呼び出して初期化すること。 + // 1. Initialize with set() first. Example) KK g_kk; g_kk.set(SQUARE_NB,fe_end,0); + // 2. Next create an instance with fromIndex(), fromKK(), etc. + // 3. Access using properties such as king(), piece0(), piece1(). // - // 備考) 派生クラス側でoverrideすべきではない関数名には/*final*/と書いてある。 - // 派生クラス側でoverrideすべき関数は "= 0"をつけて、純粋仮想関数にしてある。 - // 派生クラス側でoverrideしてもしなくても良い関数はvirtualだけつけてある。 + // It may be difficult to understand just by this explanation, but if you look at init_grad(), add_grad(), update_weights() etc. in the learning part + // I think you can understand it including the necessity. + // + // Note: this derived class may indirectly reference the above inv_piece/mir_piece for dimension reduction, so + // Initialize by calling EvalLearningTools::init() or init_mir_inv_tables() first. + // + // Remarks) /*final*/ is written for the function name that should not be overridden on the derived class side. + // The function that should be overridden on the derived class side is a pure virtual function with "= 0". + // Only virtual functions are added to the derived class that may or may not be overridden. // struct SerializerBase { - // KK,KKP,KPP配列を直列化するときの通し番号の最小値、最大値+1。 + // Minimum value and maximum value of serial number +1 when serializing KK, KKP, KPP arrays. /*final*/ uint64_t min_index() const { return min_index_; } /*final*/ uint64_t max_index() const { return min_index() + max_raw_index_; } - // max_index() - min_index()の値。 - // 派生クラス側でmax_king_sq_,fe_end_などから、値を計算して返すようにする。 + // max_index() - min_index() the value of. + // Calculate the value from max_king_sq_,fe_end_ etc. on the derived class side and return it. virtual uint64_t size() const = 0; - // 与えられたindexが、min_index()以上、max_index()未満にあるかを判定する。 + // Determine if the given index is more than min_index() and less than max_index(). /*final*/ bool is_ok(uint64_t index) { return min_index() <= index && index < max_index(); } - // 必ずこのset()を呼び出して使う。さもなくば、派生クラス側のfromKK()/fromIndex()などでインスタンスを構築して使う。 + // Make sure to call this set(). Otherwise, construct an instance using fromKK()/fromIndex() etc. on the derived class side. virtual void set(int max_king_sq, uint64_t fe_end, uint64_t min_index) { max_king_sq_ = max_king_sq; @@ -262,26 +262,26 @@ namespace EvalLearningTools max_raw_index_ = size(); } - // 現在のメンバの値に基いて、直列化されたときのindexを取得する。 + // Get the index when serialized, based on the value of the current member. /*final*/ uint64_t toIndex() const { return min_index() + toRawIndex(); } - // 直列化するときのindexを返す。(min_index()の値は加算する前のもの) + // Returns the index when serializing. (The value of min_index() is before addition) virtual uint64_t toRawIndex() const = 0; protected: - // このクラスの返すmin_index()の値 + // The value of min_index() returned by this class uint64_t min_index_; - // このクラスの返すmax_index()の値 = min_index() + max_raw_index_ - // この変数は派生クラスのsize()で計算されたもの。 + // The value of max_index() returned by this class = min_index() + max_raw_index_ + // This variable is calculated by size() of the derived class. uint64_t max_raw_index_; - // サポートする玉の升の数(通常SQUARE_NB) + // The number of balls to support (normally SQUARE_NB) int max_king_sq_; - // サポートするBonaPieceの最大値 + // Maximum BonaPiece value supported uint64_t fe_end_; }; @@ -295,10 +295,10 @@ namespace EvalLearningTools virtual uint64_t size() const { return max_king_sq_ * max_king_sq_; } - // index(通し番号)からKKのオブジェクトを生成するbuilder + // builder that creates KK object from index (serial number) KK fromIndex(uint64_t index) const { assert(index >= min_index()); return fromRawIndex(index - min_index()); } - // raw_index(通し番号ではなく0から始まる番号)からKKのオブジェクトを生成するbuilder + // builder that creates KK object from raw_index (number starting from 0, not serial number) KK fromRawIndex(uint64_t raw_index) const { int king1 = (int)(raw_index % SQUARE_NB); @@ -309,18 +309,18 @@ namespace EvalLearningTools } KK fromKK(Square king0, Square king1 , bool inverse) const { - // kkという変数名はEval::kk配列などで使っているので別の名前にする必要がある。(以下、KKP,KPPクラスなどでも同様) + // The variable name kk is used in the Eval::kk array etc., so it needs to be different. (The same applies to KKP, KPP classes, etc.) KK my_kk(king0, king1, inverse); my_kk.set(max_king_sq_, fe_end_, min_index()); return my_kk; } KK fromKK(Square king0, Square king1) const { return fromKK(king0, king1, false); } - // fromIndex()を用いてこのオブジェクトを構築したときに、以下のアクセッサで情報が得られる。 + // When you construct this object using fromIndex(), you can get information with the following accessors. Square king0() const { return king0_; } Square king1() const { return king1_; } -// 次元下げの数 +// number of dimension reductions #if defined(USE_KK_INVERSE_WRITE) #define KK_LOWER_COUNT 4 #elif defined(USE_KK_MIRROR_WRITE) @@ -330,14 +330,14 @@ namespace EvalLearningTools #endif #if defined(USE_KK_INVERSE_WRITE) && !defined(USE_KK_MIRROR_WRITE) - // USE_KK_INVERSE_WRITEわ使うならUSE_KK_MIRROR_WRITEも定義して欲しい。 + // USE_KK_INVERSE_WRITE If you use it, please also define USE_KK_MIRROR_WRITE. static_assert(false, "define also USE_KK_MIRROR_WRITE!"); #endif - // 低次元の配列のindexを得る。 - // USE_KK_INVERSE_WRITEが有効なときは、それらをinverseしたものが[2],[3]に入る。 - // この次元下げに関して、gradの符号は反転させないといけないので注意すること。 - // is_inverse()で判定できるのでこれを利用すると良い。 + // Get the index of the low-dimensional array. + // When USE_KK_INVERSE_WRITE is enabled, the inverse of them will be in [2] and [3]. + // Note that the sign of grad must be reversed for this dimension reduction. + // You can use is_inverse() because it can be determined. void toLowerDimensions(/*out*/KK kk_[KK_LOWER_COUNT]) const { kk_[0] = fromKK(king0_, king1_,false); #if defined(USE_KK_MIRROR_WRITE) @@ -349,24 +349,24 @@ namespace EvalLearningTools #endif } - // このクラスのmin_index()の値を0として数えたときのindexを取得する。 + // Get the index when counting the value of min_index() of this class as 0. virtual uint64_t toRawIndex() const { return (uint64_t)king0_ * (uint64_t)max_king_sq_ + (uint64_t)king1_; } - // toLowerDimensionsで次元下げしたものがinverseしたものであるかを返す。 + // Returns whether or not the dimension lowered with toLowerDimensions is inverse. bool is_inverse() const { return inverse_sign; } - // is_inverse() == trueのときに、gradの手番ではないほうの符号を反転させて返す。 + // When is_inverse() == true, reverse the sign that is not grad's turn and return it. template std::array apply_inverse_sign(const std::array& rhs) { return !is_inverse() ? rhs : std::array{-rhs[0], rhs[1]}; } - // 比較演算子 + // comparison operator bool operator==(const KK& rhs) { return king0() == rhs.king0() && king1() == rhs.king1(); } bool operator!=(const KK& rhs) { return !(*this == rhs); } @@ -375,14 +375,14 @@ namespace EvalLearningTools bool inverse_sign; }; - // デバッグ用出力。 + // Output for debugging. static std::ostream& operator<<(std::ostream& os, KK rhs) { os << "KK(" << rhs.king0() << "," << rhs.king1() << ")"; return os; } - // KKと同じく。KKP用。 + // Same as KK. For KKP. struct KKP : public SerializerBase { protected: @@ -393,10 +393,10 @@ namespace EvalLearningTools virtual uint64_t size() const { return (uint64_t)max_king_sq_*(uint64_t)max_king_sq_*(uint64_t)fe_end_; } - // index(通し番号)からKKPのオブジェクトを生成するbuilder + // builder that creates KKP object from index (serial number) KKP fromIndex(uint64_t index) const { assert(index >= min_index()); return fromRawIndex(index - min_index()); } - // raw_index(通し番号ではなく0から始まる番号)からKKPのオブジェクトを生成するbuilder + // A builder that creates a KKP object from raw_index (a number that starts from 0, not a serial number) KKP fromRawIndex(uint64_t raw_index) const { int piece = (int)(raw_index % Eval::fe_end); @@ -416,12 +416,12 @@ namespace EvalLearningTools } KKP fromKKP(Square king0, Square king1, Eval::BonaPiece p) const { return fromKKP(king0, king1, p, false); } - // fromIndex()を用いてこのオブジェクトを構築したときに、以下のアクセッサで情報が得られる。 + // When you construct this object using fromIndex(), you can get information with the following accessors. Square king0() const { return king0_; } Square king1() const { return king1_; } Eval::BonaPiece piece() const { return piece_; } - // KKPの次元下げの数 + // Number of KKP dimension reductions #if defined(USE_KKP_INVERSE_WRITE) #define KKP_LOWER_COUNT 4 #elif defined(USE_KKP_MIRROR_WRITE) @@ -431,14 +431,14 @@ namespace EvalLearningTools #endif #if defined(USE_KKP_INVERSE_WRITE) && !defined(USE_KKP_MIRROR_WRITE) - // USE_KKP_INVERSE_WRITEわ使うならUSE_KKP_MIRROR_WRITEも定義して欲しい。 + // USE_KKP_INVERSE_WRITE If you use it, please also define USE_KKP_MIRROR_WRITE. static_assert(false, "define also USE_KKP_MIRROR_WRITE!"); #endif - // 低次元の配列のindexを得る。ミラーしたものがkkp_[1]に返る。 - // USE_KKP_INVERSE_WRITEが有効なときは、それらをinverseしたものが[2],[3]に入る。 - // この次元下げに関して、gradの符号は反転させないといけないので注意すること。 - // is_inverse()で判定できるのでこれを利用すると良い。 + // Get the index of the low-dimensional array. The mirrored one is returned to kkp_[1]. + // When USE_KKP_INVERSE_WRITE is enabled, the inverse of them will be in [2] and [3]. + // Note that the sign of grad must be reversed for this dimension reduction. + // You can use is_inverse() because it can be determined. void toLowerDimensions(/*out*/ KKP kkp_[KKP_LOWER_COUNT]) const { kkp_[0] = fromKKP(king0_, king1_, piece_,false); #if defined(USE_KKP_MIRROR_WRITE) @@ -450,24 +450,24 @@ namespace EvalLearningTools #endif } - // このクラスのmin_index()の値を0として数えたときのindexを取得する。 + // Get the index when counting the value of min_index() of this class as 0. virtual uint64_t toRawIndex() const { return ((uint64_t)king0_ * (uint64_t)max_king_sq_ + (uint64_t)king1_) * (uint64_t)fe_end_ + (uint64_t)piece_; } - // toLowerDimensionsで次元下げしたものがinverseしたものであるかを返す。 + // Returns whether or not the dimension lowered with toLowerDimensions is inverse. bool is_inverse() const { return inverse_sign; } - // is_inverse() == trueのときに、gradの手番ではないほうの符号を反転させて返す。 + // When is_inverse() == true, reverse the sign that is not grad's turn and return it. template std::array apply_inverse_sign(const std::array& rhs) { return !is_inverse() ? rhs : std::array{-rhs[0], rhs[1]}; } - // 比較演算子 + // comparison operator bool operator==(const KKP& rhs) { return king0() == rhs.king0() && king1() == rhs.king1() && piece() == rhs.piece(); } bool operator!=(const KKP& rhs) { return !(*this == rhs); } @@ -477,7 +477,7 @@ namespace EvalLearningTools bool inverse_sign; }; - // デバッグ用出力。 + // Output for debugging. static std::ostream& operator<<(std::ostream& os, KKP rhs) { os << "KKP(" << rhs.king0() << "," << rhs.king1() << "," << rhs.piece() << ")"; @@ -485,7 +485,7 @@ namespace EvalLearningTools } - // KK,KKPと同様。KPP用 + // Same as KK and KKP. For KPP struct KPP : public SerializerBase { protected: @@ -494,28 +494,28 @@ namespace EvalLearningTools public: KPP() {} - // KK,KKP,KPP配列を直列化するときの通し番号の、KPPの最小値、最大値。 + // The minimum and maximum KPP values ​​of serial numbers when serializing KK, KKP, KPP arrays. #if !defined(USE_TRIANGLE_WEIGHT_ARRAY) virtual uint64_t size() const { return (uint64_t)max_king_sq_*(uint64_t)fe_end_*(uint64_t)fe_end_; } #else - // kpp[SQUARE_NB][fe_end][fe_end]の[fe_end][fe_end]な正方配列の部分を三角配列化する。 - // kpp[SQUARE_NB][triangle_fe_end]とすると、この三角配列の1行目は要素1個、2行目は2個、…。 - // ゆえに、triangle_fe_end = 1 + 2 + .. + fe_end = fe_end * (fe_end + 1) / 2 + // Triangularize the square array part of [fe_end][fe_end] of kpp[SQUARE_NB][fe_end][fe_end]. + // If kpp[SQUARE_NB][triangle_fe_end], the first row of this triangular array has one element, the second row has two elements, and so on. + // hence triangle_fe_end = 1 + 2 + .. + fe_end = fe_end * (fe_end + 1) / 2 virtual uint64_t size() const { return (uint64_t)max_king_sq_*(uint64_t)triangle_fe_end; } #endif virtual void set(int max_king_sq, uint64_t fe_end, uint64_t min_index) { - // この値、size()で用いていて、SerializerBase::set()でsize()を使うので先に計算する。 + // This value is used in size(), and size() is used in SerializerBase::set(), so calculate first. triangle_fe_end = (uint64_t)fe_end*((uint64_t)fe_end + 1) / 2; SerializerBase::set(max_king_sq, fe_end, min_index); } - // index(通し番号)からKPPのオブジェクトを生成するbuilder + // builder that creates KPP object from index (serial number) KPP fromIndex(uint64_t index) const { assert(index >= min_index()); return fromRawIndex(index - min_index()); } - // raw_index(通し番号ではなく0から始まる番号)からKPPのオブジェクトを生成するbuilder + // A builder that creates KPP objects from raw_index (a number that starts from 0, not a serial number) KPP fromRawIndex(uint64_t raw_index) const { const uint64_t triangle_fe_end = (uint64_t)fe_end_*((uint64_t)fe_end_ + 1) / 2; @@ -528,13 +528,13 @@ namespace EvalLearningTools #else uint64_t index2 = raw_index % triangle_fe_end; - // ここにindex2からpiece0,piece1を求める式を書く。 - // これは index2 = i * (i+1) / 2 + j の逆関数となる。 - // j = 0 の場合、i^2 + i - 2 * index2 == 0なので - // 2次方程式の解の公式から i = (sqrt(8*index2+1) - 1) / 2である。 - // iを整数化したのちに、j = index2 - i * (i + 1) / 2としてjを求めれば良い。 + // Write the expression to find piece0, piece1 from index2 here. + // This is the inverse function of index2 = i * (i+1) / 2 + j. + // If j = 0, i^2 + i-2 * index2 == 0 + // From the solution formula of the quadratic equation i = (sqrt(8*index2+1)-1) / 2. + // After i is converted into an integer, j can be calculated as j = index2-i * (i + 1) / 2. - // BonaPieceは32bit(16bitに収まらない可能性)を想定しているのでこの掛け算は64bitでないといけない。 + // BonaPiece assumes 32bit (may not fit in 16bit), so this multiplication must be 64bit. int piece1 = int(sqrt(8 * index2 + 1) - 1) / 2; int piece0 = int(index2 - (uint64_t)piece1*((uint64_t)piece1 + 1) / 2); @@ -556,13 +556,13 @@ namespace EvalLearningTools return my_kpp; } - // fromIndex()を用いてこのオブジェクトを構築したときに、以下のアクセッサで情報が得られる。 + // When you construct this object using fromIndex(), you can get information with the following accessors. Square king() const { return king_; } Eval::BonaPiece piece0() const { return piece0_; } Eval::BonaPiece piece1() const { return piece1_; } - // 次元下げの数 +// number of dimension reductions #if defined(USE_KPP_MIRROR_WRITE) #if !defined(USE_TRIANGLE_WEIGHT_ARRAY) #define KPP_LOWER_COUNT 4 @@ -577,18 +577,18 @@ namespace EvalLearningTools #endif #endif - // 低次元の配列のindexを得る。p1,p2を入れ替えたもの、ミラーしたものなどが返る。 + // Get the index of the low-dimensional array. The ones with p1 and p2 swapped, the ones mirrored, etc. are returned. void toLowerDimensions(/*out*/ KPP kpp_[KPP_LOWER_COUNT]) const { #if defined(USE_TRIANGLE_WEIGHT_ARRAY) - // 三角配列を用いる場合は、piece0とpiece1を入れ替えたものは返らないので注意。 + // Note that if you use a triangular array, the swapped piece0 and piece1 will not be returned. kpp_[0] = fromKPP(king_, piece0_, piece1_); #if defined(USE_KPP_MIRROR_WRITE) kpp_[1] = fromKPP(Mir(king_), mir_piece(piece0_), mir_piece(piece1_)); #endif #else - // 三角配列を用いない場合 + // When not using triangular array kpp_[0] = fromKPP(king_, piece0_, piece1_); kpp_[1] = fromKPP(king_, piece1_, piece0_); #if defined(USE_KPP_MIRROR_WRITE) @@ -598,7 +598,7 @@ namespace EvalLearningTools #endif } - // このクラスのmin_index()の値を0として数えたときのindexを取得する。 + // Get the index when counting the value of min_index() of this class as 0. virtual uint64_t toRawIndex() const { #if !defined(USE_TRIANGLE_WEIGHT_ARRAY) @@ -606,15 +606,15 @@ namespace EvalLearningTools return ((uint64_t)king_ * (uint64_t)fe_end_ + (uint64_t)piece0_) * (uint64_t)fe_end_ + (uint64_t)piece1_; #else - // Bonanza6.0で使われているのに似せたマクロ + // Macro similar to that used in Bonanza 6.0 auto PcPcOnSq = [&](Square k, Eval::BonaPiece i, Eval::BonaPiece j) { - // この三角配列の(i,j)は、i行目のj列目の要素。 - // i行目0列目は、そこまでの要素の合計であるから、1 + 2 + ... + i = i * (i+1) / 2 - // i行目j列目は、これにjを足したもの。i * (i + 1) /2 + j + // (i,j) in this triangular array is the element in the i-th row and the j-th column. + // 1st row + 2 + ... + i = i * (i+1) / 2 because the i-th row and 0th column is the total of the elements up to that point + // The i-th row and the j-th column is j plus this. i*(i+1)/2+j - // BonaPiece型は、32bitを想定しているので掛け算には気をつけないとオーバーフローする。 + // BonaPiece type is assumed to be 32 bits, so if you do not pay attention to multiplication, it will overflow. return (uint64_t)k * triangle_fe_end + (uint64_t)(uint64_t(i)*(uint64_t(i)+1) / 2 + uint64_t(j)); }; @@ -626,18 +626,18 @@ namespace EvalLearningTools #endif } - // toLowerDimensionsで次元下げしたものがinverseしたものであるかを返す。 - // KK,KKPとinterfaceを合せるために用意してある。このKPPクラスでは、このメソッドは常にfalseを返す。 + // Returns whether or not the dimension lowered with toLowerDimensions is inverse. + // Prepared to match KK, KKP and interface. This method always returns false for this KPP class. bool is_inverse() const { return false; } - // 比較演算子 + // comparison operator bool operator==(const KPP& rhs) { return king() == rhs.king() && ((piece0() == rhs.piece0() && piece1() == rhs.piece1()) #if defined(USE_TRIANGLE_WEIGHT_ARRAY) - // 三角配列を用いるときはpiece0とpiece1の入れ替わりを許容する。 + // When using a triangular array, allow swapping of piece0 and piece1. || (piece0() == rhs.piece1() && piece1() == rhs.piece0()) #endif ); } @@ -651,24 +651,24 @@ namespace EvalLearningTools uint64_t triangle_fe_end; // = (uint64_t)fe_end_*((uint64_t)fe_end_ + 1) / 2; }; - // デバッグ用出力。 + // Output for debugging. static std::ostream& operator<<(std::ostream& os, KPP rhs) { os << "KPP(" << rhs.king() << "," << rhs.piece0() << "," << rhs.piece1() << ")"; return os; } - // KPPPの4駒関係。ただし、手番ありでミラー等を考慮しないと学習に2TB以上のメモリが必要…。 - // 三角配列を使っても学習のために50GB×12バイト = 600GB必要。 - // ミラーしたもののみを格納するようにしてもの半分ぐらい必要。 - // ここでは、三角配列は必ず用いて、かつミラーしたものを格納するものとする。 + // 4 pieces related to KPPP. However, if there is a turn and you do not consider mirrors etc., memory of 2 TB or more is required for learning. + // Even if you use a triangular array, you need 50GB x 12 bytes = 600GB for learning. + // It takes about half as much as storing only the mirrored one. + // Here, the triangular array is always used and the mirrored one is stored. // - // また、このクラスのking()は、実際のkingのSquareとは限らず、単に、0~(king_sq-1)までの値が返る。 - // これは、ミラーを利用した圧縮を行なう場合など、利用側で適切な玉の位置に変換してやる必要がある。 - // - // あと、このクラスの返すpiece0,1,2に関して、 - // piece0() > piece1() > piece2() - // であり、コンストラクタでpiece0,1,2を渡すときも、この制約を守る必要がある。 + // Also, king() of this class is not limited to Square of the actual king, but a value from 0 to (king_sq-1) is simply returned. + // This needs to be converted to an appropriate ball position on the user side when performing compression using a mirror. + // + // Later, regarding the pieces0,1,2 returned by this class, + // piece0() >piece1() >piece2() + // It is, and it is necessary to keep this constraint when passing piece0,1,2 in the constructor. struct KPPP : public SerializerBase { protected: @@ -684,21 +684,21 @@ namespace EvalLearningTools virtual uint64_t size() const { return (uint64_t)max_king_sq_*triangle_fe_end; } - // fe_endとking_sqを設定する。 - // fe_end : このKPPPクラスの想定するfe_end - // king_sq : KPPPのときに扱う玉の升の数。 - // 3段×ミラーなら3段×5筋 = 15みたいな感じ。 - // 2段×ミラーなしなら2×9筋 = 18みたいな感じ。 - // これをこのKPPPクラスを使う側でset()を用いて最初に設定する。 + // Set fe_end and king_sq. + // fe_end: fe_end assumed by this KPPP class + // king_sq: Number of balls to handle in KPPP. + // 3 layers x 3 mirrors = 3 layers x 5 lines = 15 + // 2 steps x 2 mirrors without mirror = 18 + // Set this first using set() on the side that uses this KPPP class. virtual void set(int max_king_sq, uint64_t fe_end,uint64_t min_index) { - // この値、size()で用いていて、SerializerBase::set()でsize()を使うので先に計算する。 + // This value is used in size(), and size() is used in SerializerBase::set(), so calculate first. triangle_fe_end = fe_end * (fe_end - 1) * (fe_end - 2) / 6; SerializerBase::set(max_king_sq, fe_end, min_index); } - // 次元下げの数 - // とりあえず、ミラーの次元下げ非対応。ここでやることもないかと…。 + // number of dimension reductions + // For the time being, the dimension reduction of the mirror is not supported. I wonder if I'll do it here... /* #if defined(USE_KPPP_MIRROR_WRITE) #define KPPP_LOWER_COUNT 2 @@ -708,70 +708,70 @@ namespace EvalLearningTools */ #define KPPP_LOWER_COUNT 1 - // 低次元の配列のindexを得る。 - // p0,p1,p2を入れ替えたものは返らないので注意。 - // またミラーしたものも、USE_KPPP_MIRROR_WRITEが有効なときしか返さない。 + // Get the index of the low-dimensional array. + // Note that the one with p0,p1,p2 swapped will not be returned. + // Also, the mirrored one is returned only when USE_KPPP_MIRROR_WRITE is enabled. void toLowerDimensions(/*out*/ KPPP kppp_[KPPP_LOWER_COUNT]) const { kppp_[0] = fromKPPP(king_, piece0_, piece1_,piece2_); #if KPPP_LOWER_COUNT > 1 - // mir_pieceするとsortされてない状態になる。sortするコードが必要。 + // If mir_piece is done, it will be in a state not sorted. Need code to sort. Eval::BonaPiece p_list[3] = { mir_piece(piece2_), mir_piece(piece1_), mir_piece(piece0_) }; my_insertion_sort(p_list, 0, 3); kppp_[1] = fromKPPP((int)Mir((Square)king_), p_list[2] , p_list[1], p_list[0]); #endif } - // index(通し番号)からKPPPのオブジェクトを生成するbuilder + // builder that creates KPPP object from index (serial number) KPPP fromIndex(uint64_t index) const { assert(index >= min_index()); return fromRawIndex(index - min_index()); } - // raw_index(通し番号ではなく0から始まる番号)からKPPPのオブジェクトを生成するbuilder + // A builder that creates KPPP objects from raw_index (a number that starts from 0, not a serial number) KPPP fromRawIndex(uint64_t raw_index) const { uint64_t index2 = raw_index % triangle_fe_end; - // ここにindex2からpiece0,piece1,piece2を求める式を書く。 - // これは index2 = i(i-1)(i-2)/6-1 + j(j+1)/2 + k の逆関数となる。 - // j = k = 0 の場合、3次方程式の解の公式から実根は、 i = ...である。(以下式) - // ただしindex2が0,1のときは実数解が複数ある。これを考慮しないといけない。計算精度が足りないことに対する対策必要。 - // iが求まったあとはiを整数化したのちに、最初の式に入れてKPPのとき同様にjを求めれば良い。 + // Write the expression to find piece0, piece1, piece2 from index2 here. + // This is the inverse function of index2 = i(i-1)(i-2)/6-1 + j(j+1)/2 + k. + // For j = k = 0, the real root is i = ... from the solution formula of the cubic equation. (The following formula) + // However, if index2 is 0 or 1, there are multiple real solutions. You have to consider this. It is necessary to take measures against insufficient calculation accuracy. + // After i is calculated, i can be converted into an integer, then put in the first expression and then j can be calculated in the same way as in KPP. - // この処理、数値計算としてわりと難しい。色々工夫が必要。 + // This process is a relatively difficult numerical calculation. Various ideas are needed. int piece0; if (index2 <= 1) { - // index2 == 0,1のときだけ実数解が複数ある。 + // There are multiple real solutions only when index2 == 0,1. piece0 = (int)index2 + 2; } else { - //double t = pow(sqrt((243 *index2 * index2 - 1) * 3) + 27 * index2, 1.0 / 3); - // → これだとindex2が大きくなるとsqrt()の中身、オーバーフローする。 + //double t = pow(sqrt((243 *index2 * index2-1) * 3) + 27 * index2, 1.0 / 3); + // → In this case, the content of sqrt() will overflow if index2 becomes large. - // sqrt()の中身がオーバーフローするので、sqrtのなかで3.0を掛けずにsqrtの外側でsqrt(3.0)を掛ける。 - // sqrt()の中身がオーバーフローするので、index2が大きいときは近似式を用いる。 + // Since the contents of sqrt() overflow, do not multiply 3.0 in sqrt, but multiply sqrt(3.0) outside sqrt. + // Since the contents of sqrt() will overflow, use an approximate expression when index2 is large. double t; if (index2 < 100000000) t = pow(sqrt((243.0 *index2 * index2 - 1)) * sqrt(3.0) + 27 * index2, 1.0 / 3); else - // index2が非常に大きいとき、sqrtの中身、近似的に √243 * index2とみなせるだろう。 + // If index2 is very large, we can think of the contents of sqrt as approximately √243 * index2. t = pow( index2 * sqrt(243 * 3.0) + 27 * index2, 1.0 / 3); - - // 丸めのときに計算誤差でわずかに足りないのを防ぐためデルタを加算する。 - // 大きすぎると1大きい数になってしまう時があるので調整が必要。 - + + // Add deltas to avoid a slight calculation error when rounding. + // If it is too large, it may increase by 1 so adjustment is necessary. + const double delta = 0.000000001; piece0 = int(t / pow(3.0, 2.0 / 3) + 1.0 / (pow(3.0, 1.0 / 3) * t) + delta) + 1; - // ううう。ほんまにこんなことせんとあかんのか?(´ω`) + // Uuu. Is it really like this? ('Ω`) } - // piece2が求まったので、上式のi(i-1)(i-2)/6(=aとする)のiにpiece2を代入。また、k = 0を代入。 - // j(j+1)/2 = index2 - a - // これは、2次方程式の解の公式より.. + //Since piece2 is obtained, substitute piece2 for i of i(i-1)(i-2)/6 (=a) in the above formula. Also substitute k = 0. + // j(j+1)/2 = index2-a + // This is from the solution formula of the quadratic equation.. uint64_t a = (uint64_t)piece0*((uint64_t)piece0 - 1)*((uint64_t)piece0 - 2) / 6; int piece1 = int((1 + sqrt(8.0 * (index2 - a ) + 1)) / 2); @@ -796,12 +796,12 @@ namespace EvalLearningTools int king = (int)(raw_index /* % SQUARE_NB */); assert(king < max_king_sq_); - // king_sqとfe_endに関しては伝播させる。 + // Propagate king_sq and fe_end. return fromKPPP((Square)king, (Eval::BonaPiece)piece0, (Eval::BonaPiece)piece1 , (Eval::BonaPiece)piece2); } - // k,p0,p1,p2を指定してKPPPのインスタンスをbuildする。 - // 内部的に保持しているset()で渡されたking_sqとfe_endは引き継ぐ。 + // Specify k,p0,p1,p2 to build KPPP instance. + // The king_sq and fe_end passed by set() which is internally retained are inherited. KPPP fromKPPP(int king, Eval::BonaPiece p0, Eval::BonaPiece p1, Eval::BonaPiece p2) const { KPPP kppp(king, p0, p1, p2); @@ -809,21 +809,21 @@ namespace EvalLearningTools return kppp; } - // このクラスのmin_index()の値を0として数えたときのindexを取得する。 + // Get the index when counting the value of min_index() of this class as 0. virtual uint64_t toRawIndex() const { - // Bonanza 6.0で使われているのに似せたマクロ - // 前提条件) i > j > k であること。 - // i==j,j==kのケースはNG。 + // Macro similar to the one used in Bonanza 6.0 + // Precondition) i> j> k. + // NG in case of i==j,j==k. auto PcPcPcOnSq = [this](int king, Eval::BonaPiece i, Eval::BonaPiece j , Eval::BonaPiece k) { - // この三角配列の(i,j,k)は、i行目のj列目の要素。 - // i行目0列0番目は、そこまでの要素の合計であるから、0 + 0 + 1 + 3 + 6 + ... + (i)*(i-1)/2 = i*(i-1)*(i-2)/ 6 - // i行目j列0番目は、そこにjを加味したもの。 + j*(j-1) / 2 - // i行目j列k番目は、そこにkを足したもの。 + k + // (i,j,k) in this triangular array is the element in the i-th row and the j-th column. + // 0th row 0th column 0th is the sum of the elements up to that point, so 0 + 0 + 1 + 3 + 6 + ... + (i)*(i-1)/2 = i*( i-1)*(i-2)/6 + // i-th row, j-th column, 0-th is j with j added. + j*(j-1) / 2 + // i-th row, j-th column and k-th row is k plus it. + k assert(i > j && j > k); - // BonaPiece型は、32bitを想定しているので掛け算には気をつけないとオーバーフローする。 + // BonaPiece type is assumed to be 32 bits, so if you do not pay attention to multiplication, it will overflow. return (uint64_t)king * triangle_fe_end + (uint64_t)( uint64_t(i)*(uint64_t(i) - 1) * (uint64_t(i) - 2) / 6 + uint64_t(j)*(uint64_t(j) - 1) / 2 @@ -834,24 +834,24 @@ namespace EvalLearningTools return PcPcPcOnSq(king_, piece0_, piece1_, piece2_); } - // fromIndex()を用いてこのオブジェクトを構築したときに、以下のアクセッサで情報が得られる。 + // When you construct this object using fromIndex(), you can get information with the following accessors. int king() const { return king_; } Eval::BonaPiece piece0() const { return piece0_; } Eval::BonaPiece piece1() const { return piece1_; } Eval::BonaPiece piece2() const { return piece2_; } - // toLowerDimensionsで次元下げしたものがinverseしたものであるかを返す。 - // KK,KKPとinterfaceを合せるために用意してある。このKPPPクラスでは、このメソッドは常にfalseを返す。 + // Returns whether or not the dimension lowered with toLowerDimensions is inverse. + // Prepared to match KK, KKP and interface. This method always returns false for this KPPP class. bool is_inverse() const { return false; } - // 3角配列化したときの要素の数を返す。kppp配列が、以下のような2次元配列だと想定している。 - // kppp[king_sq][triangle_fe_end]; + // Returns the number of elements in a triangular array. It is assumed that the kppp array is the following two-dimensional array. + // kppp[king_sq][triangle_fe_end]; uint64_t get_triangle_fe_end() const { return triangle_fe_end; } - // 比較演算子 + // comparison operator bool operator==(const KPPP& rhs) { - // piece0 > piece1 > piece2を前提とするので、入れ替わりの可能性はない。 + // piece0> piece1> piece2 is assumed, so there is no possibility of replacement. return king() == rhs.king() && piece0() == rhs.piece0() && piece1() == rhs.piece1() && piece2() == rhs.piece2(); } bool operator!=(const KPPP& rhs) { return !(*this == rhs); } @@ -861,33 +861,33 @@ namespace EvalLearningTools int king_; Eval::BonaPiece piece0_, piece1_,piece2_; - // kppp[king_sq][fe_end][fe_end][fe_end]の[fe_end][fe_end][fe_end]な正方配列の部分を三角配列化する。 - // kppp[king_sq][triangle_fe_end]とすると、この三角配列の0行目から要素数は、0,0,1,3,…,n行目はn(n-1)/2個。 - // ゆえに、 + // The part of the square array of [fe_end][fe_end][fe_end] of kppp[king_sq][fe_end][fe_end][fe_end] is made into a triangular array. + // If kppp[king_sq][triangle_fe_end], the number of elements from the 0th row of this triangular array is 0,0,1,3,..., The nth row is n(n-1)/2. + // therefore, // triangle_fe_end = Σn(n-1)/2 , n=0..fe_end-1 // = fe_end * (fe_end - 1) * (fe_end - 2) / 6 uint64_t triangle_fe_end; // ((uint64_t)Eval::fe_end)*((uint64_t)Eval::fe_end - 1)*((uint64_t)Eval::fe_end - 2) / 6; }; - // デバッグ用出力。 + // Output for debugging. static std::ostream& operator<<(std::ostream& os, KPPP rhs) { os << "KPPP(" << rhs.king() << "," << rhs.piece0() << "," << rhs.piece1() << "," << rhs.piece2() << ")"; return os; } - // KKPPによる4駒関係の学習用。 + // For learning about 4 pieces by KKPP. // - // KPPPクラスと同じ設計。KPPPクラスで、pが一枚少ないものとして扱う。 - // 2つの玉の位置は0~king_sq-1までの値としてencodeされているものとする。 + // Same design as KPPP class. In KPPP class, treat as one with less p. + // The positions of the two balls are encoded as values ​​from 0 to king_sq-1. // - // あと、このクラスの返すpiece0,1に関して、 - // piece0() > piece1() - // であり、コンストラクタでpiece0,1を渡すときも、この制約を守る必要がある。 + // Later, regarding the pieces0 and 1 returned by this class, + // piece0() >piece1() + // It is, and it is necessary to keep this constraint even when passing piece0,1 in the constructor. // - // この制約から、BonaPieceZeroをpiece0,piece1に同時に代入して渡すことは出来ない。 - // 駒落ちの学習に対応させるならevaluate()で工夫が必要。 - struct KKPP : SerializerBase + // Due to this constraint, BonaPieceZero cannot be assigned to piece0 and piece1 at the same time and passed. + // If you want to support learning of dropped frames, you need to devise with evaluate(). + struct KKPP: SerializerBase { protected: KKPP(int king, Eval::BonaPiece p0, Eval::BonaPiece p1) : @@ -902,45 +902,45 @@ namespace EvalLearningTools virtual uint64_t size() const { return (uint64_t)max_king_sq_*triangle_fe_end; } - // fe_endとking_sqを設定する。 - // fe_end : このKPPPクラスの想定するfe_end - // king_sq : KPPPのときに扱う玉の升の数。 - // 9段×ミラーなら9段×5筋の2乗(先後の玉) = 45*45 = 2025 みたいな感じ。 - // これをこのKKPPクラスを使う側でset()を用いて最初に設定する。 + // Set fe_end and king_sq. + // fe_end: fe_end assumed by this KPPP class + // king_sq: Number of balls to handle in KPPP. + // 9 steps x mirrors 9 steps x 5 squared squares (balls before and after) = 45*45 = 2025. + // Set this first using set() on the side that uses this KKPP class. void set(int max_king_sq, uint64_t fe_end , uint64_t min_index) { - // この値、size()で用いていて、SerializerBase::set()でsize()を使うので先に計算する。 + // This value is used in size(), and size() is used in SerializerBase::set(), so calculate first. triangle_fe_end = fe_end * (fe_end - 1) / 2; SerializerBase::set(max_king_sq, fe_end, min_index); } - // 次元下げの数 - // とりあえず、ミラーの次元下げ非対応。ここでやることもないかと…。(学習用のメモリがもったいないので) + // number of dimension reductions + // For the time being, the dimension reduction of the mirror is not supported. I wonder if I'll do it here... (Because the memory for learning is a waste) #define KKPP_LOWER_COUNT 1 - // 低次元の配列のindexを得る。 - // p0,p1,p2を入れ替えたものは返らないので注意。 - // またミラーしたものも、USE_KPPP_MIRROR_WRITEが有効なときしか返さない。 + // Get the index of the low-dimensional array. + //Note that the one with p0,p1,p2 swapped will not be returned. + // Also, the mirrored one is returned only when USE_KPPP_MIRROR_WRITE is enabled. void toLowerDimensions(/*out*/ KKPP kkpp_[KPPP_LOWER_COUNT]) const { kkpp_[0] = fromKKPP(king_, piece0_, piece1_); - // ミラーする場合、mir_pieceするとsortされてない状態になる。sortするコードが必要。 - // あとking_に対するミラーを定義する必要も。 + // When mirroring, mir_piece will not be sorted. Need code to sort. + // We also need to define a mirror for king_. } - // index(通し番号)からKKPPのオブジェクトを生成するbuilder + // builder that creates KKPP object from index (serial number) KKPP fromIndex(uint64_t index) const { assert(index >= min_index()); return fromRawIndex(index - min_index()); } - // raw_index(通し番号ではなく0から始まる番号)からKKPPのオブジェクトを生成するbuilder + // builder that creates KKPP object from raw_index (number starting from 0, not serial number) KKPP fromRawIndex(uint64_t raw_index) const { uint64_t index2 = raw_index % triangle_fe_end; - // ここにindex2からpiece0,piece1,piece2を求める式を書く。 - // これは index2 = i(i-1)/2 + j の逆関数となる。 - // j=0として、二次方程式の解の公式を用いる。 - // index2=0のときは重根だが小さいほうはi>jを満たさないので無視。 + // Write the expression to find piece0, piece1, piece2 from index2 here. + // This is the inverse function of index2 = i(i-1)/2 + j. + // Use the formula of the solution of the quadratic equation with j=0. + // When index2=0, it is a double root, but the smaller one does not satisfy i>j and is ignored. int piece0 = (int(sqrt(8 * index2 + 1)) + 1)/2; int piece1 = int(index2 - piece0 * (piece0 - 1) /2 ); @@ -955,12 +955,12 @@ namespace EvalLearningTools int king = (int)(raw_index /* % SQUARE_NB */); assert(king < max_king_sq_); - // king_sqとfe_endに関しては伝播させる。 + // Propagate king_sq and fe_end. return fromKKPP(king, (Eval::BonaPiece)piece0, (Eval::BonaPiece)piece1); } - // k,p0,p1を指定してKKPPのインスタンスをbuildする。 - // 内部的に保持しているset()で渡されたking_sqとfe_endは引き継ぐ。 + // Specify k,p0,p1 to build KKPP instance. + // The king_sq and fe_end passed by set() which is internally retained are inherited. KKPP fromKKPP(int king, Eval::BonaPiece p0, Eval::BonaPiece p1) const { KKPP kkpp(king, p0, p1); @@ -968,17 +968,17 @@ namespace EvalLearningTools return kkpp; } - // このクラスのmin_index()の値を0として数えたときのindexを取得する。 + // Get the index when counting the value of min_index() of this class as 0. virtual uint64_t toRawIndex() const { - // Bonanza 6.0で使われているのに似せたマクロ - // 前提条件) i > jであること。 - // i==j,j==kのケースはNG。 + // Macro similar to the one used in Bonanza 6.0 + // Precondition) i> j. + // NG in case of i==j,j==k. auto PcPcOnSq = [this](int king, Eval::BonaPiece i, Eval::BonaPiece j) { assert(i > j); - // BonaPiece型は、32bitを想定しているので掛け算には気をつけないとオーバーフローする。 + // BonaPiece type is assumed to be 32 bits, so if you do not pay attention to multiplication, it will overflow. return (uint64_t)king * triangle_fe_end + (uint64_t)( + uint64_t(i)*(uint64_t(i) - 1) / 2 + uint64_t(j) @@ -988,24 +988,24 @@ namespace EvalLearningTools return PcPcOnSq(king_, piece0_, piece1_); } - // fromIndex(),fromKKPP()を用いてこのオブジェクトを構築したときに、以下のアクセッサで情報が得られる。 + // When you construct this object using fromIndex(), fromKKPP(), you can get information with the following accessors. int king() const { return king_; } Eval::BonaPiece piece0() const { return piece0_; } Eval::BonaPiece piece1() const { return piece1_; } - // toLowerDimensionsで次元下げしたものがinverseしたものであるかを返す。 - // KK,KKPとinterfaceを合せるために用意してある。このKKPPクラスでは、このメソッドは常にfalseを返す。 + // Returns whether or not the dimension lowered with toLowerDimensions is inverse. + // Prepared to match KK, KKP and interface. In this KKPP class, this method always returns false. bool is_inverse() const { return false; } - // 3角配列化したときの要素の数を返す。kkpp配列が、以下のような2次元配列だと想定している。 + //Returns the number of elements in a triangular array. It is assumed that the kkpp array is the following two-dimensional array. // kkpp[king_sq][triangle_fe_end]; uint64_t get_triangle_fe_end() const { return triangle_fe_end; } - // 比較演算子 + // comparison operator bool operator==(const KKPP& rhs) { - // piece0 > piece1を前提とするので、入れ替わりの可能性はない。 + // Since piece0> piece1 is assumed, there is no possibility of replacement. return king() == rhs.king() && piece0() == rhs.piece0() && piece1() == rhs.piece1(); } bool operator!=(const KKPP& rhs) { return !(*this == rhs); } @@ -1015,12 +1015,12 @@ namespace EvalLearningTools int king_; Eval::BonaPiece piece0_, piece1_; - // kppp[king_sq][fe_end][fe_end]の[fe_end][fe_end]な正方配列の部分を三角配列化する。 + // Triangularize the square array part of [fe_end][fe_end] of kppp[king_sq][fe_end][fe_end]. uint64_t triangle_fe_end = 0; }; - // デバッグ用出力。 + // Output for debugging. static std::ostream& operator<<(std::ostream& os, KKPP rhs) { os << "KKPP(" << rhs.king() << "," << rhs.piece0() << "," << rhs.piece1() << ")"; @@ -1031,4 +1031,4 @@ namespace EvalLearningTools } #endif // defined (EVAL_LEARN) -#endif +#endif \ No newline at end of file diff --git a/src/learn/multi_think.cpp b/src/learn/multi_think.cpp index 2dcb5b46..34f5373d 100644 --- a/src/learn/multi_think.cpp +++ b/src/learn/multi_think.cpp @@ -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 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) \ No newline at end of file diff --git a/src/learn/multi_think.h b/src/learn/multi_think.h index ad6baa5e..a2ef8cde 100644 --- a/src/learn/multi_think.h +++ b/src/learn/multi_think.h @@ -11,9 +11,9 @@ #include -// 棋譜からの学習や、自ら思考させて定跡を生成するときなど、 -// 複数スレッドが個別に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 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 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 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 loop_max; - // workerが処理した(Search::think()を呼び出した)回数 + // number of times the worker has processed (calls Search::think()) std::atomic loop_count; - // 処理した回数を返す用。 + // To return the number of times it has been processed. std::atomic done_count; - // ↑の変数を変更するときのmutex + // Mutex when changing the variables in ↑ std::mutex loop_mutex; - // スレッドの終了フラグ。 - // vectorにすると複数スレッドから書き換えようとしたときに正しく反映されないことがある…はず。 + // Thread end flag. + // vector may not be reflected properly when trying to rewrite from multiple threads... typedef uint8_t Flag; std::vector 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 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 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 tasks; - // [ASYNC] taskを一つ取り出す。on_idle()から呼び出される。 + // Take out one [ASYNC] task. Called from on_idle(). Task get_task_async() { std::unique_lock 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 \ No newline at end of file