From 08d8adbadedc6f822c5f0f35d378237ac06aed01 Mon Sep 17 00:00:00 2001 From: FireFather Date: Wed, 24 Jun 2020 22:41:00 +0200 Subject: [PATCH 1/3] added header guards 5 include files in \eval\nnue\architectures --- src/eval/nnue/architectures/halfkp-cr-ep_256x2-32-32.h | 4 ++++ src/eval/nnue/architectures/halfkp_256x2-32-32.h | 4 ++++ src/eval/nnue/architectures/k-p-cr-ep_256x2-32-32.h | 4 ++++ src/eval/nnue/architectures/k-p-cr_256x2-32-32.h | 4 ++++ src/eval/nnue/architectures/k-p_256x2-32-32.h | 3 +++ 5 files changed, 19 insertions(+) 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 7063f334..9f1f97c0 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,5 +1,8 @@ // NNUE•]‰¿ŠÖ”‚Å—p‚¢‚é“ü—Í“Á’¥—ʂƃlƒbƒgƒ[ƒN\‘¢‚Ì’è‹` +#ifndef HALFKP_CR_EP_256X2_32_32_H +#define HALFKP_CR_EP_256X2_32_32_H + #include "../features/feature_set.h" #include "../features/half_kp.h" #include "../features/castling_right.h" @@ -36,3 +39,4 @@ namespace Eval { } // namespace NNUE } // namespace Eval +#endif // HALFKP_CR_EP_256X2_32_32_H \ No newline at end of file diff --git a/src/eval/nnue/architectures/halfkp_256x2-32-32.h b/src/eval/nnue/architectures/halfkp_256x2-32-32.h index 9b25ee54..c79747c3 100644 --- a/src/eval/nnue/architectures/halfkp_256x2-32-32.h +++ b/src/eval/nnue/architectures/halfkp_256x2-32-32.h @@ -1,5 +1,8 @@ // NNUE評価関数ã§ç”¨ã„る入力特徴é‡ã¨ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯æ§‹é€ ã®å®šç¾© +#ifndef HALFKP_256X2_32_32_H +#define HALFKP_256X2_32_32_H + #include "../features/feature_set.h" #include "../features/half_kp.h" @@ -33,3 +36,4 @@ using Network = Layers::OutputLayer; } // namespace NNUE } // namespace Eval +#endif // HALFKP_256X2_32_32_H 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 17871169..dc761866 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,5 +1,8 @@ // NNUE•]‰¿ŠÖ”‚Å—p‚¢‚é“ü—Í“Á’¥—ʂƃlƒbƒgƒ[ƒN\‘¢‚Ì’è‹` +#ifndef K_P_CR_EP_256X2_32_32_H +#define K_P_CR_EP_256X2_32_32_H + #include "../features/feature_set.h" #include "../features/k.h" #include "../features/p.h" @@ -36,3 +39,4 @@ namespace Eval { } // namespace NNUE } // namespace Eval +#endif // K_P_CR_EP_256X2_32_32_H \ No newline at end of file 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 9ce7ecf1..331cb4f2 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,5 +1,8 @@ // NNUE•]‰¿ŠÖ”‚Å—p‚¢‚é“ü—Í“Á’¥—ʂƃlƒbƒgƒ[ƒN\‘¢‚Ì’è‹` +#ifndef K_P_CR_256X2_32_32_H +#define K_P_CR_256X2_32_32_H + #include "../features/feature_set.h" #include "../features/k.h" #include "../features/p.h" @@ -35,3 +38,4 @@ namespace Eval { } // namespace NNUE } // namespace Eval +#endif // K_P_CR_256X2_32_32_H \ No newline at end of file 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 b77aeaa6..2576ddfa 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,6 @@ // NNUE評価関数ã§ç”¨ã„る入力特徴é‡ã¨ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯æ§‹é€ ã®å®šç¾© +#ifndef K_P_256X2_32_32_H +#define K_P_256X2_32_32_H #include "../features/feature_set.h" #include "../features/k.h" @@ -33,3 +35,4 @@ using Network = Layers::OutputLayer; } // namespace NNUE } // namespace Eval +#endif // K_P_256X2_32_32_H \ No newline at end of file From 86e3fedf7e19482d5c9056d0415ac8284e99125f Mon Sep 17 00:00:00 2001 From: FireFather Date: Thu, 25 Jun 2020 04:38:39 +0200 Subject: [PATCH 2/3] Update evaluate_nnue.cpp --- src/eval/nnue/evaluate_nnue.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/eval/nnue/evaluate_nnue.cpp b/src/eval/nnue/evaluate_nnue.cpp index ce478783..46b3b5f9 100644 --- a/src/eval/nnue/evaluate_nnue.cpp +++ b/src/eval/nnue/evaluate_nnue.cpp @@ -250,10 +250,14 @@ void load_eval() { if (!result) { // 読ã¿è¾¼ã¿ã‚¨ãƒ©ãƒ¼ã®ã¨ã終了ã—ã¦ãれãªã„ã¨å›°ã‚‹ã€‚ - std::cout << "Error! : failed to read " << NNUE::kFileName << std::endl; - my_exit(); + std::cout << "Error! " << NNUE::kFileName << " not found or wrong format" << std::endl; + //my_exit(); } + else + std::cout << "info string NNUE " << NNUE::kFileName << " found & loaded" << std::endl; } + else + std::cout << "info string NNUE " << NNUE::kFileName << " not loaded" << std::endl; } // åˆæœŸåŒ– From aea08de018a72c2ecb86b568853e3815b32551e6 Mon Sep 17 00:00:00 2001 From: FireFather Date: Sun, 28 Jun 2020 03:12:55 +0200 Subject: [PATCH 3/3] Translation Files in /eval, /extra, & /learn - comments translated from Japanese to English --- src/eval/evaluate_common.h | 72 +- src/eval/evaluate_mir_inv_tools.cpp | 72 +- src/eval/evaluate_mir_inv_tools.h | 30 +- .../architectures/halfkp-cr-ep_256x2-32-32.h | 8 +- .../nnue/architectures/halfkp_256x2-32-32.h | 8 +- .../architectures/k-p-cr-ep_256x2-32-32.h | 8 +- .../nnue/architectures/k-p-cr_256x2-32-32.h | 8 +- src/eval/nnue/architectures/k-p_256x2-32-32.h | 8 +- src/eval/nnue/evaluate_nnue.cpp | 114 +- src/eval/nnue/evaluate_nnue.h | 24 +- src/eval/nnue/evaluate_nnue_learner.cpp | 44 +- src/eval/nnue/evaluate_nnue_learner.h | 20 +- src/eval/nnue/features/castling_right.cpp | 10 +- src/eval/nnue/features/castling_right.h | 20 +- src/eval/nnue/features/enpassant.cpp | 8 +- src/eval/nnue/features/enpassant.h | 20 +- src/eval/nnue/features/feature_set.h | 62 +- src/eval/nnue/features/features_common.h | 26 +- src/eval/nnue/features/half_kp.cpp | 10 +- src/eval/nnue/features/half_kp.h | 24 +- src/eval/nnue/features/half_relative_kp.cpp | 12 +- src/eval/nnue/features/half_relative_kp.h | 30 +- src/eval/nnue/features/index_list.h | 8 +- src/eval/nnue/features/k.cpp | 8 +- src/eval/nnue/features/k.h | 20 +- src/eval/nnue/features/p.cpp | 8 +- src/eval/nnue/features/p.h | 20 +- src/eval/nnue/layers/affine_transform.h | 32 +- src/eval/nnue/layers/clipped_relu.h | 26 +- src/eval/nnue/layers/input_slice.h | 24 +- src/eval/nnue/layers/sum.h | 58 +- src/eval/nnue/nnue_accumulator.h | 8 +- src/eval/nnue/nnue_architecture.h | 8 +- src/eval/nnue/nnue_common.h | 18 +- src/eval/nnue/nnue_feature_transformer.h | 40 +- src/eval/nnue/nnue_test_command.cpp | 22 +- src/eval/nnue/nnue_test_command.h | 4 +- src/eval/nnue/trainer/features/factorizer.h | 28 +- .../trainer/features/factorizer_feature_set.h | 24 +- .../trainer/features/factorizer_half_kp.h | 18 +- src/eval/nnue/trainer/trainer.h | 22 +- .../nnue/trainer/trainer_affine_transform.h | 54 +- src/eval/nnue/trainer/trainer_clipped_relu.h | 38 +- .../trainer/trainer_feature_transformer.h | 54 +- src/eval/nnue/trainer/trainer_input_slice.h | 62 +- src/eval/nnue/trainer/trainer_sum.h | 66 +- src/extra/sfen_packer.cpp | 193 ++- src/learn/half_float.h | 8 +- src/learn/learn.h | 176 +-- src/learn/learner.cpp | 1367 ++++++++--------- src/learn/learning_tools.cpp | 58 +- src/learn/learning_tools.h | 528 +++---- src/learn/multi_think.cpp | 74 +- src/learn/multi_think.h | 96 +- 54 files changed, 1903 insertions(+), 1905 deletions(-) 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‚¢‚é“ü—Í“Á’¥—ʂƃlƒbƒgƒ[ƒ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 { - // ƒlƒbƒgƒ[ƒ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‚¢‚é“ü—Í“Á’¥—ʂƃlƒbƒgƒ[ƒ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 { - // ƒlƒbƒgƒ[ƒ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‚¢‚é“ü—Í“Á’¥—ʂƃlƒbƒgƒ[ƒ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 { - // ƒlƒbƒgƒ[ƒ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ƒ‹‚É–„‚ßž‚ÞƒnƒbƒVƒ…’l + // 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“¯Žž‚É’l‚ª1‚ƂȂéƒCƒ“ƒfƒbƒNƒX‚Ì”‚ÌÅ‘å’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; - // ·•ªŒvŽZ‚Ì‘ã‚í‚è‚É‘SŒvŽZ‚ðs‚¤ƒ^ƒCƒ~ƒ“ƒO + // Timing of full calculation instead of difference calculation static constexpr TriggerEvent kRefreshTrigger = TriggerEvent::kNone; - // “Á’¥—ʂ̂¤‚¿A’l‚ª1‚Å‚ ‚éƒCƒ“ƒfƒbƒNƒX‚ÌƒŠƒXƒg‚ðŽæ“¾‚·‚é + // Get a list of indices with a value of 1 among the features static void AppendActiveIndices(const Position& pos, Color perspective, IndexList* active); - // “Á’¥—ʂ̂¤‚¿AˆêŽè‘O‚©‚ç’l‚ª•ω»‚µ‚½ƒCƒ“ƒfƒbƒNƒX‚ÌƒŠƒXƒg‚ðŽæ“¾‚·‚é + // 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 { - // “Á’¥—ʂ̂¤‚¿A’l‚ª1‚Å‚ ‚éƒCƒ“ƒfƒbƒNƒX‚ÌƒŠƒXƒg‚ðŽæ“¾‚·‚é + // Get a list of indices with a value of 1 among the features void EnPassant::AppendActiveIndices( const Position& pos, Color perspective, IndexList* active) { - // ƒRƒ“ƒpƒCƒ‰‚ÌŒx‚ð‰ñ”ð‚·‚é‚½‚ßA”z—ñƒTƒCƒY‚ª¬‚³‚¢ê‡‚͉½‚à‚µ‚È‚¢ + // 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); } - // “Á’¥—ʂ̂¤‚¿AˆêŽè‘O‚©‚ç’l‚ª•ω»‚µ‚½ƒCƒ“ƒfƒbƒNƒX‚ÌƒŠƒXƒg‚ðŽæ“¾‚·‚é + // 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ƒ‹‚É–„‚ßž‚ÞƒnƒbƒVƒ…’l + // 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“¯Žž‚É’l‚ª1‚ƂȂéƒCƒ“ƒfƒbƒNƒX‚Ì”‚ÌÅ‘å’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; - // ·•ªŒvŽZ‚Ì‘ã‚í‚è‚É‘SŒvŽZ‚ðs‚¤ƒ^ƒCƒ~ƒ“ƒO + // Timing of full calculation instead of difference calculation static constexpr TriggerEvent kRefreshTrigger = TriggerEvent::kAnyPieceMoved; - // “Á’¥—ʂ̂¤‚¿A’l‚ª1‚Å‚ ‚éƒCƒ“ƒfƒbƒNƒX‚ÌƒŠƒXƒg‚ðŽæ“¾‚·‚é + // Get a list of indices with a value of 1 among the features static void AppendActiveIndices(const Position& pos, Color perspective, IndexList* active); - // “Á’¥—ʂ̂¤‚¿AˆêŽè‘O‚©‚ç’l‚ª•ω»‚µ‚½ƒCƒ“ƒfƒbƒNƒX‚ÌƒŠƒXƒg‚ðŽæ“¾‚·‚é + // 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 8ef8fee4..502fbc05 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_ @@ -15,17 +15,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) @@ -35,17 +35,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 f105296f..fb0d9959 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ã®æ•°å€¤ï¼’ã¤ãã£ã¤ã‘ã¦ãŠã。 + // 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) { // In Maxima, @@ -1047,43 +1047,41 @@ double delta_winning_percentage(double value) 0.5756462732485115 * pow(PawnValue, -1) * pow(10.0, -0.25 * pow(PawnValue, -1) * value) * pow(pow(10.0, -0.25 * pow(PawnValue, -1) * value) + 1.0, -2); } - -// 普通ã®ã‚·ã‚°ãƒ¢ã‚¤ãƒ‰é–¢æ•°ã®å°Žé–¢æ•°ã€‚ 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); @@ -1094,22 +1092,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); @@ -1121,41 +1119,41 @@ 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); const double dq = delta_winning_percentage(shallow); - // 期待å‹çŽ‡ã‚’å‹ã£ã¦ã„れã°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 pp = (q - p) * dq / q / (1.0 - q); const double tt = (q - t) * dq / q / (1.0 - q); const double grad = lambda * pp + (1.0 - lambda) * tt; @@ -1163,8 +1161,8 @@ double calc_grad(Value deep, Value shallow , const PackedSfenValue& psv) 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) @@ -1175,7 +1173,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; @@ -1198,13 +1196,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())()) @@ -1233,12 +1232,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(); @@ -1253,7 +1252,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()); @@ -1280,35 +1279,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; } @@ -1316,17 +1316,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(); @@ -1337,24 +1337,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 = [&]() @@ -1362,11 +1362,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(); @@ -1379,8 +1379,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) @@ -1389,7 +1389,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; @@ -1398,10 +1398,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; @@ -1409,7 +1409,7 @@ struct SfenReader } } - // ã“ã®èª­ã¿è¾¼ã‚“ã å±€é¢ãƒ‡ãƒ¼ã‚¿ã‚’shuffleã™ã‚‹ã€‚ + // Shuffle the read phase data. // random shuffle by Fisher-Yates algorithm if (!no_shuffle) @@ -1419,8 +1419,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); @@ -1429,7 +1429,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); @@ -1437,12 +1437,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]); @@ -1450,76 +1450,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) @@ -1544,43 +1544,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; @@ -1604,20 +1604,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"; @@ -1631,8 +1632,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; @@ -1642,16 +1643,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; @@ -1660,36 +1661,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; @@ -1707,34 +1708,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; @@ -1744,31 +1745,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); @@ -1782,8 +1783,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) { @@ -1812,7 +1813,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; @@ -1836,11 +1837,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())) @@ -1850,20 +1851,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; @@ -1871,33 +1872,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) { @@ -1907,33 +1908,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. } } @@ -1941,17 +1942,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; @@ -2226,7 +2227,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; @@ -2235,22 +2236,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)); @@ -2263,47 +2264,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)); @@ -2316,7 +2317,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); @@ -2325,57 +2326,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; @@ -2414,14 +2415,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; @@ -2430,7 +2431,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; @@ -2443,7 +2444,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) { @@ -2454,9 +2455,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; @@ -2480,7 +2480,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); } @@ -2488,7 +2488,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; } @@ -2702,7 +2702,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; @@ -2711,14 +2710,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; @@ -2737,7 +2736,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"]; @@ -2746,62 +2745,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) @@ -2811,15 +2810,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) @@ -2835,7 +2834,7 @@ void learn(Position&, istringstream& is) string validation_set_file_name; - // ファイルåãŒå¾Œã‚ã«ãšã‚‰ãšã‚‰ã¨æ›¸ã‹ã‚Œã¦ã„ã‚‹ã¨ä»®å®šã—ã¦ã„る。 + // Assume the filenames are staggered. while (true) { string option; @@ -2844,26 +2843,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; @@ -2874,10 +2873,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]; @@ -2899,7 +2898,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; @@ -2909,7 +2908,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; @@ -2920,13 +2919,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); } @@ -2935,25 +2934,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)) @@ -2969,17 +2968,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; @@ -3003,7 +3002,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; @@ -3025,11 +3024,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) { @@ -3052,9 +3051,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)); @@ -3079,7 +3078,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; @@ -3101,18 +3100,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; @@ -3125,7 +3124,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); @@ -3138,7 +3137,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; @@ -3154,20 +3153,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) { @@ -3180,17 +3179,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 } @@ -3203,4 +3202,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ãŒï¼’ã¤ã‚ã‚‹ã¨ãã«ã€è«–ç†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ãŒä¸€æžšå°‘ãªã„ã‚‚ã®ã¨ã—ã¦æ‰±ã†ã€‚ - // ï¼’ã¤ã®çމã®ä½ç½®ã¯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