Translation

Files in /eval, /extra, & /learn - comments translated from Japanese to English
This commit is contained in:
FireFather
2020-06-28 03:12:55 +02:00
parent 2f8c692caa
commit aea08de018
54 changed files with 1903 additions and 1905 deletions
+4 -4
View File
@@ -4,8 +4,8 @@
// Half Float Library by yaneurao
// (16-bit float)
// 16bit型による浮動小数点演算
// コンパイラの生成するfloat型のコードがIEEE 754の形式であると仮定して、それを利用する。
// Floating point operation by 16bit type
// Assume that the float type code generated by the compiler is in IEEE 754 format and use it.
#include "../types.h"
@@ -99,7 +99,7 @@ namespace HalfFloat
return c.f;
}
// unit testになってないが、一応計算が出来ることは確かめた。コードはあとでなおす(かも)。
// It is not a unit test, but I confirmed that it can be calculated. I'll fix the code later (maybe).
static void unit_test()
{
float16 a, b, c, d;
@@ -130,4 +130,4 @@ namespace HalfFloat
}
#endif // __HALF_FLOAT_H__
#endif // __HALF_FLOAT_H__
+88 -88
View File
@@ -6,173 +6,173 @@
#include <vector>
// =====================
// 学習時の設定
// Settings for learning
// =====================
// 以下のいずれかを選択すれば、そのあとの細々したものは自動的に選択される。
// いずれも選択しない場合は、そのあとの細々したものをひとつひとつ設定する必要がある。
// If you select one of the following, the details after that will be automatically selected.
// If you don't select any of them, you need to set the subsequent details one by one.
// elmo方式での学習設定。これをデフォルト設定とする。
// 標準の雑巾絞りにするためにはlearnコマンドで "lambda 1"を指定してやれば良い。
// Learning setting by elmo method. This is the default setting.
// To make a standard squeeze diaphragm, specify "lambda 1" with the learn command.
#define LEARN_ELMO_METHOD
// ----------------------
// 更新式
// update formula
// ----------------------
// AdaGrad。これが安定しているのでお勧め。
// Ada Grad. Recommended because it is stable.
// #define ADA_GRAD_UPDATE
// 勾配の符号だけ見るSGD。省メモリで済むが精度は…。
// SGD looking only at the sign of the gradient. It requires less memory, but the accuracy is...
// #define SGD_UPDATE
// ----------------------
// 学習時の設定
// Settings for learning
// ----------------------
// mini-batchサイズ。
// この数だけの局面をまとめて勾配を計算する。
// 小さくするとupdate_weights()の回数が増えるので収束が速くなる。勾配が不正確になる。
// 大きくするとupdate_weights()の回数が減るので収束が遅くなる。勾配は正確に出るようになる。
// 多くの場合において、この値を変更する必要はないと思う。
// mini-batch size.
// Calculate the gradient by combining this number of phases.
// If you make it smaller, the number of update_weights() will increase and the convergence will be faster. The gradient is incorrect.
// If you increase it, the number of update_weights() decreases, so the convergence will be slow. The slope will come out accurately.
// I don't think you need to change this value in most cases.
#define LEARN_MINI_BATCH_SIZE (1000 * 1000 * 1)
// ファイルから1回に読み込む局面数。これだけ読み込んだあとshuffleする。
// ある程度大きいほうが良いが、この数×40byte×3倍ぐらいのメモリを消費する。10M局面なら400MB*3程度消費する。
// THREAD_BUFFER_SIZE(=10000)の倍数にすること。
// The number of phases to read from the file at one time. After reading this much, shuffle.
// It is better to have a certain size, but this number x 40 bytes x 3 times as much memory is consumed. 400MB*3 is consumed in the 10M phase.
// Must be a multiple of THREAD_BUFFER_SIZE(=10000).
#define LEARN_SFEN_READ_SIZE (1000 * 1000 * 10)
// 学習時の評価関数の保存間隔。この局面数だけ学習させるごとに保存。
// 当然ながら、保存間隔を長くしたほうが学習時間は短くなる。
// フォルダ名は 0/ , 1/ , 2/ ...のように保存ごとにインクリメントされていく。
// デフォルトでは10億局面に1回。
// Saving interval of evaluation function at learning. Save each time you learn this number of phases.
// Needless to say, the longer the saving interval, the shorter the learning time.
// Folder name is incremented for each save like 0/, 1/, 2/...
// By default, once every 1 billion phases.
#define LEARN_EVAL_SAVE_INTERVAL (1000000000ULL)
// ----------------------
// 目的関数の選択
// Select the objective function
// ----------------------
// 目的関数が勝率の差の二乗和
// 詳しい説明は、learner.cppを見ること。
// The objective function is the sum of squares of the difference in winning percentage
// See learner.cpp for more information.
//#define LOSS_FUNCTION_IS_WINNING_PERCENTAGE
// 目的関数が交差エントロピー
// 詳しい説明は、learner.cppを見ること。
// いわゆる、普通の「雑巾絞り」
// Objective function is cross entropy
// See learner.cpp for more information.
// So-called ordinary "rag cloth squeezer"
//#define LOSS_FUNCTION_IS_CROSS_ENTOROPY
// 目的関数が交差エントロピーだが、勝率の関数を通さない版
// A version in which the objective function is cross entropy, but the win rate function is not passed
// #define LOSS_FUNCTION_IS_CROSS_ENTOROPY_FOR_VALUE
// elmo(WCSC27)の方式
// elmo (WCSC27) method
// #define LOSS_FUNCTION_IS_ELMO_METHOD
// ※ 他、色々追加するかも。
// ※ Other things may be added.
// ----------------------
// 学習に関するデバッグ設定
// debug settings for learning
// ----------------------
// 学習時のrmseの出力をこの回数に1回に減らす。
// rmseの計算は1スレッドで行なうためそこそこ時間をとられるので出力を減らすと効果がある。
// Reduce the output of rmse during learning to 1 for this number of times.
// rmse calculation is done in one thread, so it takes some time, so reducing the output is effective.
#define LEARN_RMSE_OUTPUT_INTERVAL 1
// ----------------------
// ゼロベクトルからの学習
// learning from zero vector
// ----------------------
// 評価関数パラメーターをゼロベクトルから学習を開始する。
// ゼロ初期化して棋譜生成してゼロベクトルから学習させて、
// 棋譜生成→学習を繰り返すとプロの棋譜に依らないパラメーターが得られる。(かも)
// (すごく時間かかる)
// Start learning the evaluation function parameters from the zero vector.
// Initialize to zero, generate a game, learn from zero vector,
// Game generation → If you repeat learning, you will get parameters that do not depend on the professional game. (maybe)
// (very time consuming)
//#define RESET_TO_ZERO_VECTOR
// ----------------------
// 学習のときの浮動小数
// Floating point for learning
// ----------------------
// これをdoubleにしたほうが計算精度は上がるが、重み配列絡みのメモリが倍必要になる。
// 現状、ここをfloatにした場合、評価関数ファイルに対して、重み配列はその4.5倍のサイズ。(KPPTで4.5GB程度)
// double型にしても収束の仕方にほとんど差異がなかったのでfloatに固定する。
// If this is set to double, the calculation accuracy will be higher, but the weight array entangled memory will be doubled.
// Currently, if this is float, the weight array is 4.5 times the size of the evaluation function file. (About 4.5GB with KPPT)
// Even if it is a double type, there is almost no difference in the way of convergence, so fix it to float.
// floatを使う場合
// when using float
typedef float LearnFloatType;
// doubleを使う場合
// when using double
//typedef double LearnFloatType;
// float16を使う場合
// when using float16
//#include "half_float.h"
//typedef HalfFloat::float16 LearnFloatType;
// ----------------------
// 省メモリ化
// save memory
// ----------------------
// Weight配列(のうちのKPP)に三角配列を用いて省メモリ化する。
// これを用いると、学習用の重み配列は評価関数ファイルの3倍程度で済むようになる。
// Use a triangular array for the Weight array (of which is KPP) to save memory.
// If this is used, the weight array for learning will be about 3 times as large as the evaluation function file.
#define USE_TRIANGLE_WEIGHT_ARRAY
// ----------------------
// 次元下げ
// dimension down
// ----------------------
// ミラー(左右対称性)、インバース(先後対称性)に関して次元下げを行なう。
// デフォルトではすべてオン。
// Dimension reduction for mirrors (left/right symmetry) and inverse (forward/backward symmetry).
// All on by default.
// KKに対してミラー、インバースを利用した次元下げを行なう。(効果のほどは不明)
// USE_KK_INVERSE_WRITEをオンにするときはUSE_KK_MIRROR_WRITEもオンでなければならない。
// Dimension reduction using mirror and inverse for KK. (Unclear effect)
// USE_KK_MIRROR_WRITE must be on when USE_KK_INVERSE_WRITE is on.
#define USE_KK_MIRROR_WRITE
#define USE_KK_INVERSE_WRITE
// KKPに対してミラー、インバースを利用した次元下げを行なう。(インバースのほうは効果のほどは不明)
// USE_KKP_INVERSE_WRITEをオンにするときは、USE_KKP_MIRROR_WRITEもオンになっていなければならない。
// Dimension reduction using Mirror and Inverse for KKP. (Inverse is not so effective)
// When USE_KKP_INVERSE_WRITE is turned on, USE_KKP_MIRROR_WRITE must also be turned on.
#define USE_KKP_MIRROR_WRITE
#define USE_KKP_INVERSE_WRITE
// KPPに対してミラーを利用した次元下げを行なう。(これをオフにすると教師局面が倍ぐらい必要になる)
// KPPにはインバースはない。(先手側のKしかないので)
// Perform dimension reduction using a mirror for KPP. (Turning this off requires double the teacher position)
// KPP has no inverse. (Because there is only K on the front side)
#define USE_KPP_MIRROR_WRITE
// KPPPに対してミラーを利用した次元下げを行なう。(これをオフにすると教師局面が倍ぐらい必要になる)
// KPPPにもインバースはない。(先手側のKしかないので)
// Perform a dimension reduction using a mirror for KPPP. (Turning this off requires double the teacher position)
// KPPP has no inverse. (Because there is only K on the front side)
#define USE_KPPP_MIRROR_WRITE
// KKPP成分に対して学習時にKPPによる次元下げを行なう。
// 学習、めっちゃ遅くなる。
// 未デバッグなので使わないこと。
// Reduce the dimension by KPP for learning the KKPP component.
// Learning is very slow.
// Do not use as it is not debugged.
//#define USE_KKPP_LOWER_DIM
// ======================
// 教師局面生成時の設定
// Settings for creating teacher phases
// ======================
// ----------------------
// 引き分けを書き出す
// write out the draw
// ----------------------
// 引き分けに至ったとき、それを教師局面として書き出す
// これをするほうが良いかどうかは微妙。
// When you reach a draw, write it out as a teacher position
// It's subtle whether it's better to do this.
// #define LEARN_GENSFEN_USE_DRAW_RESULT
// ======================
// configure
// configure
// ======================
// ----------------------
// elmo(WCSC27)の方法での学習
// Learning with the method of elmo (WCSC27)
// ----------------------
#if defined( LEARN_ELMO_METHOD )
@@ -182,49 +182,49 @@ typedef float LearnFloatType;
// ----------------------
// Learnerで用いるstructの定義
// Definition of struct used in Learner
// ----------------------
#include "../position.h"
namespace Learner
{
// PackedSfenと評価値が一体化した構造体
// オプションごとに書き出す内容が異なると教師棋譜を再利用するときに困るので
// とりあえず、以下のメンバーはオプションによらずすべて書き出しておく。
//Structure in which PackedSfen and evaluation value are integrated
// If you write different contents for each option, it will be a problem when reusing the teacher game
// For the time being, write all the following members regardless of the options.
struct PackedSfenValue
{
// 局面
// phase
PackedSfen sfen;
// Learner::search()から返ってきた評価値
// Evaluation value returned from Learner::search()
int16_t score;
// PVの初手
// 教師との指し手一致率を求めるときなどに用いる
// PV first move
// Used when finding the match rate with the teacher
uint16_t move;
// 初期局面からの局面の手数。
// Trouble of the phase from the initial phase.
uint16_t gamePly;
// この局面の手番側が、ゲームを最終的に勝っているなら1。負けているなら-1。
// 引き分けに至った場合は、0。
// 引き分けは、教師局面生成コマンドgensfenにおいて、
// LEARN_GENSFEN_DRAW_RESULTが有効なときにだけ書き出す。
// 1 if the player on this side ultimately wins the game. -1 if you are losing.
// 0 if a draw is reached.
// The draw is in the teacher position generation command gensfen,
// Only write if LEARN_GENSFEN_DRAW_RESULT is enabled.
int8_t game_result;
// 教師局面を書き出したファイルを他の人とやりとりするときに
// この構造体サイズが不定だと困るため、paddingしてどの環境でも必ず40bytesになるようにしておく。
// When exchanging the file that wrote the teacher aspect with other people
//Because this structure size is not fixed, pad it so that it is 40 bytes in any environment.
uint8_t padding;
// 32 + 2 + 2 + 2 + 1 + 1 = 40bytes
};
// 読み筋とそのときの評価値を返す型
// Learner::search() , Learner::qsearch()で用いる。
// Type that returns the reading line and the evaluation value at that time
// Used in Learner::search(), Learner::qsearch().
typedef std::pair<Value, std::vector<Move> > ValueAndPV;
// いまのところ、やねうら王2018 Otafukuしか、このスタブを持っていないが
// EVAL_LEARNdefineするなら、このスタブが必須。
// 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_
+683 -684
View File
File diff suppressed because it is too large Load Diff
+29 -29
View File
@@ -23,15 +23,15 @@ namespace EvalLearningTools
std::vector<bool> min_index_flag;
// --- 個別のテーブルごとの初期化
// --- initialization for each individual table
void init_min_index_flag()
{
// mir_pieceinv_pieceの初期化が終わっていなければならない。
// Initialization of mir_piece and inv_piece must be completed.
assert(mir_piece(Eval::f_pawn) == Eval::e_pawn);
// 次元下げ用フラグ配列の初期化
// KPPPに関しては関与しない。
// Initialize the flag array for dimension reduction
// Not involved in KPPP.
KK g_kk;
g_kk.set(SQUARE_NB, Eval::fe_end, 0);
@@ -46,9 +46,9 @@ namespace EvalLearningTools
#pragma omp parallel
{
#if defined(_OPENMP)
// Windows環境下でCPUが2つあるときに、論理64コアまでしか使用されないのを防ぐために
// ここで明示的にCPUに割り当てる
int thread_index = omp_get_thread_num(); // 自分のthread numberを取得
// To prevent the logical 64 cores from being used when there are two CPUs under Windows
// explicitly assign to CPU here
int thread_index = omp_get_thread_num(); // get your thread number
WinProcGroup::bindThisThread(thread_index);
#endif
@@ -56,20 +56,20 @@ namespace EvalLearningTools
for (int64_t index_ = 0; index_ < (int64_t)size; ++index_)
{
// OpenMPの制約からループ変数は符号型でないといけないらしいのだが、
// さすがに使いにくい。
// It seems that the loop variable must be a sign type due to OpenMP restrictions, but
// It's really difficult to use.
uint64_t index = (uint64_t)index_;
if (g_kk.is_ok(index))
{
// indexからの変換と逆変換によって元のindexに戻ることを確認しておく。
// 起動時に1回しか実行しない処理なのでassertで書いておく。
// Make sure that the original index will be restored by conversion from index and reverse conversion.
// It is a process that is executed only once at startup, so write it in assert.
assert(g_kk.fromIndex(index).toIndex() == index);
KK a[KK_LOWER_COUNT];
g_kk.fromIndex(index).toLowerDimensions(a);
// 次元下げの1つ目の要素が元のindexと同一であることを確認しておく。
// Make sure that the first element of dimension reduction is the same as the original index.
assert(a[0].toIndex() == index);
uint64_t min_index = UINT64_MAX;
@@ -118,9 +118,9 @@ namespace EvalLearningTools
void learning_tools_unit_test_kpp()
{
// KPPの三角配列化にバグがないかテストする
// k-p0-p1のすべての組み合わせがきちんとKPPの扱う対象になっていかと、そのときの次元下げが
// 正しいかを判定する。
// test KPP triangulation for bugs
// All combinations of k-p0-p1 are properly handled by KPP, and the dimension reduction at that time is
// Determine if it is correct.
KK g_kk;
g_kk.set(SQUARE_NB, Eval::fe_end, 0);
@@ -159,24 +159,24 @@ namespace EvalLearningTools
f[index - g_kpp.min_index()] = f[index2-g_kpp.min_index()] = true;
}
// 抜けてるindexがなかったかの確認。
// Check if there is no missing index.
for(size_t index = 0 ; index < f.size(); index++)
if (!f[index])
{
std::cout << index << g_kpp.fromIndex(index + g_kpp.min_index()) << std::endl;
std::cout << index << g_kpp.fromIndex(index + g_kpp.min_index()) << std::endl;
}
}
void learning_tools_unit_test_kppp()
{
// KPPPの計算に抜けがないかをテストする
// Test for missing KPPP calculations
KPPP g_kppp;
g_kppp.set(15, Eval::fe_end,0);
uint64_t min_index = g_kppp.min_index();
uint64_t max_index = g_kppp.max_index();
// 最後の要素の確認。
// Confirm last element.
//KPPP x = KPPP::fromIndex(max_index-1);
//std::cout << x << std::endl;
@@ -208,10 +208,10 @@ namespace EvalLearningTools
void learning_tools_unit_test_kkpp()
{
KKPP g_kkpp;
g_kkpp.set(SQUARE_NB, 10000 , 0);
g_kkpp.set(SQUARE_NB, 10000, 0);
uint64_t n = 0;
for (int k = 0; k<SQUARE_NB; ++k)
for (int i = 0; i<10000; ++i) // 試しに、かなり大きなfe_endを想定して10000で回してみる。
for (int i = 0; i<10000; ++i) // As a test, assuming a large fe_end, try turning at 10000.
for (int j = 0; j < i; ++j)
{
auto kkpp = g_kkpp.fromKKPP(k, (BonaPiece)i, (BonaPiece)j);
@@ -222,27 +222,27 @@ namespace EvalLearningTools
}
}
// このEvalLearningTools全体の初期化
// Initialize this entire EvalLearningTools
void init()
{
// 初期化は、起動後1回限りで良いのでそのためのフラグ。
// Initialization is required only once after startup, so a flag for that.
static bool first = true;
if (first)
{
std::cout << "EvalLearningTools init..";
// mir_piece()inv_piece()を利用可能にする。
// このあとmin_index_flagの初期化を行なうが、そこが
// これに依存しているので、こちらを先に行なう必要がある。
// Make mir_piece() and inv_piece() available.
// After this, the min_index_flag is initialized, but
// It depends on this, so you need to do this first.
init_mir_inv_tables();
//learning_tools_unit_test_kpp();
//learning_tools_unit_test_kppp();
//learning_tools_unit_test_kkpp();
// UnitTestを実行するの最後でも良いのだが、init_min_index_flag()にとても時間がかかるので
// デバッグ時はこのタイミングで行いたい。
// It may be the last time to execute UnitTest, but since init_min_index_flag() takes a long time,
// I want to do this at the time of debugging.
init_min_index_flag();
@@ -253,4 +253,4 @@ namespace EvalLearningTools
}
}
#endif
#endif
+264 -264
View File
File diff suppressed because it is too large Load Diff
+37 -37
View File
@@ -10,67 +10,67 @@
void MultiThink::go_think()
{
// あとでOptionsの設定を復元するためにコピーで保持しておく。
// Keep a copy to restore the Options settings later.
auto oldOptions = Options;
// 定跡を用いる場合、on the flyで行なうとすごく時間がかかる&ファイルアクセスを行なう部分が
// thread safeではないので、メモリに丸読みされている状態であることをここで保証する。
// When using the constant track, it takes a lot of time to perform on the fly & the part to access the file is
// Since it is not thread safe, it is guaranteed here that it is being completely read in memory.
Options["BookOnTheFly"] = std::string("false");
// 評価関数の読み込み等
// learnコマンドの場合、評価関数読み込み後に評価関数の値を補正している可能性があるので、
// メモリの破損チェックは省略する。
// Read evaluation function, etc.
// In the case of the learn command, the value of the evaluation function may be corrected after reading the evaluation function, so
// Skip memory corruption check.
is_ready(true);
// 派生クラスのinit()を呼び出す。
// Call the derived class's init().
init();
// ループ上限はset_loop_max()で設定されているものとする。
// The loop upper limit is set with set_loop_max().
loop_count = 0;
done_count = 0;
// threadをOptions["Threads"]の数だけ生成して思考開始。
// Create threads as many as Options["Threads"] and start thinking.
std::vector<std::thread> threads;
auto thread_num = (size_t)Options["Threads"];
// worker threadの終了フラグの確保
// Secure end flag of worker thread
thread_finished.resize(thread_num);
// worker threadの起動
// start worker thread
for (size_t i = 0; i < thread_num; ++i)
{
thread_finished[i] = 0;
threads.push_back(std::thread([i, this]
{
// プロセッサの全スレッドを使い切る。
// exhaust all processor threads.
WinProcGroup::bindThisThread(i);
// オーバーライドされている処理を実行
// execute the overridden process
this->thread_worker(i);
// スレッドが終了したので終了フラグを立てる
// Set the end flag because the thread has ended
this->thread_finished[i] = 1;
}));
}
// すべてのthreadの終了待ちを
// for (auto& th : threads)
// th.join();
// のように書くとスレッドがまだ仕事をしている状態でここに突入するので、
// その間、callback_func()が呼び出せず、セーブできなくなる。
// そこで終了フラグを自前でチェックする必要がある。
// wait for all threads to finish
// for (auto& th :threads)
// th.join();
// If you write like, the thread will rush here while it is still working,
// During that time, callback_func() cannot be called and you cannot save.
// Therefore, you need to check the end flag yourself.
// すべてのスレッドが終了したかを判定する関数
// function to determine if all threads have finished
auto threads_done = [&]()
{
// ひとつでも終了していなければfalseを返す
// returns false if no one is finished
for (auto& f : thread_finished)
if (!f)
return false;
return true;
};
// コールバック関数が設定されているならコールバックする。
// Call back if the callback function is set.
auto do_a_callback = [&]()
{
if (callback_func)
@@ -80,44 +80,44 @@ void MultiThink::go_think()
for (uint64_t i = 0 ; ; )
{
// 全スレッドが終了していたら、ループを抜ける。
// If all threads have finished, exit the loop.
if (threads_done())
break;
sleep(1000);
// callback_secondsごとにcallback_func()が呼び出される。
// callback_func() is called every callback_seconds.
if (++i == callback_seconds)
{
do_a_callback();
// ↑から戻ってきてからカウンターをリセットしているので、
// do_a_callback()のなかでsave()などにどれだけ時間がかかろうと
// 次に呼び出すのは、そこから一定時間の経過を要する。
// Since I am returning from ↑, I reset the counter, so
// no matter how long it takes to save() etc. in do_a_callback()
// The next call will take a certain amount of time.
i = 0;
}
}
// 最後の保存。
// Last save.
std::cout << std::endl << "finalize..";
// do_a_callback();
// → 呼び出し元で保存するはずで、ここでは要らない気がする。
// → It should be saved by the caller, so I feel that it is not necessary here.
// 終了したフラグは立っているがスレッドの終了コードの実行中であるということはありうるので
// join()でその終了を待つ必要がある。
// It is possible that the exit code of the thread is running but the exit code of the thread is running, so
// We need to wait for the end with join().
for (auto& th : threads)
th.join();
// 全スレッドが終了しただけでfileの書き出しスレッドなどはまだ動いていて
// 作業自体は完了していない可能性があるのでスレッドがすべて終了したことだけ出力する。
// The file writing thread etc. are still running only when all threads are finished
// Since the work itself may not have completed, output only that all threads have finished.
std::cout << "all threads are joined." << std::endl;
// Optionsを書き換えたので復元。
// 値を代入しないとハンドラが起動しないのでこうやって復元する。
// Restored because Options were rewritten.
// Restore the handler because the handler will not start unless you assign a value.
for (auto& s : oldOptions)
Options[s.first] = std::string(s.second);
}
#endif // defined(EVAL_LEARN)
#endif // defined(EVAL_LEARN)
+48 -48
View File
@@ -11,9 +11,9 @@
#include <atomic>
// 棋譜からの学習や、自ら思考させて定跡を生成するときなど、
// 複数スレッドが個別にSearch::think()を呼び出したいときに用いるヘルパクラス。
// このクラスを派生させて用いる。
// Learning from a game record, when making yourself think and generating a fixed track, etc.
// Helper class used when multiple threads want to call Search::think() individually.
// Derive and use this class.
struct MultiThink
{
MultiThink() : prng(21120903)
@@ -21,43 +21,43 @@ struct MultiThink
loop_count = 0;
}
// マスタースレッドからこの関数を呼び出すと、スレッドがそれぞれ思考して、
// 思考終了条件を満たしたところで制御を返す。
// 他にやってくれること。
// ・各スレッドがLearner::search(),qsearch()を呼び出しても安全なように
//  置換表をスレッドごとに分離してくれる。(終了後、元に戻してくれる。)
// ・bookはon the flyモードだとthread safeではないので、このモードを一時的に
//  オフにしてくれる。
// [要件]
// 1) thread_worker()のオーバーライド
// 2) set_loop_max()でループ回数の設定
// 3) 定期的にcallbackされる関数を設定する(必要なら)
// callback_funccallback_interval
// Call this function from the master thread, each thread will think,
// Return control when the thought ending condition is satisfied.
// Do something else.
// ・It is safe for each thread to call Learner::search(),qsearch()
// Separates the substitution table for each thread. (It will be restored after the end.)
// ・Book is not thread safe when in on the fly mode, so temporarily change this mode.
// Turn it off.
// [Requirements]
// 1) Override thread_worker()
// 2) Set the loop count with set_loop_max()
// 3) set a function to be called back periodically (if necessary)
// callback_func and callback_interval
void go_think();
// 派生クラス側で初期化したいものがあればこれをoverrideしておけば、
// go_think()で初期化が終わったタイミングで呼び出される。
// 定跡の読み込みなどはそのタイミングで行うと良い。
// If there is something you want to initialize on the derived class side, override this,
// Called when initialization is completed with go_think().
// It is better to read the fixed trace at that timing.
virtual void init() {}
// go_think()したときにスレッドを生成して呼び出されるthread worker
// これをoverrideして用いる。
// A thread worker that is called by creating a thread when you go_think()
// Override and use this.
virtual void thread_worker(size_t thread_id) = 0;
// go_think()したときにcallback_seconds[秒]ごとにcallbackされる。
// Called back every callback_seconds [seconds] when go_think().
std::function<void()> callback_func;
uint64_t callback_seconds = 600;
// workerが処理する(Search::think()を呼び出す)回数を設定する。
// Set the number of times worker processes (calls Search::think()).
void set_loop_max(uint64_t loop_max_) { loop_max = loop_max_; }
// set_loop_max()で設定した値を取得する。
// Get the value set by set_loop_max().
uint64_t get_loop_max() const { return loop_max; }
// [ASYNC] ループカウンターの値を取り出して、取り出し後にループカウンターを加算する。
// もしループカウンターがloop_maxに達していたらUINT64_MAXを返す。
// 局面を生成する場合などは、局面を生成するタイミングでこの関数を呼び出すようにしないと、
// 生成した局面数と、カウンターの値が一致しなくなってしまうので注意すること。
// [ASYNC] Take the value of the loop counter and add the loop counter after taking it out.
// If the loop counter has reached loop_max, return UINT64_MAX.
// If you want to generate a phase, you must call this function at the time of generating the phase,
// Please note that the number of generated phases and the value of the counter will not match.
uint64_t get_next_loop_count() {
std::unique_lock<std::mutex> lk(loop_mutex);
if (loop_count >= loop_max)
@@ -65,46 +65,46 @@ struct MultiThink
return loop_count++;
}
// [ASYNC] 処理した個数を返す用。呼び出されるごとにインクリメントされたカウンターが返る。
// [ASYNC] For returning the processed number. Each time it is called, it returns a counter that is incremented.
uint64_t get_done_count() {
std::unique_lock<std::mutex> lk(loop_mutex);
return ++done_count;
}
// worker threadがI/Oにアクセスするときのmutex
// Mutex when worker thread accesses I/O
std::mutex io_mutex;
protected:
// 乱数発生器本体
// Random number generator body
AsyncPRNG prng;
private:
// workerが処理する(Search::think()を呼び出す)回数
// number of times worker processes (calls Search::think())
std::atomic<uint64_t> loop_max;
// workerが処理した(Search::think()を呼び出した)回数
// number of times the worker has processed (calls Search::think())
std::atomic<uint64_t> loop_count;
// 処理した回数を返す用。
// To return the number of times it has been processed.
std::atomic<uint64_t> done_count;
// ↑の変数を変更するときのmutex
// Mutex when changing the variables in ↑
std::mutex loop_mutex;
// スレッドの終了フラグ。
// vector<bool>にすると複数スレッドから書き換えようとしたときに正しく反映されないことがある…はず。
// Thread end flag.
// vector<bool> may not be reflected properly when trying to rewrite from multiple threads...
typedef uint8_t Flag;
std::vector<Flag> thread_finished;
};
// idle時間にtaskを処理する仕組み。
// masterは好きなときにpush_task_async()でtaskを渡す。
// slaveは暇なときにon_idle()を実行すると、taskを一つ取り出してqueueがなくなるまで実行を続ける。
// MultiThinkthread workermaster-slave方式で書きたいときに用いると便利。
// Mechanism to process task during idle time.
// master passes the task with push_task_async() whenever you like.
// When slave executes on_idle() in its spare time, it retrieves one task and continues execution until there is no queue.
// Convenient to use when you want to write MultiThink thread worker in master-slave method.
struct TaskDispatcher
{
typedef std::function<void(size_t /* thread_id */)> Task;
// slaveはidle中にこの関数を呼び出す。
// slave calls this function during idle.
void on_idle(size_t thread_id)
{
Task task;
@@ -114,24 +114,24 @@ struct TaskDispatcher
sleep(1);
}
// [ASYNC] taskを一つ積む。
// Stack [ASYNC] task.
void push_task_async(Task task)
{
std::unique_lock<std::mutex> lk(task_mutex);
tasks.push_back(task);
}
// task用の配列の要素をsize分だけ事前に確保する。
// Allocate size array elements for task in advance.
void task_reserve(size_t size)
{
tasks.reserve(size);
}
protected:
// taskの集合
// set of tasks
std::vector<Task> tasks;
// [ASYNC] taskを一つ取り出す。on_idle()から呼び出される。
// Take out one [ASYNC] task. Called from on_idle().
Task get_task_async()
{
std::unique_lock<std::mutex> lk(task_mutex);
@@ -142,10 +142,10 @@ protected:
return task;
}
// tasksにアクセスするとき用のmutex
// a mutex for accessing tasks
std::mutex task_mutex;
};
#endif // defined(EVAL_LEARN) && defined(YANEURAOU_2018_OTAFUKU_ENGINE)
#endif
#endif