Skip to content

Commit

Permalink
Merge pull request #2 from LeelaChessZero/master
Browse files Browse the repository at this point in the history
Update from master
  • Loading branch information
Naphthalin authored Sep 23, 2019
2 parents 59f10c3 + 90124a1 commit 8fad165
Show file tree
Hide file tree
Showing 13 changed files with 154 additions and 55 deletions.
14 changes: 7 additions & 7 deletions appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,19 @@ image:
- Visual Studio 2017
environment:
matrix:
- NAME: cuda
- NAME: opencl
- NAME: blas
- NAME: gpu-nvidia-cuda
- NAME: gpu-opencl
- NAME: cpu-openblas
clone_folder: c:\projects\lc0
install:
- cmd: set CUDA=false
- cmd: set OPENCL=false
- cmd: set BLAS=false
- cmd: set GTEST=false
- cmd: IF %NAME%==cuda set CUDA=true
- cmd: IF %NAME%==opencl set OPENCL=true
- cmd: IF %NAME%==blas set BLAS=true
- cmd: IF %NAME%==blas set GTEST=true
- cmd: IF %NAME%==gpu-nvidia-cuda set CUDA=true
- cmd: IF %NAME%==gpu-opencl set OPENCL=true
- cmd: IF %NAME%==cpu-openblas set BLAS=true
- cmd: IF %NAME%==cpu-openblas set GTEST=true
- cmd: IF %BLAS%==true IF NOT EXIST C:\cache\OpenBLAS appveyor DownloadFile https://sjeng.org/ftp/OpenBLAS-0.3.3-win-oldthread.zip
- cmd: IF %BLAS%==true IF NOT EXIST C:\cache\OpenBLAS 7z x OpenBLAS-0.3.3-win-oldthread.zip -oC:\cache\OpenBLAS
- cmd: IF %OPENCL%==true nuget install opencl-nug -Version 0.777.77 -OutputDirectory C:\cache
Expand Down
4 changes: 2 additions & 2 deletions build-cl.cmd
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ set MSBuild="C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\MSBui
rem call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" amd64
call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" amd64

meson.py build --backend vs2017 --buildtype release ^
rem change to '-Dblas=true' to also build the blas backend with mkl
meson build --backend vs2017 --buildtype release -Dblas=false ^
-Dmkl_include="C:\Program Files (x86)\IntelSWTools\compilers_and_libraries\windows\mkl\include" ^
-Dmkl_libdirs="C:\Program Files (x86)\IntelSWTools\compilers_and_libraries\windows\mkl\lib\intel64" ^
-Dopencl_libdirs="C:\Program Files (x86)\AMD APP SDK\3.0\lib\x86_64" ^
Expand All @@ -28,4 +29,3 @@ cd build
%MSBuild% /p:Configuration=Release /p:Platform=x64 ^
/p:PreferredToolArchitecture=x64 lc0@exe.vcxproj ^
/filelogger

49 changes: 39 additions & 10 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -66,20 +66,48 @@ endif
gen = generator(protoc, output: ['@[email protected]', '@[email protected]'],
arguments : ['--proto_path=@CURRENT_SOURCE_DIR@/libs/lczero-common', '--cpp_out=@BUILD_DIR@', '@INPUT@'])

# Handle submodules.
git = find_program('git', required: false)
if run_command('checkdir.py', 'libs/lczero-common/proto').returncode() != 0
if run_command('git', 'status').returncode() == 0
message('updating git submodule libs/lczero-common')
run_command('git', 'submodule', 'update', '--init', '--recursive')
if git.found()
if run_command(git, 'status').returncode() == 0
message('updating git submodule libs/lczero-common')
run_command(git, 'submodule', 'update', '--init', '--recursive')
else
message('cloning lczero-common.git into libs/lczero-common')
run_command(git, 'clone', '--depth=1',
'https://github.com/LeelaChessZero/lczero-common.git',
'libs/lczero-common/')
endif
else
message('cloning lczero-common.git into libs/lczero-common')
run_command('git', 'clone', '--depth=1',
'https://github.com/LeelaChessZero/lczero-common.git',
'libs/lczero-common/')
error('Please install git to automatically fetch submodules or download the archives manually from GitHub.')
endif
endif

files += gen.process('libs/lczero-common/proto/net.proto',
preserve_path_from : meson.current_source_dir() + '/libs/lczero-common/')

# Extract git short revision.
short_rev = 'unknown'
if git.found()
r = run_command(git, 'rev-parse', '--short', 'HEAD')
if r.returncode() == 0
# Now let's check if the working directory is clean.
if run_command(git, 'diff-index', '--quiet', 'HEAD').returncode() == 0
short_rev = r.stdout().strip()
else
short_rev = 'dirty'
warning('Cannot extract valid git short revision from dirty working directory.')
endif
else
warning('Failed to parse short revision. Use git clone instead of downloading the archive from GitHub.')
endif
endif

# Construct build identifier.
build_identifier = 'git.' + short_rev
add_project_arguments('-DBUILD_IDENTIFIER="' + build_identifier + '"', language : 'cpp')
message('Using build identifier "' + build_identifier + '".')

#############################################################################
## Main files
Expand Down Expand Up @@ -207,7 +235,6 @@ if get_option('build_backends')
has_blas = true

elif get_option('accelerate') and accelerate_lib.found()
includes += include_directories('/System/Library/Frameworks/Accelerate.framework/Frameworks/vecLib.framework/Headers')
deps += [ accelerate_lib ]
has_blas = true

Expand Down Expand Up @@ -311,7 +338,7 @@ if get_option('build_backends')
deps += [ opencl_framework ]
has_opencl = true

elif opencl_lib.found()
elif opencl_lib.found() and cc.has_header('CL/opencl.h', args: '-I' + get_option('opencl_include'))

deps += [ opencl_lib ]
has_opencl = true
Expand All @@ -332,7 +359,9 @@ if get_option('build_backends')
'src/neural/shared/winograd_filter.cc',
]

includes += include_directories(get_option('opencl_include'))
if not opencl_framework.found()
includes += include_directories(get_option('opencl_include'))
endif
files += opencl_files
has_backends = true

Expand Down
6 changes: 3 additions & 3 deletions meson_options.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ option('openblas_include',
description: 'Paths to openblas include directories')

option('opencl_include',
type: 'array',
value: ['/usr/include/'],
description: 'Paths to OpenCL include directories')
type: 'string',
value: '/usr/include/',
description: 'Path to OpenCL include directory')

option('tensorflow_libdir',
type: 'array',
Expand Down
20 changes: 16 additions & 4 deletions src/chess/board.cc
Original file line number Diff line number Diff line change
Expand Up @@ -982,16 +982,28 @@ void ChessBoard::SetFromFen(const std::string& fen, int* no_capture_ply,
for (char c : castlings) {
switch (c) {
case 'K':
castlings_.set_we_can_00();
if (our_king_.as_string() == "e1" && our_pieces_.get(0, 7) &&
rooks_.get(0, 7)) {
castlings_.set_we_can_00();
}
break;
case 'k':
castlings_.set_they_can_00();
if (their_king_.as_string() == "e8" && their_pieces_.get(7, 7) &&
rooks_.get(7, 7)) {
castlings_.set_they_can_00();
}
break;
case 'Q':
castlings_.set_we_can_000();
if (our_king_.as_string() == "e1" && our_pieces_.get(0, 0) &&
rooks_.get(0, 0)) {
castlings_.set_we_can_000();
}
break;
case 'q':
castlings_.set_they_can_000();
if (their_king_.as_string() == "e8" && their_pieces_.get(7, 0) &&
rooks_.get(7, 0)) {
castlings_.set_they_can_000();
}
break;
default:
throw Exception("Bad fen string: " + fen);
Expand Down
15 changes: 10 additions & 5 deletions src/mcts/node.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include "chess/position.h"
#include "neural/encoder.h"
#include "neural/writer.h"
#include "utils/fastmath.h"
#include "utils/mutex.h"

namespace lczero {
Expand Down Expand Up @@ -336,8 +337,12 @@ class EdgeAndNode {
Node* node() const { return node_; }

// Proxy functions for easier access to node/edge.
float GetQ(float default_q) const {
return (node_ && node_->GetN() > 0) ? node_->GetQ() : default_q;
float GetQ(float default_q, bool logit_q = false) const {
return (node_ && node_->GetN() > 0)
?
// Scale Q slightly to avoid logit(1) = infinity.
(logit_q ? FastLogit(0.9999999f * node_->GetQ()) : node_->GetQ())
: default_q;
}
float GetD() const {
return (node_ && node_->GetN() > 0) ? node_->GetD() : 0.0f;
Expand All @@ -362,9 +367,9 @@ class EdgeAndNode {
return numerator * GetP() / (1 + GetNStarted());
}

int GetVisitsToReachU(float target_score, float numerator,
float default_q) const {
const auto q = GetQ(default_q);
int GetVisitsToReachU(float target_score, float numerator, float default_q,
bool logit_q) const {
const auto q = GetQ(default_q, logit_q);
if (q >= target_score) return std::numeric_limits<int>::max();
const auto n1 = GetNStarted() + 1;
return std::max(
Expand Down
24 changes: 23 additions & 1 deletion src/mcts/params.cc
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ const OptionId SearchParams::kMaxPrefetchBatchId{
"When the engine cannot gather a large enough batch for immediate use, try "
"to prefetch up to X positions which are likely to be useful soon, and put "
"them into cache."};
const OptionId SearchParams::kLogitQId{
"logit-q", "LogitQ",
"Apply logit to Q when determining Q+U best child. This makes the U term "
"less dominant when Q is near -1 or +1."};
const OptionId SearchParams::kCpuctId{
"cpuct", "CPuct",
"cpuct_init constant from \"UCT search\" algorithm. Higher values promote "
Expand Down Expand Up @@ -93,6 +97,15 @@ const OptionId SearchParams::kNoiseId{
"engine to discover new ideas during training by exploring moves which are "
"known to be bad. Not normally used during play.",
'n'};
const OptionId SearchParams::kNoiseEpsilonId{
"noise-epsilon", "DirichletNoiseEpsilon",
"Amount of Dirichlet noise to combine with root priors. This allows the "
"engine to discover new ideas during training by exploring moves which are "
"known to be bad. Not normally used during play."};
const OptionId SearchParams::kNoiseAlphaId{
"noise-alpha", "DirichletNoiseAlpha",
"Alpha of Dirichlet noise to control the sharpness of move probabilities. "
"Larger values result in flatter / more evenly distributed values."};
const OptionId SearchParams::kVerboseStatsId{
"verbose-move-stats", "VerboseMoveStats",
"Display Q, V, N, U and P values of every move candidate after each move."};
Expand Down Expand Up @@ -192,6 +205,7 @@ void SearchParams::Populate(OptionsParser* options) {
// Many of them are overridden with training specific values in tournament.cc.
options->Add<IntOption>(kMiniBatchSizeId, 1, 1024) = 256;
options->Add<IntOption>(kMaxPrefetchBatchId, 0, 1024) = 32;
options->Add<BoolOption>(kLogitQId) = false;
options->Add<FloatOption>(kCpuctId, 0.0f, 100.0f) = 3.0f;
options->Add<FloatOption>(kCpuctBaseId, 1.0f, 1000000000.0f) = 19652.0f;
options->Add<FloatOption>(kCpuctFactorId, 0.0f, 1000.0f) = 2.0f;
Expand All @@ -203,6 +217,8 @@ void SearchParams::Populate(OptionsParser* options) {
options->Add<FloatOption>(kTemperatureVisitOffsetId, -1000.0f, 1000.0f) =
0.0f;
options->Add<BoolOption>(kNoiseId) = false;
options->Add<FloatOption>(kNoiseEpsilonId, 0.0f, 1.0f) = 0.0f;
options->Add<FloatOption>(kNoiseAlphaId, 0.0f, 10000000.0f) = 0.3f;
options->Add<BoolOption>(kVerboseStatsId) = false;
options->Add<BoolOption>(kLogLiveStatsId) = false;
options->Add<FloatOption>(kSmartPruningFactorId, 0.0f, 10.0f) = 1.33f;
Expand All @@ -228,15 +244,21 @@ void SearchParams::Populate(OptionsParser* options) {
options->Add<IntOption>(kKLDGainAverageInterval, 1, 10000000) = 100;
options->Add<FloatOption>(kMinimumKLDGainPerNode, 0.0f, 1.0f) = 0.0f;

options->HideOption(kNoiseEpsilonId);
options->HideOption(kNoiseAlphaId);
options->HideOption(kLogLiveStatsId);
}

SearchParams::SearchParams(const OptionsDict& options)
: options_(options),
kLogitQ(options.Get<bool>(kLogitQId.GetId())),
kCpuct(options.Get<float>(kCpuctId.GetId())),
kCpuctBase(options.Get<float>(kCpuctBaseId.GetId())),
kCpuctFactor(options.Get<float>(kCpuctFactorId.GetId())),
kNoise(options.Get<bool>(kNoiseId.GetId())),
kNoiseEpsilon(options.Get<bool>(kNoiseId.GetId())
? 0.25f
: options.Get<float>(kNoiseEpsilonId.GetId())),
kNoiseAlpha(options.Get<float>(kNoiseAlphaId.GetId())),
kSmartPruningFactor(options.Get<float>(kSmartPruningFactorId.GetId())),
kFpuAbsolute(options.Get<std::string>(kFpuStrategyId.GetId()) ==
"absolute"),
Expand Down
11 changes: 9 additions & 2 deletions src/mcts/params.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ class SearchParams {
int GetMaxPrefetchBatch() const {
return options_.Get<int>(kMaxPrefetchBatchId.GetId());
}
bool GetLogitQ() const { return kLogitQ; }
float GetCpuct() const { return kCpuct; }
float GetCpuctBase() const { return kCpuctBase; }
float GetCpuctFactor() const { return kCpuctFactor; }
Expand All @@ -70,7 +71,8 @@ class SearchParams {
return options_.Get<float>(kTemperatureWinpctCutoffId.GetId());
}

bool GetNoise() const { return kNoise; }
float GetNoiseEpsilon() const { return kNoiseEpsilon; }
float GetNoiseAlpha() const { return kNoiseAlpha; }
bool GetVerboseStats() const {
return options_.Get<bool>(kVerboseStatsId.GetId());
}
Expand Down Expand Up @@ -102,6 +104,7 @@ class SearchParams {
// Search parameter IDs.
static const OptionId kMiniBatchSizeId;
static const OptionId kMaxPrefetchBatchId;
static const OptionId kLogitQId;
static const OptionId kCpuctId;
static const OptionId kCpuctBaseId;
static const OptionId kCpuctFactorId;
Expand All @@ -112,6 +115,8 @@ class SearchParams {
static const OptionId kTemperatureWinpctCutoffId;
static const OptionId kTemperatureVisitOffsetId;
static const OptionId kNoiseId;
static const OptionId kNoiseEpsilonId;
static const OptionId kNoiseAlphaId;
static const OptionId kVerboseStatsId;
static const OptionId kLogLiveStatsId;
static const OptionId kSmartPruningFactorId;
Expand Down Expand Up @@ -140,10 +145,12 @@ class SearchParams {
// 2. Parameter has to stay the say during the search.
// TODO(crem) Some of those parameters can be converted to be dynamic after
// trivial search optimiations.
const bool kLogitQ;
const float kCpuct;
const float kCpuctBase;
const float kCpuctFactor;
const bool kNoise;
const float kNoiseEpsilon;
const float kNoiseAlpha;
const float kSmartPruningFactor;
const bool kFpuAbsolute;
const float kFpuValue;
Expand Down
27 changes: 17 additions & 10 deletions src/mcts/search.cc
Original file line number Diff line number Diff line change
Expand Up @@ -212,16 +212,19 @@ std::vector<std::string> Search::GetVerboseStats(Node* node,
const float fpu = GetFpu(params_, node, node == root_node_);
const float cpuct = ComputeCpuct(params_, node->GetN());
const float U_coeff =
cpuct * std::sqrt(std::max(node->GetChildrenVisits(), 1u));
cpuct * std::sqrt(std::max(node->GetChildrenVisits(), 1u));
const bool logit_q = params_.GetLogitQ();

std::vector<EdgeAndNode> edges;
for (const auto& edge : node->Edges()) edges.push_back(edge);

std::sort(
edges.begin(), edges.end(),
[&fpu, &U_coeff](EdgeAndNode a, EdgeAndNode b) {
return std::forward_as_tuple(a.GetN(), a.GetQ(fpu) + a.GetU(U_coeff)) <
std::forward_as_tuple(b.GetN(), b.GetQ(fpu) + b.GetU(U_coeff));
[&fpu, &U_coeff, &logit_q](EdgeAndNode a, EdgeAndNode b) {
return std::forward_as_tuple(
a.GetN(), a.GetQ(fpu, logit_q) + a.GetU(U_coeff)) <
std::forward_as_tuple(
b.GetN(), b.GetQ(fpu, logit_q) + b.GetU(U_coeff));
});

std::vector<std::string> infos;
Expand Down Expand Up @@ -250,7 +253,8 @@ std::vector<std::string> Search::GetVerboseStats(Node* node,
<< ") ";

oss << "(Q+U: " << std::setw(8) << std::setprecision(5)
<< edge.GetQ(fpu) + edge.GetU(U_coeff) << ") ";
<< edge.GetQ(fpu, logit_q) + edge.GetU(U_coeff)
<< ") ";

oss << "(V: ";
optional<float> v;
Expand Down Expand Up @@ -955,7 +959,7 @@ SearchWorker::NodeToProcess SearchWorker::PickNodeToExtend(
}
++possible_moves;
}
const float Q = child.GetQ(fpu);
const float Q = child.GetQ(fpu, params_.GetLogitQ());
const float score = child.GetU(puct_mult) + Q;
if (score > best) {
second_best = best;
Expand All @@ -970,7 +974,8 @@ SearchWorker::NodeToProcess SearchWorker::PickNodeToExtend(

if (second_best_edge) {
int estimated_visits_to_change_best =
best_edge.GetVisitsToReachU(second_best, puct_mult, fpu);
best_edge.GetVisitsToReachU(second_best, puct_mult, fpu,
params_.GetLogitQ());
// Only cache for n-2 steps as the estimate created by GetVisitsToReachU
// has potential rounding errors and some conservative logic that can push
// it up to 2 away from the real value.
Expand All @@ -982,7 +987,8 @@ SearchWorker::NodeToProcess SearchWorker::PickNodeToExtend(
second_best_edge.Reset();
}

if (is_root_node && possible_moves <= 1 && !search_->limits_.infinite) {
if (is_root_node && possible_moves <= 1 && !search_->limits_.infinite &&
params_.GetSmartPruningFactor()) {
// If there is only one move theoretically possible within remaining time,
// output it.
Mutex::Lock counters_lock(search_->counters_mutex_);
Expand Down Expand Up @@ -1262,8 +1268,9 @@ void SearchWorker::FetchSingleNodeResult(NodeToProcess* node_to_process,
for (auto edge : node->Edges()) edge.edge()->SetP(edge.GetP() * scale);
}
// Add Dirichlet noise if enabled and at root.
if (params_.GetNoise() && node == search_->root_node_) {
ApplyDirichletNoise(node, 0.25, 0.3);
if (params_.GetNoiseEpsilon() && node == search_->root_node_) {
ApplyDirichletNoise(node, params_.GetNoiseEpsilon(),
params_.GetNoiseAlpha());
}
}

Expand Down
Loading

0 comments on commit 8fad165

Please sign in to comment.