Skip to content

Commit

Permalink
Merge branch 'master' into release/0.26
Browse files Browse the repository at this point in the history
  • Loading branch information
borg323 committed Aug 28, 2020
2 parents 2520eb3 + 2f14654 commit 0442a72
Show file tree
Hide file tree
Showing 18 changed files with 193 additions and 44 deletions.
2 changes: 1 addition & 1 deletion .circleci/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ FROM floopcz/tensorflow_cc:ubuntu-shared-cuda
ARG DEBIAN_FRONTEND=noninteractive

RUN wget https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS-2019.PUB && apt-key add GPG-PUB-KEY-INTEL-SW-PRODUCTS-2019.PUB && sh -c 'echo deb https://apt.repos.intel.com/mkl all main > /etc/apt/sources.list.d/intel-mkl.list' && apt-get update && apt-get install -y intel-mkl-64bit-2018.2-046
RUN apt-get install -y clang ninja-build python3-pip nvidia-opencl-dev libopenblas-dev libboost-dev libgtest-dev git ssh tar gzip ca-certificates sudo
RUN apt-get install -y clang ninja-build python3-pip nvidia-opencl-dev libopenblas-dev libboost-dev libgtest-dev git ssh tar gzip ca-certificates libeigen3-dev sudo
RUN apt-get install -y g++-8
RUN apt-get install -y cuda
RUN pip3 install meson
Expand Down
2 changes: 1 addition & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ version: 2
jobs:
build:
docker:
- image: danieluranga/leela_chess_zero-lc0_ubuntu_builder:0.0.7
- image: danieluranga/leela_chess_zero-lc0_ubuntu_builder:0.0.8
steps:
- checkout
- run:
Expand Down
10 changes: 6 additions & 4 deletions appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ install:
- cmd: set BLAS=false
- cmd: set GTEST=false
- cmd: set ANDROID=false
- cmd: set NET=703350
- cmd: set NET_HASH=feb6dcb84697b55c3573f503dc9fca2783478ef5f3021669ad854129aaab0683
- cmd: set NET=703810
- cmd: set NET_HASH=b30e742bcfd905815e0e7dbd4e1bafb41ade748f85d006b8e28758f1a3107ae3
- cmd: IF %NAME%==android set ANDROID=true
- cmd: IF %NAME%==gpu-nvidia-cuda set CUDA=true
- cmd: IF %NAME%==gpu-dx12 set DX=true
Expand All @@ -53,7 +53,7 @@ install:
- cmd: IF %CUDA%==true IF NOT EXIST C:\cache\cuda appveyor DownloadFile http://developer.download.nvidia.com/compute/redist/cudnn/v7.4.2/cudnn-10.0-windows10-x64-v7.4.2.24.zip
- cmd: IF %CUDA%==true IF NOT EXIST C:\cache\cuda 7z x cudnn-10.0-windows10-x64-v7.4.2.24.zip -oC:\cache
- cmd: set PATH=C:\Python36;C:\Python36\scripts;%PATH%
- cmd: pip3 install --upgrade meson==0.54.3
- cmd: pip3 install --upgrade meson
- cmd: call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" amd64
- cmd: IF %NAME%==android IF NOT EXIST C:\ndk\android-ndk-r19c\toolchains\llvm\prebuilt\windows-x86_64 appveyor DownloadFile https://dl.google.com/android/repository/android-ndk-r19c-windows-x86_64.zip
- cmd: IF %NAME%==android IF NOT EXIST C:\ndk\android-ndk-r19c\toolchains\llvm\prebuilt\windows-x86_64 7z x android-ndk-r19c-windows-x86_64.zip -oC:\ndk
Expand Down Expand Up @@ -88,7 +88,9 @@ before_build:
- cmd: IF %DX%==true SET BUILD_BLAS=true
- cmd: SET EMBED=false
- cmd: IF %APPVEYOR_REPO_TAG%==true IF %ANDROID%==true SET EMBED=true
- cmd: IF %ANDROID%==false meson build --backend vs2017 --buildtype release -Dgtest=%GTEST% -Dopencl=%OPENCL% -Dblas=%BUILD_BLAS% -Ddnnl=true -Ddx=%DX% -Dcudnn=%CUDA% -Dispc_native_only=false -Dpopcnt=false -Dcudnn_include="%CUDA_PATH%\include","%PKG_FOLDER%\cuda\include" -Dcudnn_libdirs="%CUDA_PATH%\lib\x64","%PKG_FOLDER%\cuda\lib\x64" -Dopenblas_include="%PKG_FOLDER%\OpenBLAS\dist64\include" -Dopenblas_libdirs="%PKG_FOLDER%\OpenBLAS\dist64\lib" -Ddnnl_dir="%PKG_FOLDER%\dnnl_win_1.5.0_cpu_vcomp" -Dopencl_include="%PKG_FOLDER%\opencl-nug.0.777.77\build\native\include" -Dopencl_libdirs="%PKG_FOLDER%\opencl-nug.0.777.77\build\native\lib\x64" -Ddefault_library=static
- cmd: SET EXTRA=
- cmd: IF %NAME%==cpu-dnnl SET EXTRA=-Db_vscrt=md
- cmd: IF %ANDROID%==false meson build --backend vs2017 --buildtype release -Dgtest=%GTEST% -Dopencl=%OPENCL% -Dblas=%BUILD_BLAS% -Ddnnl=true -Ddx=%DX% -Dcudnn=%CUDA% -Dispc_native_only=false -Dpopcnt=false -Dcudnn_include="%CUDA_PATH%\include","%PKG_FOLDER%\cuda\include" -Dcudnn_libdirs="%CUDA_PATH%\lib\x64","%PKG_FOLDER%\cuda\lib\x64" -Dopenblas_include="%PKG_FOLDER%\OpenBLAS\dist64\include" -Dopenblas_libdirs="%PKG_FOLDER%\OpenBLAS\dist64\lib" -Ddnnl_dir="%PKG_FOLDER%\dnnl_win_1.5.0_cpu_vcomp" -Dopencl_include="%PKG_FOLDER%\opencl-nug.0.777.77\build\native\include" -Dopencl_libdirs="%PKG_FOLDER%\opencl-nug.0.777.77\build\native\lib\x64" -Ddefault_library=static %EXTRA%
- cmd: IF %ANDROID%==true meson arm64-v8a --buildtype release -Dgtest=false -Dopenblas_include="%PKG_FOLDER%\OpenBLAS\android-aarch64\include" -Dopenblas_libdirs="%PKG_FOLDER%\OpenBLAS\android-aarch64\lib" -Dembed=%EMBED% -Ddefault_library=static --cross-file crossfile-aarch64
- cmd: IF %ANDROID%==true meson armeabi-v7a --buildtype release -Dgtest=false -Dopenblas_include="%PKG_FOLDER%\OpenBLAS\android-armv7a\include" -Dopenblas_libdirs="%PKG_FOLDER%\OpenBLAS\android-armv7a\lib" -Dembed=%EMBED% -Ddefault_library=static --cross-file crossfile-armv7a -Dispc=false
build_script:
Expand Down
15 changes: 9 additions & 6 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
# along with Leela Chess. If not, see <http://www.gnu.org/licenses/>.

project('lc0', 'cpp',
default_options : ['cpp_std=c++17', 'b_ndebug=if-release', 'warning_level=3', 'b_lto=true'],
default_options : ['cpp_std=c++17', 'b_ndebug=if-release', 'warning_level=3', 'b_lto=true', 'b_vscrt=mt'],
meson_version: '>=0.52')

cc = meson.get_compiler('cpp')
Expand Down Expand Up @@ -418,11 +418,14 @@ if get_option('build_backends')
cuda_arguments = ['@EXTRA_ARGS@', '-c', '@INPUT@', '-o', '@OUTPUT@',
'-I', meson.current_source_dir() + '/src']
if host_machine.system() == 'windows'
# meson bug fixed in v0.51
if meson.version().version_compare('<0.51') or get_option('default_library') != 'static'
cuda_arguments += ['-Xcompiler', '-MD']
else
if get_option('b_vscrt') == 'mt'
cuda_arguments += ['-Xcompiler', '-MT']
elif get_option('b_vscrt') == 'mtd'
cuda_arguments += ['-Xcompiler', '-MTd']
elif get_option('b_vscrt') == 'mdd' or (get_option('b_vscrt') == 'from_buildtype' and get_option('buildtype') == 'debug')
cuda_arguments += ['-Xcompiler', '-MDd']
elif get_option('b_vscrt') != 'none'
cuda_arguments += ['-Xcompiler', '-MD']
endif
else
cuda_arguments += ['--std=c++14', '-Xcompiler', '-fPIC']
Expand Down Expand Up @@ -591,4 +594,4 @@ if get_option('python_bindings')
[py_files + files],
include_directories: [includes],
dependencies: [cpython] + deps)
endif
endif
1 change: 1 addition & 0 deletions src/chess/pgn.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ class PgnReader {
bool in_comment = false;
bool started = false;
while (GzGetLine(file, line)) {
if (!line.empty() && line.back() == '\r') line.pop_back();
// TODO: support line breaks in tags to ensure they are properly ignored.
if (line.empty() || line[0] == '[') {
if (started) {
Expand Down
8 changes: 6 additions & 2 deletions src/chess/position.cc
Original file line number Diff line number Diff line change
Expand Up @@ -91,17 +91,21 @@ void PositionHistory::Append(Move m) {
// has a bug in implementation of emplace_back, when
// reallocation happens. (it also reallocates Last())
positions_.push_back(Position(Last(), m));
positions_.back().SetRepetitions(ComputeLastMoveRepetitions());
int cycle_length;
int repetitions = ComputeLastMoveRepetitions(&cycle_length);
positions_.back().SetRepetitions(repetitions, cycle_length);
}

int PositionHistory::ComputeLastMoveRepetitions() const {
int PositionHistory::ComputeLastMoveRepetitions(int* cycle_length) const {
*cycle_length = 0;
const auto& last = positions_.back();
// TODO(crem) implement hash/cache based solution.
if (last.GetRule50Ply() < 4) return 0;

for (int idx = positions_.size() - 3; idx >= 0; idx -= 2) {
const auto& pos = positions_[idx];
if (pos.GetBoard() == last.GetBoard()) {
*cycle_length = positions_.size() - 1 - idx;
return 1 + pos.GetRepetitions();
}
if (pos.GetRule50Ply() < 2) return 0;
Expand Down
12 changes: 10 additions & 2 deletions src/chess/position.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,15 @@ class Position {
// How many time the same position appeared in the game before.
int GetRepetitions() const { return repetitions_; }

// How many half-moves since the same position appeared in the game before.
int GetPliesSincePrevRepetition() const { return cycle_length_; }

// Someone outside that class knows better about repetitions, so they can
// set it.
void SetRepetitions(int repetitions) { repetitions_ = repetitions; }
void SetRepetitions(int repetitions, int cycle_length) {
repetitions_ = repetitions;
cycle_length_ = cycle_length;
}

// Number of ply with no captures and pawn moves.
int GetRule50Ply() const { return rule50_ply_; }
Expand All @@ -73,6 +79,8 @@ class Position {
int rule50_ply_ = 0;
// How many repetitions this position had before. For new positions it's 0.
int repetitions_;
// How many half-moves since the position was repeated or 0.
int cycle_length_;
// number of half-moves since beginning of the game.
int ply_count_ = 0;
};
Expand Down Expand Up @@ -125,7 +133,7 @@ class PositionHistory {
bool DidRepeatSinceLastZeroingMove() const;

private:
int ComputeLastMoveRepetitions() const;
int ComputeLastMoveRepetitions(int* cycle_length) const;

std::vector<Position> positions_;
};
Expand Down
30 changes: 28 additions & 2 deletions src/mcts/node.cc
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,7 @@ void Node::SortEdges() {
}

void Node::MakeTerminal(GameResult result, float plies_left, Terminal type) {
SetBounds(result, result);
if (type != Terminal::TwoFold) SetBounds(result, result);
terminal_type_ = type;
m_ = plies_left;
if (result == GameResult::DRAW) {
Expand Down Expand Up @@ -375,11 +375,37 @@ void Node::AdjustForTerminal(float v, float d, float m, int multivisit) {
d_ += multivisit * d / n_;
m_ += multivisit * m / n_;
// Best child is potentially no longer valid. This shouldn't be needed since
// AjdustForTerminal is always called immediately after FinalizeScoreUpdate,
// AdjustForTerminal is always called immediately after FinalizeScoreUpdate,
// but for safety in case that changes.
best_child_cached_ = nullptr;
}

void Node::RevertTerminalVisits(float v, float d, float m, int multivisit) {
// Compute new n_ first, as reducing a node to 0 visits is a special case.
const int n_new = n_ - multivisit;
if (n_new <= 0) {
if (parent_ != nullptr) {
// To keep consistency with FinalizeScoreUpdate() expanding a node again,
// we need to reduce the parent's visited policy.
parent_->visited_policy_ -= parent_->edges_[index_].GetP();
}
// If n_new == 0, reset all relevant values to 0.
wl_ = 0.0;
d_ = 1.0;
m_ = 0.0;
n_ = 0;
} else {
// Recompute Q and M.
wl_ -= multivisit * (v - wl_) / n_new;
d_ -= multivisit * (d - d_) / n_new;
m_ -= multivisit * (m - m_) / n_new;
// Decrement N.
n_ -= multivisit;
}
// Best child is potentially no longer valid.
best_child_cached_ = nullptr;
}

void Node::UpdateBestChild(const Iterator& best_edge, int visits_allowed) {
best_child_cached_ = best_edge.node();
// An edge can point to an unexpanded node with n==0. These nodes don't
Expand Down
5 changes: 4 additions & 1 deletion src/mcts/node.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ class Node {
using Iterator = Edge_Iterator<false>;
using ConstIterator = Edge_Iterator<true>;

enum class Terminal : uint8_t { NonTerminal, EndOfGame, Tablebase };
enum class Terminal : uint8_t { NonTerminal, EndOfGame, Tablebase, TwoFold };

// Takes pointer to a parent node and own index in a parent.
Node(Node* parent, uint16_t index)
Expand Down Expand Up @@ -165,6 +165,7 @@ class Node {
// Returns whether the node is known to be draw/lose/win.
bool IsTerminal() const { return terminal_type_ != Terminal::NonTerminal; }
bool IsTbTerminal() const { return terminal_type_ == Terminal::Tablebase; }
bool IsTwoFoldTerminal() const { return terminal_type_ == Terminal::TwoFold; }
typedef std::pair<GameResult, GameResult> Bounds;
Bounds GetBounds() const { return {lower_bound_, upper_bound_}; }
uint8_t GetNumEdges() const { return num_edges_; }
Expand All @@ -191,6 +192,8 @@ class Node {
void FinalizeScoreUpdate(float v, float d, float m, int multivisit);
// Like FinalizeScoreUpdate, but it updates n existing visits by delta amount.
void AdjustForTerminal(float v, float d, float m, int multivisit);
// Revert visits to a node which ended in a now reverted terminal.
void RevertTerminalVisits(float v, float d, float m, int multivisit);
// When search decides to treat one visit as several (in case of collisions
// or visiting terminal nodes several times), it amplifies the visit by
// incrementing n_in_flight.
Expand Down
6 changes: 6 additions & 0 deletions src/mcts/params.cc
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,11 @@ const OptionId SearchParams::kRootHasOwnCpuctParamsId{
"If enabled, cpuct parameters for root node are taken from *AtRoot "
"parameters. Otherwise, they are the same as for the rest of nodes. "
"Temporary flag for transition to a new version."};
const OptionId SearchParams::kTwoFoldDrawsId{
"two-fold-draws", "TwoFoldDraws",
"Evaluates twofold repetitions in the search tree as draws. Visits to "
"these positions are reverted when the first occurrence is played "
"and not in the search tree anymore."};
const OptionId SearchParams::kTemperatureId{
"temperature", "Temperature",
"Tau value from softmax formula for the first move. If equal to 0, the "
Expand Down Expand Up @@ -283,6 +288,7 @@ void SearchParams::Populate(OptionsParser* options) {
options->Add<FloatOption>(kCpuctFactorId, 0.0f, 1000.0f) = 2.815f;
options->Add<FloatOption>(kCpuctFactorAtRootId, 0.0f, 1000.0f) = 2.815f;
options->Add<BoolOption>(kRootHasOwnCpuctParamsId) = true;
options->Add<BoolOption>(kTwoFoldDrawsId) = true;
options->Add<FloatOption>(kTemperatureId, 0.0f, 100.0f) = 0.0f;
options->Add<IntOption>(kTempDecayMovesId, 0, 100) = 0;
options->Add<IntOption>(kTempDecayDelayMovesId, 0, 100) = 0;
Expand Down
2 changes: 2 additions & 0 deletions src/mcts/params.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ class SearchParams {
float GetCpuctFactor(bool at_root) const {
return at_root ? kCpuctFactorAtRoot : kCpuctFactor;
}
bool GetTwoFoldDraws() const { return options_.Get<bool>(kTwoFoldDrawsId); }
float GetTemperature() const { return options_.Get<float>(kTemperatureId); }
float GetTemperatureVisitOffset() const {
return options_.Get<float>(kTemperatureVisitOffsetId);
Expand Down Expand Up @@ -121,6 +122,7 @@ class SearchParams {
static const OptionId kCpuctFactorId;
static const OptionId kCpuctFactorAtRootId;
static const OptionId kRootHasOwnCpuctParamsId;
static const OptionId kTwoFoldDrawsId;
static const OptionId kTemperatureId;
static const OptionId kTempDecayMovesId;
static const OptionId kTempDecayDelayMovesId;
Expand Down
65 changes: 58 additions & 7 deletions src/mcts/search.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1044,7 +1044,7 @@ void SearchWorker::GatherMinibatch() {
// of the game), it means that we already visited this node before.
if (picked_node.IsExtendable()) {
// Node was never visited, extend it.
ExtendNode(node);
ExtendNode(node, picked_node.depth);

// Only send non-terminal nodes to a neural network.
if (!node->IsTerminal()) {
Expand Down Expand Up @@ -1145,14 +1145,54 @@ SearchWorker::NodeToProcess SearchWorker::PickNodeToExtend(
}
return NodeToProcess::Collision(node, depth, collision_limit);
}
// Either terminal or unexamined leaf node -- the end of this playout.
if (node->IsTerminal() || !node->HasChildren()) {
// If terminal, we either found a twofold draw to be reverted, or
// reached the end of this playout.
if (node->IsTerminal()) {
// Probably best place to check for two-fold draws consistently.
// Depth starts with 1 at root, so real depth is depth - 1.
// Check whether first repetition was before root. If yes, remove
// terminal status of node and revert all visits in the tree.
// Length of repetition was stored in m_. This code will only do
// something when tree is reused and twofold visits need to be reverted.
if (node->IsTwoFoldTerminal() && depth - 1 < node->GetM()) {
int depth_counter = 0;
// Cache node's values as we reset them in the process. We could
// manually set wl and d, but if we want to reuse this for reverting
// other terminal nodes this is the way to go.
const auto wl = node->GetWL();
const auto d = node->GetD();
const auto m = node->GetM();
const auto terminal_visits = node->GetN();
for (Node* node_to_revert = node; node_to_revert != nullptr;
node_to_revert = node_to_revert->GetParent()) {
// Revert all visits on twofold draw when making it non terminal.
node_to_revert->RevertTerminalVisits(wl, d, m + (float)depth_counter,
terminal_visits);
depth_counter++;
// Even if original tree still exists, we don't want to revert more
// than until new root.
if (depth_counter > depth - 1) break;
// If wl != 0, we would have to switch signs at each depth.
}
// Mark the prior twofold draw as non terminal to extend it again.
node->MakeNotTerminal();
// When reverting the visits, we also need to revert the initial
// visits, as we reused fewer nodes than anticipated.
search_->initial_visits_ -= terminal_visits;
// Max depth doesn't change when reverting the visits, and cum_depth_
// only counts the average depth of new nodes, not reused ones.
} else {
return NodeToProcess::Visit(node, depth);
}
}
// If unexamined leaf node -- the end of this playout.
if (!node->HasChildren()) {
return NodeToProcess::Visit(node, depth);
}
Node* possible_shortcut_child = node->GetCachedBestChild();
if (possible_shortcut_child) {
// Add two here to reverse the conservatism that goes into calculating the
// remaining cache visits.
// Add two here to reverse the conservatism that goes into calculating
// the remaining cache visits.
collision_limit =
std::min(collision_limit, node->GetRemainingCacheVisits() + 2);
is_root_node = false;
Expand Down Expand Up @@ -1239,7 +1279,7 @@ SearchWorker::NodeToProcess SearchWorker::PickNodeToExtend(
}
}

void SearchWorker::ExtendNode(Node* node) {
void SearchWorker::ExtendNode(Node* node, int depth) {
// Initialize position sequence with pre-move position.
history_.Trim(search_->played_history_.GetLength());
std::vector<Move> to_add;
Expand Down Expand Up @@ -1291,9 +1331,20 @@ void SearchWorker::ExtendNode(Node* node) {
return;
}

if (history_.Last().GetRepetitions() >= 2) {
const auto repetitions = history_.Last().GetRepetitions();
// Mark two-fold repetitions as draws according to settings.
// Depth starts with 1 at root, so number of plies in PV is depth - 1.
if (repetitions >= 2) {
node->MakeTerminal(GameResult::DRAW);
return;
} else if (repetitions == 1 && depth - 1 >= 4 &&
params_.GetTwoFoldDraws() &&
depth - 1 >= history_.Last().GetPliesSincePrevRepetition()) {
const auto cycle_length = history_.Last().GetPliesSincePrevRepetition();
// use plies since first repetition as moves left; exact if forced draw.
node->MakeTerminal(GameResult::DRAW, (float)cycle_length,
Node::Terminal::TwoFold);
return;
}

// Neither by-position or by-rule termination, but maybe it's a TB position.
Expand Down
4 changes: 2 additions & 2 deletions src/mcts/search.h
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ class Search {
const SearchParams params_;
const MoveList searchmoves_;
const std::chrono::steady_clock::time_point start_time_;
const int64_t initial_visits_;
int64_t initial_visits_;
// tb_hits_ must be initialized before root_move_filter_.
std::atomic<int> tb_hits_{0};
const MoveList root_move_filter_;
Expand Down Expand Up @@ -303,7 +303,7 @@ class SearchWorker {
};

NodeToProcess PickNodeToExtend(int collision_limit);
void ExtendNode(Node* node);
void ExtendNode(Node* node, int depth);
bool AddNodeToComputation(Node* node, bool add_if_cached, int* transform_out);
int PrefetchIntoCache(Node* node, int budget, bool is_odd_depth);
void FetchSingleNodeResult(NodeToProcess* node_to_process,
Expand Down
Loading

0 comments on commit 0442a72

Please sign in to comment.