mirror of
https://github.com/official-stockfish/Stockfish.git
synced 2026-07-26 14:47:16 +00:00
Merge branch 'master' into trainer
This commit is contained in:
@@ -25,19 +25,7 @@
|
||||
#include <chrono>
|
||||
#include <random>
|
||||
#include <regex>
|
||||
|
||||
#if defined (_OPENMP)
|
||||
#include <omp.h>
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
// 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 <filesystem>
|
||||
#elif defined(__GNUC__)
|
||||
#include <dirent.h>
|
||||
#endif
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
+20
-59
@@ -1,46 +1,32 @@
|
||||
#if defined(EVAL_LEARN)
|
||||
|
||||
#include "../eval/evaluate_common.h"
|
||||
|
||||
#include "learn.h"
|
||||
#include "multi_think.h"
|
||||
#include "../misc.h"
|
||||
#include "../thread.h"
|
||||
#include "../nnue/evaluate_nnue_learner.h"
|
||||
#include "../position.h"
|
||||
#include "../syzygy/tbprobe.h"
|
||||
#include "../thread.h"
|
||||
#include "../tt.h"
|
||||
#include "../uci.h"
|
||||
#include "../syzygy/tbprobe.h"
|
||||
#include "learn.h"
|
||||
#include "multi_think.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <random>
|
||||
#include <regex>
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
#include <unordered_set>
|
||||
#include <iomanip>
|
||||
#include <list>
|
||||
#include <climits>
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <limits>
|
||||
#include <optional>
|
||||
|
||||
#if defined (_OPENMP)
|
||||
#include <omp.h>
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
// std::filesystem doesn't work on GCC even though it claims to support C++17.
|
||||
#include <filesystem>
|
||||
#elif defined(__GNUC__)
|
||||
#include <dirent.h>
|
||||
#endif
|
||||
|
||||
#if defined(EVAL_LEARN)
|
||||
#include "../nnue/evaluate_nnue_learner.h"
|
||||
#include <climits>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <limits>
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <random>
|
||||
#include <regex>
|
||||
#include <shared_mutex>
|
||||
#endif
|
||||
#include <sstream>
|
||||
#include <unordered_set>
|
||||
|
||||
using namespace std;
|
||||
|
||||
@@ -80,7 +66,7 @@ namespace Learner
|
||||
file_worker_thread.join();
|
||||
output_file_stream.close();
|
||||
|
||||
#if !defined(DNDEBUG)
|
||||
#if defined(_DEBUG)
|
||||
{
|
||||
// All buffers should be empty since file_worker_thread
|
||||
// should have written everything before exiting.
|
||||
@@ -176,7 +162,7 @@ namespace Learner
|
||||
output_file_stream.write(reinterpret_cast<const char*>(buf->data()), sizeof(PackedSfenValue) * buf->size());
|
||||
|
||||
sfen_write_count += buf->size();
|
||||
#if 1
|
||||
|
||||
// Add the processed number here, and if it exceeds save_every,
|
||||
// change the file name and reset this counter.
|
||||
sfen_write_count_current_file += buf->size();
|
||||
@@ -196,7 +182,7 @@ namespace Learner
|
||||
output_file_stream.open(new_filename, ios::out | ios::binary | ios::app);
|
||||
cout << endl << "output sfen file = " << new_filename << endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Output '.' every time when writing a game record.
|
||||
std::cout << ".";
|
||||
|
||||
@@ -522,10 +508,6 @@ namespace Learner
|
||||
{
|
||||
// Write out one sfen.
|
||||
sfen_writer.write(thread_id, *it);
|
||||
#if 0
|
||||
pos.set_from_packed_sfen(it->sfen);
|
||||
cout << pos << "Win : " << it->is_win << " , " << it->score << endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
return quit;
|
||||
@@ -717,6 +699,7 @@ namespace Learner
|
||||
flush_psv(result.value());
|
||||
break;
|
||||
}
|
||||
|
||||
{
|
||||
auto [search_value, search_pv] = search(pos, depth, 1, nodes);
|
||||
|
||||
@@ -744,19 +727,6 @@ namespace Learner
|
||||
// Save the move score for adjudication.
|
||||
move_hist_scores.push_back(search_value);
|
||||
|
||||
#if 0
|
||||
dbg_hit_on(search_value == leaf_value);
|
||||
// gensfen depth 3 eval_limit 32000
|
||||
// Total 217749 Hits 203579 hit rate (%) 93.490
|
||||
// gensfen depth 6 eval_limit 32000
|
||||
// Total 78407 Hits 69190 hit rate (%) 88.245
|
||||
// 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
|
||||
|
||||
// If depth 0, pv is not obtained, so search again at depth 2.
|
||||
if (search_depth_min <= 0)
|
||||
{
|
||||
@@ -892,12 +862,6 @@ namespace Learner
|
||||
|
||||
string token;
|
||||
|
||||
// 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;
|
||||
|
||||
// Save to file in this unit.
|
||||
// File names are serialized like file_1.bin, file_2.bin.
|
||||
uint64_t save_every = UINT64_MAX;
|
||||
@@ -946,8 +910,6 @@ namespace Learner
|
||||
is >> write_minply;
|
||||
else if (token == "write_maxply")
|
||||
is >> write_maxply;
|
||||
else if (token == "use_eval_hash")
|
||||
is >> use_eval_hash;
|
||||
else if (token == "save_every")
|
||||
is >> save_every;
|
||||
else if (token == "random_file_name")
|
||||
@@ -1017,7 +979,6 @@ namespace Learner
|
||||
<< " write_minply = " << write_minply << endl
|
||||
<< " write_maxply = " << write_maxply << endl
|
||||
<< " output_file_name = " << output_file_name << endl
|
||||
<< " use_eval_hash = " << use_eval_hash << endl
|
||||
<< " save_every = " << save_every << endl
|
||||
<< " random_file_name = " << random_file_name << endl
|
||||
<< " write_out_draw_game_in_training_data_generation = " << write_out_draw_game_in_training_data_generation << endl
|
||||
|
||||
+28
-99
@@ -5,84 +5,6 @@
|
||||
|
||||
#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.
|
||||
|
||||
// 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
|
||||
// ----------------------
|
||||
|
||||
// Ada Grad. Recommended because it is stable.
|
||||
// #define ADA_GRAD_UPDATE
|
||||
|
||||
// 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 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)
|
||||
|
||||
// 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)
|
||||
|
||||
// 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
|
||||
// ----------------------
|
||||
|
||||
// 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
|
||||
|
||||
// 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) method
|
||||
// #define LOSS_FUNCTION_IS_ELMO_METHOD
|
||||
|
||||
// ※ Other things may be added.
|
||||
|
||||
|
||||
// ----------------------
|
||||
// debug settings for learning
|
||||
// ----------------------
|
||||
|
||||
// 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
|
||||
|
||||
// ----------------------
|
||||
// Floating point for learning
|
||||
// ----------------------
|
||||
@@ -109,28 +31,7 @@ typedef float LearnFloatType;
|
||||
// Learning with the method of elmo (WCSC27)
|
||||
// ----------------------
|
||||
|
||||
#if defined( LEARN_ELMO_METHOD )
|
||||
#define LOSS_FUNCTION_IS_ELMO_METHOD
|
||||
#define ADA_GRAD_UPDATE
|
||||
#endif
|
||||
|
||||
// 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)
|
||||
#define LEARN_UPDATE "SGD"
|
||||
#endif
|
||||
|
||||
#if defined(LOSS_FUNCTION_IS_WINNING_PERCENTAGE)
|
||||
#define LOSS_FUNCTION "WINNING_PERCENTAGE"
|
||||
#elif defined(LOSS_FUNCTION_IS_CROSS_ENTOROPY)
|
||||
#define LOSS_FUNCTION "CROSS_ENTOROPY"
|
||||
#elif defined(LOSS_FUNCTION_IS_CROSS_ENTOROPY_FOR_VALUE)
|
||||
#define LOSS_FUNCTION "CROSS_ENTOROPY_FOR_VALUE"
|
||||
#elif defined(LOSS_FUNCTION_IS_ELMO_METHOD)
|
||||
#define LOSS_FUNCTION "ELMO_METHOD(WCSC27)"
|
||||
#endif
|
||||
|
||||
// ----------------------
|
||||
// Definition of struct used in Learner
|
||||
@@ -139,6 +40,34 @@ typedef float LearnFloatType;
|
||||
|
||||
namespace Learner
|
||||
{
|
||||
// ----------------------
|
||||
// Settings for learning
|
||||
// ----------------------
|
||||
|
||||
// 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.
|
||||
|
||||
constexpr std::size_t LEARN_MINI_BATCH_SIZE = 1000 * 1000 * 1;
|
||||
|
||||
// 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).
|
||||
|
||||
constexpr std::size_t LEARN_SFEN_READ_SIZE = 1000 * 1000 * 10;
|
||||
|
||||
// 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.
|
||||
constexpr std::size_t LEARN_EVAL_SAVE_INTERVAL = 1000000000ULL;
|
||||
|
||||
// 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.
|
||||
constexpr std::size_t LEARN_RMSE_OUTPUT_INTERVAL = 1;
|
||||
|
||||
//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.
|
||||
|
||||
+432
-477
File diff suppressed because it is too large
Load Diff
@@ -2,9 +2,6 @@
|
||||
|
||||
#if defined (EVAL_LEARN)
|
||||
|
||||
#if defined(_OPENMP)
|
||||
#include <omp.h>
|
||||
#endif
|
||||
#include "../misc.h"
|
||||
|
||||
using namespace Eval;
|
||||
|
||||
@@ -4,7 +4,11 @@
|
||||
// A set of machine learning tools related to the weight array used for machine learning of evaluation functions
|
||||
|
||||
#include "learn.h"
|
||||
|
||||
#if defined (EVAL_LEARN)
|
||||
|
||||
#include "../misc.h" // PRNG , my_insertion_sort
|
||||
|
||||
#include <array>
|
||||
#include <cmath> // std::sqrt()
|
||||
|
||||
@@ -24,14 +28,6 @@ namespace EvalLearningTools
|
||||
// cumulative value of one mini-batch gradient
|
||||
LearnFloatType g = LearnFloatType(0);
|
||||
|
||||
// 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).
|
||||
|
||||
// For SGD_UPDATE, this structure is reduced by 10 bytes to 8 bytes.
|
||||
|
||||
// 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.
|
||||
@@ -71,96 +67,6 @@ namespace EvalLearningTools
|
||||
|
||||
template <typename T> void updateFV(T& v) { updateFV(v, 1.0); }
|
||||
|
||||
#if defined (ADA_GRAD_UPDATE)
|
||||
|
||||
// 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);
|
||||
|
||||
// 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
|
||||
LearnFloatType g2 = LearnFloatType(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 <typename T>
|
||||
void updateFV(T& v,double k)
|
||||
{
|
||||
// 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)
|
||||
|
||||
constexpr double epsilon = 0.000001;
|
||||
|
||||
if (g == LearnFloatType(0))
|
||||
return;
|
||||
|
||||
g2 += g * g;
|
||||
|
||||
// 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);
|
||||
|
||||
// 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<T>::max)() , V);
|
||||
V = (std::max)((double)(std::numeric_limits<T>::min)() , V);
|
||||
|
||||
v0 = (LearnFloatType)V;
|
||||
v = (T)round(V);
|
||||
|
||||
// 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)
|
||||
|
||||
// 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 <typename T>
|
||||
void updateFV(T & v , double k)
|
||||
{
|
||||
if (g == 0)
|
||||
return;
|
||||
|
||||
// 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.
|
||||
|
||||
// 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));
|
||||
// → 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;
|
||||
if (g > 0.0)
|
||||
V-= diff;
|
||||
else
|
||||
V+= diff;
|
||||
|
||||
V = (std::min)((double)(std::numeric_limits<T>::max)(), V);
|
||||
V = (std::max)((double)(std::numeric_limits<T>::min)(), V);
|
||||
|
||||
v = (T)V;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// grad setting
|
||||
template <typename T> void set_grad(const T& g_) { g = g_; }
|
||||
|
||||
|
||||
Reference in New Issue
Block a user