├── .gitignore ├── .gitmodules ├── .travis.yml ├── AUTHORS ├── AUTHORS.SAI ├── CMakeLists.txt ├── COPYING ├── Dockerfiles ├── Dockerfile.base ├── Dockerfile.cpu ├── Dockerfile.cpu-blas ├── Dockerfile.gpu ├── Dockerfile.gpu-blas ├── Dockerfile.tests └── Dockerfile.tests-blas ├── README.md ├── SHA256_licence.txt ├── appveyor.yml ├── autogtp ├── .gitignore ├── CMakeLists.txt ├── Console.h ├── Game.cpp ├── Game.h ├── Job.cpp ├── Job.h ├── Management.cpp ├── Management.h ├── Order.cpp ├── Order.h ├── README.md ├── Result.h ├── Worker.cpp ├── Worker.h ├── autogtp.pro └── main.cpp ├── cmake └── Modules │ ├── CMakePushCheckState.cmake │ ├── CheckFortranFunctionExists.cmake │ ├── CheckFunctionExists.cmake │ ├── FindBLAS.cmake │ ├── FindOpenCL.cmake │ ├── FindPackageHandleStandardArgs.cmake │ ├── FindPackageMessage.cmake │ ├── GetGitRevisionDescription.cmake │ └── GetGitRevisionDescription.cmake.in ├── docs ├── CONTRIBUTING-GITHUB.md ├── CONTRIBUTING-LINUX.md ├── CONTRIBUTING-WINDOWS.md ├── FAQ-CHINESE.md ├── FAQ-ENGLISH.md ├── RUN-LINUX.md └── RUN-WINDOWS.md ├── msvc ├── .gitignore ├── VS2019 │ ├── autogtp.vcxproj │ ├── autogtp.vcxproj.filters │ ├── cmake_build.bat │ ├── leela-zero-9x9.vcxproj │ ├── leela-zero-9x9.vcxproj.filters │ ├── leela-zero.vcxproj │ ├── leela-zero.vcxproj.filters │ └── packages.config ├── VS2022 │ ├── autogtp.vcxproj │ ├── autogtp.vcxproj.filters │ ├── cmake_build.bat │ ├── leela-zero-9x9.vcxproj │ ├── leela-zero-9x9.vcxproj.filters │ ├── leela-zero.vcxproj │ ├── leela-zero.vcxproj.filters │ └── packages.config ├── leela-zero2019.sln ├── sai.hta └── sai9x9.bat ├── scripts ├── cpplint.py └── resign_analysis │ └── resign_analysis.py ├── src ├── CL │ └── cl2.hpp ├── CPUPipe.cpp ├── CPUPipe.h ├── FastBoard.cpp ├── FastBoard.h ├── FastState.cpp ├── FastState.h ├── ForwardPipe.h ├── FullBoard.cpp ├── FullBoard.h ├── GTP.cpp ├── GTP.h ├── GameState.cpp ├── GameState.h ├── Im2Col.h ├── KoState.cpp ├── KoState.h ├── Leela.cpp ├── Makefile ├── NNCache.cpp ├── NNCache.h ├── Network.cpp ├── Network.h ├── OpenCL.cpp ├── OpenCL.h ├── OpenCLScheduler.cpp ├── OpenCLScheduler.h ├── Random.cpp ├── Random.h ├── SGFParser.cpp ├── SGFParser.h ├── SGFTree.cpp ├── SGFTree.h ├── SHA256.cpp ├── SHA256.h ├── SMP.cpp ├── SMP.h ├── ThreadPool.h ├── TimeControl.cpp ├── TimeControl.h ├── Timing.cpp ├── Timing.h ├── Training.cpp ├── Training.h ├── Tuner.cpp ├── Tuner.h ├── UCTNode.cpp ├── UCTNode.h ├── UCTNodePointer.cpp ├── UCTNodePointer.h ├── UCTNodeRoot.cpp ├── UCTSearch.cpp ├── UCTSearch.h ├── Utils.cpp ├── Utils.h ├── Zobrist.cpp ├── Zobrist.h ├── config.h ├── half │ └── half.hpp ├── kernels │ ├── clblast │ │ ├── hgemm_tensorcore.opencl │ │ ├── xgemm_batched.opencl │ │ ├── xgemm_part1.opencl │ │ ├── xgemm_part2.opencl │ │ └── xgemm_part3.opencl │ ├── common.opencl │ ├── convolve1.opencl │ ├── convolve3.opencl │ └── tensorcore_test.opencl └── tests │ ├── 0k.txt │ ├── gtests.cpp │ └── utils_unittest.cpp ├── training ├── caffe │ ├── zero.prototxt │ ├── zero_mini.prototxt │ └── zero_nano.prototxt ├── elf │ └── elf_convert.py ├── minigo │ └── convert_minigo.py └── tf │ ├── average_weights.py │ ├── chunkparser.py │ ├── config.py │ ├── dumper │ └── mongo_training.py │ ├── gammadiff.py │ ├── mixprec.py │ ├── net2net.py │ ├── net_to_model.py │ ├── parse.py │ ├── quantize_weights.py │ ├── requirements.txt │ ├── save-gamma.py │ ├── save-w.py │ ├── shufflebuffer.py │ ├── test.py │ ├── tfprocess.py │ └── v2_write_training.py ├── utils ├── KomiSample.cpp ├── NetColorEval.cpp ├── NetEval.cpp ├── NetGenEval.cpp ├── Nodecount.cpp ├── PanelColorParse.cpp ├── ParseChunks.cpp ├── ParseResults.cpp ├── Rndweights.cpp ├── checklength.py ├── cutweights.py ├── saivs.py ├── saivs2d.py ├── saivsdraws.py ├── sgfmerge.py └── wts2mat.py └── validation ├── .gitignore ├── CMakeLists.txt ├── Results.cpp ├── Results.h ├── SPRT.cpp ├── SPRT.h ├── Validation.cpp ├── Validation.h ├── main.cpp └── validation.pro /.gitignore: -------------------------------------------------------------------------------- 1 | sai 2 | *.o 3 | *.d 4 | *.gz 5 | .vscode/settings.json 6 | training/tf/leelalogs 7 | training/tf/checkpoint 8 | training/tf/venv 9 | leelaz-model* 10 | *.orig 11 | sai_opencl_tuning 12 | /build-autogtp-* 13 | /build-validation-* 14 | .vs/ 15 | build/ 16 | debug/ 17 | 18 | *~ 19 | train_* 20 | __pycache__/ 21 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "gtest"] 2 | path = gtest 3 | url = https://github.com/google/googletest.git 4 | [submodule "src/Eigen"] 5 | path = src/Eigen 6 | url = https://gitlab.com/libeigen/eigen.git 7 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: required 2 | 3 | language: cpp 4 | services: 5 | - docker 6 | 7 | before_install: 8 | - docker pull ubuntu:16.04 9 | - docker build -f Dockerfiles/Dockerfile.base -t sai:base . 10 | 11 | jobs: 12 | include: 13 | - stage: test 14 | script: 15 | - docker build -f Dockerfiles/Dockerfile.gpu -t sai:gpu . 16 | - docker run sai:gpu 17 | - script: 18 | - docker build -f Dockerfiles/Dockerfile.gpu-blas -t sai:gpu-blas . 19 | - docker run sai:gpu-blas 20 | - script: 21 | - docker build -f Dockerfiles/Dockerfile.cpu -t sai:cpu . 22 | - docker run sai:cpu 23 | - script: 24 | - docker build -f Dockerfiles/Dockerfile.cpu-blas -t sai:cpu-blas . 25 | - docker run sai:cpu-blas 26 | - script: 27 | - docker build -f Dockerfiles/Dockerfile.tests -t sai:tests . 28 | - docker run sai:tests 29 | - script: 30 | - docker build -f Dockerfiles/Dockerfile.tests-blas -t sai:tests-blas . 31 | - docker run sai:tests-blas 32 | - stage: style 33 | before_install: 34 | script: find . -regex ".*\.\(cpp\|h\|hpp\)" -not -regex ".*moc_.*.cpp" -not -path "./gtest/*" -not -path "./training/*" -not -path "./src/half/*" -not -path "./src/CL/*" -not -path "./src/Eigen/*" | xargs python2 scripts/cpplint.py --filter=-build/c++11,-build/include,-build/include_order,-build/include_what_you_use,-build/namespaces,-readability/braces,-readability/casting,-readability/fn_size,-readability/namespace,-readability/todo,-runtime/explicit,-runtime/indentation_namespace,-runtime/int,-runtime/references,-whitespace/blank_line,-whitespace/braces,-whitespace/comma,-whitespace/comments,-whitespace/empty_loop_body,-whitespace/line_length,-whitespace/semicolon 35 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Gian-Carlo Pascutto 2 | Seth Troisi 3 | Henrik Forstén 4 | TFiFiE 5 | Junhee Yoo 6 | Marco Calignano 7 | Andy Olsen 8 | Hersmunch 9 | Bood Qian 10 | Peter Wen 11 | ywrt 12 | Arseny Krasutsky 13 | earthengine 14 | Jonathan Roy 15 | Mankit Pong 16 | michael 17 | Barry G Becker 18 | Junyan Xu 19 | Maks Kolman 20 | kuba97531 21 | Antti Korhonen 22 | Chin-Chang Yang 23 | Xingcan LAN 24 | bittsitt 25 | tux3 26 | 5525345551 27 | Adrian Petrescu 28 | Akita Noek 29 | Alderi-Tokori 30 | Alexander Taylor 31 | Ancalagon 32 | Ashley Griffiths 33 | Barry Becker 34 | Ed Lee 35 | Eddh 36 | F. Huizinga 37 | FFLaguna 38 | Jiannan Liu 39 | Joe Ren 40 | LL145 41 | Mark Andrew Gerads 42 | Nate 43 | OmnipotentEntity 44 | Przemek Wesołek 45 | Sebastian H 46 | Shen-Ta Hsieh(BestSteve) 47 | Virgile Andreani 48 | Ximin Luo 49 | ZenStone 50 | Zhenzhen Zhan 51 | afalturki 52 | betterworld 53 | cheshirecats 54 | dbosst 55 | fohristiwhirl 56 | gaieepo 57 | ncaq 58 | tterava 59 | wonderingabout 60 | zediir 61 | zliu1022 62 | Пахотин Иван 63 | Google LLC 64 | -------------------------------------------------------------------------------- /AUTHORS.SAI: -------------------------------------------------------------------------------- 1 | The SAI Team is composed of: 2 | ---------------- 3 | Gianluca Amato 4 | Marco Fantozzi 5 | Rosa Gini 6 | Carlo Metta 7 | Francesco Morandin 8 | Maurizio Parton 9 | -------------------------------------------------------------------------------- /Dockerfiles/Dockerfile.base: -------------------------------------------------------------------------------- 1 | FROM ubuntu:16.04 2 | 3 | # Install 4 | RUN apt-get -qq update 5 | RUN apt-get install -y cmake g++ 6 | RUN apt-get install -y libboost-all-dev libopenblas-dev opencl-headers ocl-icd-libopencl1 ocl-icd-opencl-dev zlib1g-dev 7 | RUN apt-get install -y qt5-default qt5-qmake 8 | 9 | RUN mkdir -p /src/build/ 10 | COPY . /src/ 11 | WORKDIR /src/build/ 12 | -------------------------------------------------------------------------------- /Dockerfiles/Dockerfile.cpu: -------------------------------------------------------------------------------- 1 | FROM sai:base 2 | 3 | # CPU build 4 | RUN CXX=g++ CC=gcc cmake -DUSE_CPU_ONLY=1 .. 5 | 6 | CMD cmake --build . --target sai --config Release -- -j2 7 | -------------------------------------------------------------------------------- /Dockerfiles/Dockerfile.cpu-blas: -------------------------------------------------------------------------------- 1 | FROM sai:base 2 | 3 | # CPU build 4 | RUN CXX=g++ CC=gcc cmake -DUSE_CPU_ONLY=1 -DUSE_BLAS=1 .. 5 | 6 | CMD cmake --build . --target sai --config Release -- -j2 7 | -------------------------------------------------------------------------------- /Dockerfiles/Dockerfile.gpu: -------------------------------------------------------------------------------- 1 | FROM sai:base 2 | 3 | # GPU build 4 | RUN CXX=g++ CC=gcc cmake .. 5 | 6 | CMD cmake --build . --target sai --config Release -- -j2 7 | -------------------------------------------------------------------------------- /Dockerfiles/Dockerfile.gpu-blas: -------------------------------------------------------------------------------- 1 | FROM sai:base 2 | 3 | # GPU build 4 | RUN CXX=g++ CC=gcc cmake -DUSE_BLAS=1 .. 5 | 6 | CMD cmake --build . --target sai --config Release -- -j2 7 | -------------------------------------------------------------------------------- /Dockerfiles/Dockerfile.tests: -------------------------------------------------------------------------------- 1 | FROM sai:base 2 | 3 | # CPU build 4 | RUN CXX=g++ CC=gcc cmake -DUSE_CPU_ONLY=1 .. 5 | RUN cmake --build . --target tests --config Release -- -j2 6 | 7 | CMD ./tests 8 | 9 | -------------------------------------------------------------------------------- /Dockerfiles/Dockerfile.tests-blas: -------------------------------------------------------------------------------- 1 | FROM sai:base 2 | 3 | # CPU build 4 | RUN CXX=g++ CC=gcc cmake -DUSE_CPU_ONLY=1 -DUSE_BLAS=1 .. 5 | RUN cmake --build . --target tests --config Release -- -j2 6 | 7 | CMD ./tests 8 | 9 | -------------------------------------------------------------------------------- /SHA256_licence.txt: -------------------------------------------------------------------------------- 1 | /* 2 | * Updated to C++, zedwood.com 2012 3 | * Based on Olivier Gay's version 4 | * See Modified BSD License below: 5 | * 6 | * FIPS 180-2 SHA-224/256/384/512 implementation 7 | * Issue date: 04/30/2005 8 | * http://www.ouah.org/ogay/sha2/ 9 | * 10 | * Copyright (C) 2005, 2007 Olivier Gay 11 | * All rights reserved. 12 | * 13 | * Redistribution and use in source and binary forms, with or without 14 | * modification, are permitted provided that the following conditions 15 | * are met: 16 | * 1. Redistributions of source code must retain the above copyright 17 | * notice, this list of conditions and the following disclaimer. 18 | * 2. Redistributions in binary form must reproduce the above copyright 19 | * notice, this list of conditions and the following disclaimer in the 20 | * documentation and/or other materials provided with the distribution. 21 | * 3. Neither the name of the project nor the names of its contributors 22 | * may be used to endorse or promote products derived from this software 23 | * without specific prior written permission. 24 | * 25 | * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 26 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 | * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 29 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 | * SUCH DAMAGE. 36 | */ 37 | 38 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: '{build}' 2 | image: 3 | - Visual Studio 2015 4 | - Visual Studio 2017 5 | configuration: Release 6 | platform: x64 7 | matrix: 8 | fast_finish: true 9 | environment: 10 | matrix: 11 | - cmake_build: 1 12 | - cmake_build: 1 13 | features: USE_CPU_ONLY 14 | run_tests: 1 15 | - cmake_build: 1 16 | features: USE_CPU_ONLY USE_BLAS 17 | run_tests: 1 18 | - msbuild: 1 19 | skip_commits: 20 | files: 21 | - '**/*.md' 22 | - '**/.gitignore' 23 | - scripts/ 24 | - training/ 25 | - AUTHORS 26 | - COPYING 27 | for: 28 | - matrix: 29 | only: 30 | - image: Visual Studio 2015 31 | install: 32 | - cmd: set MSVCDIR=msvc\VS2015 33 | - cmd: echo %MSVCDIR% 34 | - cmd: nuget restore %MSVCDIR% -PackagesDirectory msvc\packages 35 | - matrix: 36 | only: 37 | - image: Visual Studio 2017 38 | install: 39 | - cmd: set MSVCDIR=msvc\VS2017 40 | - cmd: echo %MSVCDIR% 41 | - cmd: nuget restore %MSVCDIR% -PackagesDirectory msvc\packages 42 | build_script: 43 | - cmd: if "%cmake_build%"=="1" %MSVCDIR%\cmake_build.bat 44 | - cmd: if "%msbuild%"=="1" git submodule update --init --recursive 45 | - cmd: if "%msbuild%"=="1" msbuild /t:build %MSVCDIR%\leela-zero.vcxproj 46 | 47 | test_script: 48 | - cmd: if "%run_tests%"=="1" cd build && Release\tests.exe 49 | 50 | cache: msvc\packages -> appveyor.yml 51 | -------------------------------------------------------------------------------- /autogtp/.gitignore: -------------------------------------------------------------------------------- 1 | /Makefile 2 | /.qmake.stash 3 | /autogtp 4 | /*.sgf 5 | /*.train 6 | /storefile*.bin 7 | /*.gz 8 | /moc_*.cpp 9 | /moc_*.h 10 | /autogtp.pro.user 11 | 12 | # Weight files 13 | /[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]*[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f] 14 | -------------------------------------------------------------------------------- /autogtp/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | cmake_minimum_required(VERSION 3.1) 3 | 4 | add_executable(autogtp 5 | Game.h Order.h Management.h Worker.h Job.h Result.h Console.h 6 | Worker.cpp Management.cpp Job.cpp main.cpp Game.cpp Order.cpp) 7 | set_target_properties(autogtp PROPERTIES AUTOMOC 1) 8 | target_link_libraries(autogtp Qt5::Core) 9 | 10 | install(TARGETS autogtp DESTINATION ${CMAKE_INSTALL_BINDIR}) 11 | -------------------------------------------------------------------------------- /autogtp/Console.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of SAI, which is a fork of Leela Zero. 3 | Copyright (C) 2017-2018 Marco Calignano 4 | 5 | SAI is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | SAI is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with SAI. If not, see . 17 | */ 18 | 19 | #ifndef CONSOLE_H 20 | #define CONSOLE_H 21 | 22 | #include 23 | #include 24 | #include 25 | #include "stdio.h" 26 | 27 | 28 | #ifdef Q_OS_WIN 29 | #include 30 | #include 31 | typedef QWinEventNotifier Notifier; 32 | #else 33 | #include 34 | typedef QSocketNotifier Notifier; 35 | #endif 36 | 37 | 38 | class Console : public QObject 39 | { 40 | Q_OBJECT 41 | public: 42 | Console(QObject *parent = nullptr) 43 | : QObject(parent), 44 | #ifdef Q_OS_WIN 45 | m_notifier(GetStdHandle(STD_INPUT_HANDLE)) { 46 | #else 47 | m_notifier(fileno(stdin), Notifier::Read) { 48 | #endif 49 | connect(&m_notifier, &Notifier::activated, this, &Console::readInput); 50 | } 51 | ~Console() = default; 52 | 53 | signals: 54 | void sendQuit(); 55 | 56 | public slots: 57 | void readInput() { 58 | QTextStream qin(stdin); 59 | QString line = qin.readLine(); 60 | if (line.contains("q")) { 61 | emit sendQuit(); 62 | } 63 | } 64 | private: 65 | Notifier m_notifier; 66 | }; 67 | 68 | #endif // CONSOLE_H 69 | -------------------------------------------------------------------------------- /autogtp/Game.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of SAI, which is a fork of Leela Zero. 3 | Copyright (C) 2017-2018 Marco Calignano 4 | Coptright (C) 2018-2019 SAI Team 5 | 6 | SAI is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SAI is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SAI. If not, see . 18 | */ 19 | 20 | #ifndef GAME_H 21 | #define GAME_H 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | #define BOARD_SIZE 19 28 | 29 | using VersionTuple = std::tuple; 30 | 31 | class Engine { 32 | public: 33 | Engine(const QString& network, 34 | const QString& options, 35 | const QStringList& commands = QStringList("time_settings 0 1 0"), 36 | const QString& binary = QString("./sai")) : 37 | m_binary(binary), m_options(options), 38 | m_network(network), m_commands(commands) { 39 | #ifdef WIN32 40 | m_binary.append(".exe"); 41 | #endif 42 | if (!QFileInfo::exists(m_binary)) { 43 | m_binary.remove(0, 2); // ./sai -> sai 44 | } 45 | } 46 | Engine() = default; 47 | QString getCmdLine(void) const { 48 | return m_binary + " " + m_options + " " + m_network; 49 | } 50 | QString getNetworkFile(void) const { 51 | return QFileInfo(m_network).baseName(); 52 | } 53 | QString m_binary; 54 | QString m_options; 55 | QString m_network; 56 | QStringList m_commands; 57 | }; 58 | 59 | class Game : QProcess { 60 | public: 61 | Game(const Engine& engine); 62 | ~Game() = default; 63 | bool gameStart(const VersionTuple& min_version, 64 | const QString &sgf = QString(), 65 | const int moves = 0); 66 | void move(); 67 | bool waitForMove() { return waitReady(); } 68 | bool readMove(); 69 | bool nextMove(); 70 | bool getScore(); 71 | bool loadSgf(const QString &fileName); 72 | bool loadSgf(const QString &fileName, const int moves); 73 | bool writeSgf(); 74 | bool komi(float komi); 75 | bool loadTraining(const QString &fileName); 76 | bool saveTraining(); 77 | bool fixSgf(Game& whiteGame, const bool resignation, 78 | const bool isSelfPlay); 79 | bool dumpTraining(); 80 | bool dumpDebug(); 81 | void gameQuit(); 82 | QString getMove() const { return m_moveDone; } 83 | QString getFile() const { return m_fileName; } 84 | bool setMove(const QString& m); 85 | bool checkGameEnd(); 86 | int getWinner(); 87 | QString getWinnerName() const { return m_winner; } 88 | int getMovesCount() const { return m_moveNum; } 89 | void setMovesCount(int moves); 90 | int getToMove() const { return m_blackToMove ? BLACK : WHITE; } 91 | QString getResult() const { return m_result.trimmed(); } 92 | const Engine & getEngine() const { return m_engine; } 93 | bool getSgf(QString& sgf); 94 | void mergeSgfComments(QString& blackSgf, const QString& whiteSgf) const; 95 | enum { 96 | BLACK = 0, 97 | WHITE = 1, 98 | JIGO = 2, 99 | }; 100 | 101 | private: 102 | enum { 103 | NO_LEELAZ = 1, 104 | PROCESS_DIED, 105 | WRONG_GTP, 106 | LAUNCH_FAILURE 107 | }; 108 | Engine m_engine; 109 | QString m_winner; 110 | QString m_fileName; 111 | QString m_moveDone; 112 | QString m_result; 113 | bool m_isHandicap; 114 | bool m_resignation; 115 | bool m_blackToMove; 116 | bool m_blackResigned; 117 | int m_passes; 118 | int m_moveNum; 119 | bool sendGtpCommand(QString cmd); 120 | void checkVersion(const VersionTuple &min_version); 121 | bool waitReady(); 122 | bool eatNewLine(); 123 | void error(int errnum); 124 | void fixSgfPlayer(QString& sgfData, const Engine& whiteEngine); 125 | void fixSgfComment(QString& sgfData, Game& whiteGame, 126 | const bool isSelfPlay); 127 | void fixSgfResult(QString& sgfData, const bool resignation); 128 | }; 129 | 130 | #endif /* GAME_H */ 131 | -------------------------------------------------------------------------------- /autogtp/Job.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of SAI, which is a fork of Leela Zero. 3 | Copyright (C) 2017-2018 Marco Calignano 4 | Coptright (C) 2018 SAI Team 5 | 6 | SAI is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SAI is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SAI. If not, see . 18 | */ 19 | 20 | #ifndef JOB_H 21 | #define JOB_H 22 | 23 | #include "Game.h" 24 | #include "Result.h" 25 | #include "Order.h" 26 | #include 27 | #include 28 | #include 29 | class Management; 30 | using VersionTuple = std::tuple; 31 | 32 | class Job : public QObject { 33 | Q_OBJECT 34 | public: 35 | enum { 36 | RUNNING = 0, 37 | FINISHING, 38 | STORING 39 | }; 40 | enum { 41 | Production = 0, 42 | Validation 43 | }; 44 | Job(QString gpu, Management *parent); 45 | ~Job() = default; 46 | virtual Result execute() = 0; 47 | virtual void init(const Order &o); 48 | void finish() { m_state.storeRelaxed(FINISHING); } 49 | void store() { 50 | m_state.storeRelaxed(STORING); 51 | } 52 | 53 | protected: 54 | QAtomicInt m_state; 55 | QString m_gpu; 56 | int m_moves; 57 | VersionTuple m_leelazMinVersion; 58 | Management *m_boss; 59 | }; 60 | 61 | 62 | class ProductionJob : public Job { 63 | Q_OBJECT 64 | public: 65 | ProductionJob(QString gpu, Management *parent); 66 | ~ProductionJob() = default; 67 | void init(const Order &o); 68 | Result execute(); 69 | private: 70 | Engine m_engine; 71 | QString m_sgf; 72 | QString m_selfplay_id; 73 | bool m_debug; 74 | bool m_restore; 75 | }; 76 | 77 | class ValidationJob : public Job { 78 | Q_OBJECT 79 | public: 80 | ValidationJob(QString gpu, Management *parent); 81 | ~ValidationJob() = default; 82 | void init(const Order &o); 83 | Result execute(); 84 | private: 85 | Engine m_engineFirst; 86 | Engine m_engineSecond; 87 | QString m_sgf; 88 | }; 89 | 90 | class WaitJob : public Job { 91 | Q_OBJECT 92 | public: 93 | WaitJob(QString gpu, Management *parent); 94 | ~WaitJob() = default; 95 | void init(const Order &o); 96 | Result execute(); 97 | private: 98 | int m_minutes; 99 | }; 100 | 101 | #endif // JOB_H 102 | -------------------------------------------------------------------------------- /autogtp/Management.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of SAI, which is a fork of Leela Zero. 3 | Copyright (C) 2017-2018 Marco Calignano 4 | Coptright (C) 2018-2019 SAI Team 5 | 6 | SAI is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SAI is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SAI. If not, see . 18 | */ 19 | 20 | #ifndef MANAGEMENT_H 21 | #define MANAGEMENT_H 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include "Worker.h" 34 | 35 | constexpr int AUTOGTP_VERSION = 18; 36 | 37 | class Management : public QObject { 38 | Q_OBJECT 39 | public: 40 | Management(const int gpus, 41 | const int games, 42 | const QStringList& gpuslist, 43 | const int ver, 44 | const int maxGame, 45 | const bool delNetworks, 46 | const QString& keep, 47 | const QString& debug, 48 | const QString& serverUrl, 49 | const QString& publicAuthKey, 50 | const QString& username, 51 | const QString& password); 52 | ~Management() = default; 53 | void giveAssignments(); 54 | void incMoves() { m_movesMade++; } 55 | void wait(); 56 | signals: 57 | void sendQuit(); 58 | public slots: 59 | void getResult(Order ord, Result res, int index, int duration); 60 | void storeGames(); 61 | 62 | private: 63 | 64 | struct NetworkException: public std::runtime_error 65 | { 66 | NetworkException(std::string const& message) 67 | : std::runtime_error("NetworkException: " + message) 68 | {} 69 | }; 70 | QMutex m_syncMutex; 71 | QVector m_gamesThreads; 72 | int m_games; 73 | int m_gpus; 74 | QStringList m_gpusList; 75 | int m_selfGames; 76 | int m_matchGames; 77 | int m_gamesPlayed; 78 | QAtomicInt m_movesMade; 79 | QString m_keepPath; 80 | QString m_debugPath; 81 | QString m_serverUrl; 82 | QString m_publicAuthKey; 83 | QString m_username; 84 | QString m_password; 85 | QString m_hashedPassword; 86 | int m_version; 87 | std::chrono::high_resolution_clock::time_point m_start; 88 | int m_storeGames; 89 | QList m_storedFiles; 90 | Order m_fallBack; 91 | Order m_lastMatch; 92 | int m_gamesLeft; 93 | int m_threadsLeft; 94 | bool m_delNetworks; 95 | QLockFile *m_lockFile; 96 | QString m_leelaversion; 97 | 98 | Order getWorkInternal(bool tuning); 99 | Order getWork(bool tuning = false); 100 | Order getWork(const QFileInfo &file); 101 | QString getOption(const QJsonObject &ob, const QString &key, const QString &opt, const QString &defValue); 102 | QString getBoolOption(const QJsonObject &ob, const QString &key, const QString &opt, bool defValue); 103 | QString getOptionsString(const QJsonObject &opt, const QString &rnd); 104 | QString getGtpCommandsString(const QJsonValue >pCommands); 105 | void sendAllGames(); 106 | void checkStoredGames(); 107 | QFileInfo getNextStored(); 108 | bool networkExists(const QString &name, const QString &gzipHash); 109 | void fetchNetwork(const QString &net, const QString &hash); 110 | QString fetchGameData(const QString &name, const QString &extension); 111 | void printTimingInfo(float duration); 112 | void runTuningProcess(const QString &tuneCmdLine); 113 | void gzipFile(const QString &fileName); 114 | bool sendCurl(const QStringList &lines, const QStringList &args = QStringList()); 115 | void saveCurlCmdLine(const QStringList &prog_cmdline, const QString &name); 116 | void archiveFiles(const QString &fileName); 117 | void cleanupFiles(const QString &fileName); 118 | void uploadData(const QMap &r, const QMap &l); 119 | void uploadResult(const QMap &r, const QMap &l); 120 | }; 121 | 122 | #endif 123 | -------------------------------------------------------------------------------- /autogtp/Order.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of SAI, which is a fork of Leela Zero. 3 | Copyright (C) 2017-2018 Marco Calignano 4 | 5 | SAI is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | SAI is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with SAI. If not, see . 17 | */ 18 | 19 | #include "Order.h" 20 | #include 21 | #include 22 | 23 | void Order::save(const QString &file) { 24 | QFile f(file); 25 | if (!f.open(QIODevice::WriteOnly | QIODevice::Text)) { 26 | return; 27 | } 28 | QTextStream out(&f); 29 | out << m_type << Qt::endl; 30 | out << m_parameters.size() << Qt::endl; 31 | for (QString key : m_parameters.keys()) 32 | { 33 | out << key << " " << m_parameters.value(key) << Qt::endl; 34 | } 35 | out.flush(); 36 | f.close(); 37 | } 38 | 39 | void Order::load(const QString &file) { 40 | QFile f(file); 41 | if (!f.open(QIODevice::ReadOnly | QIODevice::Text)) { 42 | return; 43 | } 44 | QTextStream in(&f); 45 | in >> m_type; 46 | int count; 47 | in >> count; 48 | QString key; 49 | for (int i = 0; i < count; i++) { 50 | in >> key; 51 | if (key.contains("options") || key.contains("gtpCommands")) { 52 | m_parameters[key] = in.readLine().remove(0, 1); 53 | } else { 54 | in >> m_parameters[key]; 55 | } 56 | } 57 | f.close(); 58 | } 59 | -------------------------------------------------------------------------------- /autogtp/Order.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of SAI, which is a fork of Leela Zero. 3 | Copyright (C) 2017-2018 Marco Calignano 4 | 5 | SAI is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | SAI is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with SAI. If not, see . 17 | */ 18 | 19 | #ifndef ORDER_H 20 | #define ORDER_H 21 | 22 | #include 23 | #include 24 | 25 | class Order { 26 | public: 27 | enum { 28 | Error = 0, 29 | Production, 30 | Validation, 31 | Wait, 32 | RestoreMatch, 33 | RestoreSelfPlayed 34 | }; 35 | Order() = default; 36 | Order(int t, QMap p = QMap()) { m_type = t; m_parameters = p; } 37 | Order(const Order &o) { m_type = o.m_type; m_parameters = o.m_parameters; } 38 | Order &operator=(const Order &o) { m_type = o.m_type; m_parameters = o.m_parameters; return *this; } 39 | ~Order() = default; 40 | void type(int t) { m_type = t; } 41 | int type() const { return m_type; } 42 | QMap parameters() const { return m_parameters; } 43 | void parameters(const QMap &l) { m_parameters = l; } 44 | void add(const QString &key, const QString &value) { m_parameters[key] = value; } 45 | bool isValid() { return (m_type > Error && m_type <= RestoreSelfPlayed); } 46 | void save(const QString &file); 47 | void load(const QString &file); 48 | 49 | private: 50 | int m_type; 51 | QMap m_parameters; 52 | }; 53 | 54 | #endif // ORDER_H 55 | -------------------------------------------------------------------------------- /autogtp/README.md: -------------------------------------------------------------------------------- 1 | # autogtp 2 | 3 | This is a self-play tool for SAI. When launched, it will fetch the 4 | best network from the server so far, play a game against itself, and upload 5 | the SGF and training data at the end of the game. 6 | 7 | ## Requirements 8 | 9 | * Qt 5.3 or later with qmake 10 | * C++14 capable compiler 11 | * curl 12 | * gzip and gunzip 13 | 14 | ## Matches information 15 | 16 | Autogtp will automatically download better networks once found. 17 | 18 | While autogtp is running, typing q+Enter will save the processed data and exit. 19 | When autogtp runs next, autogtp will continue the game. 20 | 21 | Not each trained network will be a strength improvement over the prior one. 22 | Patience please. :) 23 | 24 | Match games are played at full strength. 25 | 26 | Self-play games are played with some randomness in the first moves, 27 | and noise all game long. 28 | 29 | Training data from self-play games are full strength even if plays appear weak. 30 | -------------------------------------------------------------------------------- /autogtp/Result.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of SAI, which is a fork of Leela Zero. 3 | Copyright (C) 2017-2018 Marco Calignano 4 | 5 | SAI is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | SAI is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with SAI. If not, see . 17 | */ 18 | 19 | #ifndef RESULT_H 20 | #define RESULT_H 21 | 22 | #include 23 | #include 24 | 25 | class Result { 26 | public: 27 | enum Type { 28 | File = 0, 29 | Win, 30 | Loss, 31 | Waited, 32 | StoreMatch, 33 | StoreSelfPlayed, 34 | Error 35 | }; 36 | Result() = default; 37 | Result(int t, QMap n = QMap()) { m_type = t, m_parameters = n; } 38 | ~Result() = default; 39 | void type(int t) { m_type = t; } 40 | int type() { return m_type; } 41 | void add(const QString &name, const QString &value) { m_parameters[name] = value; } 42 | QMap parameters() { return m_parameters; } 43 | void clear() { m_parameters.clear(); } 44 | private: 45 | int m_type; 46 | QMap m_parameters; 47 | }; 48 | 49 | #endif // RESULT_H 50 | -------------------------------------------------------------------------------- /autogtp/Worker.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of SAI, which is a fork of Leela Zero. 3 | Copyright (C) 2017-2018 Marco Calignano 4 | 5 | SAI is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | SAI is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with SAI. If not, see . 17 | */ 18 | 19 | #include "Worker.h" 20 | #include "Game.h" 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | 27 | Worker::Worker(int index, const QString& gpuIndex, Management *parent) : 28 | m_index(index), 29 | m_state(), 30 | m_gpu(""), 31 | m_job(nullptr), 32 | m_boss(parent) 33 | { 34 | if (!gpuIndex.isEmpty()) { 35 | m_gpu = " --gpu=" + gpuIndex + " "; 36 | } 37 | } 38 | 39 | void Worker::doStore() { 40 | QTextStream(stdout) << "Storing current game ..." << Qt::endl; 41 | m_job->store(); 42 | m_state.storeRelaxed(STORING); 43 | } 44 | 45 | void Worker::order(Order o) 46 | { 47 | if (!o.isValid()) { 48 | if (m_job != nullptr) { 49 | m_job->finish(); 50 | } 51 | return; 52 | } 53 | if (m_todo.type() != o.type() || m_job == nullptr) { 54 | createJob(o.type()); 55 | } 56 | m_todo = o; 57 | m_job->init(m_todo); 58 | } 59 | 60 | 61 | void Worker::createJob(int type) { 62 | if (m_job != nullptr) { 63 | delete m_job; 64 | } 65 | switch (type) { 66 | case Order::Production: 67 | case Order::RestoreSelfPlayed: 68 | m_job = new ProductionJob(m_gpu, m_boss); 69 | break; 70 | case Order::Validation: 71 | case Order::RestoreMatch: 72 | m_job = new ValidationJob(m_gpu, m_boss); 73 | break; 74 | case Order::Wait: 75 | m_job = new WaitJob(m_gpu, m_boss); 76 | break; 77 | } 78 | } 79 | 80 | void Worker::run() { 81 | Result res; 82 | do { 83 | auto start = std::chrono::high_resolution_clock::now(); 84 | res = m_job->execute(); 85 | auto end = std::chrono::high_resolution_clock::now(); 86 | auto gameDuration = 87 | std::chrono::duration_cast(end - start).count(); 88 | if (m_state != STORING) { 89 | emit resultReady(m_todo, res, m_index, gameDuration); 90 | } 91 | } while (m_state == RUNNING); 92 | if (m_state == STORING) { 93 | m_todo.add("moves", res.parameters()["moves"]); 94 | m_todo.add("sgf", res.parameters()["sgf"]); 95 | if (res.type() == Result::StoreMatch) { 96 | m_todo.type(Order::RestoreMatch); 97 | } else { 98 | m_todo.type(Order::RestoreSelfPlayed); 99 | } 100 | QString unique = QUuid::createUuid().toRfc4122().toHex(); 101 | QLockFile fi("storefile" + unique + ".bin.lock"); 102 | fi.lock(); 103 | m_todo.save("storefile" + unique + ".bin"); 104 | fi.unlock(); 105 | } 106 | QTextStream(stdout) << "Program ends: quitting current worker." << Qt::endl; 107 | } 108 | -------------------------------------------------------------------------------- /autogtp/Worker.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of SAI, which is a fork of Leela Zero. 3 | Copyright (C) 2017-2018 Marco Calignano 4 | 5 | SAI is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | SAI is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with SAI. If not, see . 17 | */ 18 | 19 | #ifndef WORKER_H 20 | #define WORKER_H 21 | 22 | #include "Job.h" 23 | #include "Order.h" 24 | 25 | #include 26 | #include 27 | 28 | class Management; 29 | 30 | class Worker : public QThread { 31 | Q_OBJECT 32 | public: 33 | enum { 34 | RUNNING = 0, 35 | FINISHING, 36 | STORING 37 | }; 38 | Worker(int index, const QString& gpuIndex, Management *parent); 39 | ~Worker() = default; 40 | void order(Order o); 41 | void doFinish() { m_job->finish(); m_state.storeRelaxed(FINISHING); } 42 | void doStore(); 43 | void run() override; 44 | signals: 45 | void resultReady(Order o, Result r, int index, int duration); 46 | private: 47 | int m_index; 48 | QAtomicInt m_state; 49 | QString m_gpu; 50 | Order m_todo; 51 | Job *m_job; 52 | Management *m_boss; 53 | void createJob(int type); 54 | }; 55 | 56 | #endif // WORKER_H 57 | -------------------------------------------------------------------------------- /autogtp/autogtp.pro: -------------------------------------------------------------------------------- 1 | QT_REQ_MAJOR_VERSION = 5 2 | QT_REQ_MINOR_VERSION = 3 3 | QT_REQ_VERSION = "$$QT_REQ_MAJOR_VERSION"."$$QT_REQ_MINOR_VERSION" 4 | 5 | lessThan(QT_MAJOR_VERSION, $$QT_REQ_MAJOR_VERSION) { 6 | error(Minimum supported Qt version is $$QT_REQ_VERSION!) 7 | } 8 | equals(QT_MAJOR_VERSION, $$QT_REQ_MAJOR_VERSION):lessThan(QT_MINOR_VERSION, $$QT_REQ_MINOR_VERSION) { 9 | error(Minimum supported Qt version is $$QT_REQ_VERSION!) 10 | } 11 | 12 | 13 | TARGET = autogtp 14 | CONFIG += c++14 15 | CONFIG += warn_on 16 | CONFIG += console 17 | CONFIG -= app_bundle 18 | 19 | TEMPLATE = app 20 | 21 | SOURCES += main.cpp \ 22 | Game.cpp \ 23 | Worker.cpp \ 24 | Order.cpp \ 25 | Job.cpp \ 26 | Management.cpp 27 | 28 | HEADERS += \ 29 | Game.h \ 30 | Worker.h \ 31 | Job.h \ 32 | Order.h \ 33 | Result.h \ 34 | Management.h \ 35 | Console.h 36 | -------------------------------------------------------------------------------- /cmake/Modules/CMakePushCheckState.cmake: -------------------------------------------------------------------------------- 1 | # Distributed under the OSI-approved BSD 3-Clause License. See accompanying 2 | # file Copyright.txt or https://cmake.org/licensing for details. 3 | 4 | #.rst: 5 | # CMakePushCheckState 6 | # ------------------- 7 | # 8 | # 9 | # 10 | # This module defines three macros: CMAKE_PUSH_CHECK_STATE() 11 | # CMAKE_POP_CHECK_STATE() and CMAKE_RESET_CHECK_STATE() These macros can 12 | # be used to save, restore and reset (i.e., clear contents) the state of 13 | # the variables CMAKE_REQUIRED_FLAGS, CMAKE_REQUIRED_DEFINITIONS, 14 | # CMAKE_REQUIRED_LIBRARIES, CMAKE_REQUIRED_INCLUDES and CMAKE_EXTRA_INCLUDE_FILES 15 | # used by the various Check-files coming with CMake, like e.g. 16 | # check_function_exists() etc. The variable contents are pushed on a 17 | # stack, pushing multiple times is supported. This is useful e.g. when 18 | # executing such tests in a Find-module, where they have to be set, but 19 | # after the Find-module has been executed they should have the same 20 | # value as they had before. 21 | # 22 | # CMAKE_PUSH_CHECK_STATE() macro receives optional argument RESET. 23 | # Whether it's specified, CMAKE_PUSH_CHECK_STATE() will set all 24 | # CMAKE_REQUIRED_* variables to empty values, same as 25 | # CMAKE_RESET_CHECK_STATE() call will do. 26 | # 27 | # Usage: 28 | # 29 | # :: 30 | # 31 | # cmake_push_check_state(RESET) 32 | # set(CMAKE_REQUIRED_DEFINITIONS -DSOME_MORE_DEF) 33 | # check_function_exists(...) 34 | # cmake_reset_check_state() 35 | # set(CMAKE_REQUIRED_DEFINITIONS -DANOTHER_DEF) 36 | # check_function_exists(...) 37 | # cmake_pop_check_state() 38 | 39 | macro(CMAKE_RESET_CHECK_STATE) 40 | 41 | set(CMAKE_EXTRA_INCLUDE_FILES) 42 | set(CMAKE_REQUIRED_INCLUDES) 43 | set(CMAKE_REQUIRED_DEFINITIONS) 44 | set(CMAKE_REQUIRED_LIBRARIES) 45 | set(CMAKE_REQUIRED_FLAGS) 46 | set(CMAKE_REQUIRED_QUIET) 47 | 48 | endmacro() 49 | 50 | macro(CMAKE_PUSH_CHECK_STATE) 51 | 52 | if(NOT DEFINED _CMAKE_PUSH_CHECK_STATE_COUNTER) 53 | set(_CMAKE_PUSH_CHECK_STATE_COUNTER 0) 54 | endif() 55 | 56 | math(EXPR _CMAKE_PUSH_CHECK_STATE_COUNTER "${_CMAKE_PUSH_CHECK_STATE_COUNTER}+1") 57 | 58 | set(_CMAKE_EXTRA_INCLUDE_FILES_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER} ${CMAKE_EXTRA_INCLUDE_FILES}) 59 | set(_CMAKE_REQUIRED_INCLUDES_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER} ${CMAKE_REQUIRED_INCLUDES}) 60 | set(_CMAKE_REQUIRED_DEFINITIONS_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER} ${CMAKE_REQUIRED_DEFINITIONS}) 61 | set(_CMAKE_REQUIRED_LIBRARIES_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER} ${CMAKE_REQUIRED_LIBRARIES}) 62 | set(_CMAKE_REQUIRED_FLAGS_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER} ${CMAKE_REQUIRED_FLAGS}) 63 | set(_CMAKE_REQUIRED_QUIET_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER} ${CMAKE_REQUIRED_QUIET}) 64 | 65 | if (${ARGC} GREATER 0 AND "${ARGV0}" STREQUAL "RESET") 66 | cmake_reset_check_state() 67 | endif() 68 | 69 | endmacro() 70 | 71 | macro(CMAKE_POP_CHECK_STATE) 72 | 73 | # don't pop more than we pushed 74 | if("${_CMAKE_PUSH_CHECK_STATE_COUNTER}" GREATER "0") 75 | 76 | set(CMAKE_EXTRA_INCLUDE_FILES ${_CMAKE_EXTRA_INCLUDE_FILES_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER}}) 77 | set(CMAKE_REQUIRED_INCLUDES ${_CMAKE_REQUIRED_INCLUDES_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER}}) 78 | set(CMAKE_REQUIRED_DEFINITIONS ${_CMAKE_REQUIRED_DEFINITIONS_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER}}) 79 | set(CMAKE_REQUIRED_LIBRARIES ${_CMAKE_REQUIRED_LIBRARIES_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER}}) 80 | set(CMAKE_REQUIRED_FLAGS ${_CMAKE_REQUIRED_FLAGS_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER}}) 81 | set(CMAKE_REQUIRED_QUIET ${_CMAKE_REQUIRED_QUIET_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER}}) 82 | 83 | math(EXPR _CMAKE_PUSH_CHECK_STATE_COUNTER "${_CMAKE_PUSH_CHECK_STATE_COUNTER}-1") 84 | endif() 85 | 86 | endmacro() 87 | -------------------------------------------------------------------------------- /cmake/Modules/CheckFortranFunctionExists.cmake: -------------------------------------------------------------------------------- 1 | # Distributed under the OSI-approved BSD 3-Clause License. See accompanying 2 | # file Copyright.txt or https://cmake.org/licensing for details. 3 | 4 | #.rst: 5 | # CheckFortranFunctionExists 6 | # -------------------------- 7 | # 8 | # macro which checks if the Fortran function exists 9 | # 10 | # CHECK_FORTRAN_FUNCTION_EXISTS(FUNCTION VARIABLE) 11 | # 12 | # :: 13 | # 14 | # FUNCTION - the name of the Fortran function 15 | # VARIABLE - variable to store the result 16 | # Will be created as an internal cache variable. 17 | # 18 | # 19 | # 20 | # The following variables may be set before calling this macro to modify 21 | # the way the check is run: 22 | # 23 | # :: 24 | # 25 | # CMAKE_REQUIRED_LIBRARIES = list of libraries to link 26 | 27 | macro(CHECK_FORTRAN_FUNCTION_EXISTS FUNCTION VARIABLE) 28 | if(NOT DEFINED ${VARIABLE}) 29 | message(STATUS "Looking for Fortran ${FUNCTION}") 30 | if(CMAKE_REQUIRED_LIBRARIES) 31 | set(CHECK_FUNCTION_EXISTS_ADD_LIBRARIES 32 | LINK_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES}) 33 | else() 34 | set(CHECK_FUNCTION_EXISTS_ADD_LIBRARIES) 35 | endif() 36 | file(WRITE 37 | ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/testFortranCompiler.f 38 | " 39 | program TESTFortran 40 | external ${FUNCTION} 41 | call ${FUNCTION}() 42 | end program TESTFortran 43 | " 44 | ) 45 | try_compile(${VARIABLE} 46 | ${CMAKE_BINARY_DIR} 47 | ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/testFortranCompiler.f 48 | ${CHECK_FUNCTION_EXISTS_ADD_LIBRARIES} 49 | OUTPUT_VARIABLE OUTPUT 50 | ) 51 | # message(STATUS "${OUTPUT}") 52 | if(${VARIABLE}) 53 | set(${VARIABLE} 1 CACHE INTERNAL "Have Fortran function ${FUNCTION}") 54 | message(STATUS "Looking for Fortran ${FUNCTION} - found") 55 | file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log 56 | "Determining if the Fortran ${FUNCTION} exists passed with the following output:\n" 57 | "${OUTPUT}\n\n") 58 | else() 59 | message(STATUS "Looking for Fortran ${FUNCTION} - not found") 60 | set(${VARIABLE} "" CACHE INTERNAL "Have Fortran function ${FUNCTION}") 61 | file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log 62 | "Determining if the Fortran ${FUNCTION} exists failed with the following output:\n" 63 | "${OUTPUT}\n\n") 64 | endif() 65 | endif() 66 | endmacro() 67 | -------------------------------------------------------------------------------- /cmake/Modules/CheckFunctionExists.cmake: -------------------------------------------------------------------------------- 1 | # Distributed under the OSI-approved BSD 3-Clause License. See accompanying 2 | # file Copyright.txt or https://cmake.org/licensing for details. 3 | 4 | #.rst: 5 | # CheckFunctionExists 6 | # ------------------- 7 | # 8 | # Check if a C function can be linked:: 9 | # 10 | # check_function_exists( ) 11 | # 12 | # Check that the ```` is provided by libraries on the system and store 13 | # the result in a ````. ```` will be created as an internal 14 | # cache variable. 15 | # 16 | # The following variables may be set before calling this macro to modify the 17 | # way the check is run: 18 | # 19 | # :: 20 | # 21 | # CMAKE_REQUIRED_FLAGS = string of compile command line flags 22 | # CMAKE_REQUIRED_DEFINITIONS = list of macros to define (-DFOO=bar) 23 | # CMAKE_REQUIRED_INCLUDES = list of include directories 24 | # CMAKE_REQUIRED_LIBRARIES = list of libraries to link 25 | # CMAKE_REQUIRED_QUIET = execute quietly without messages 26 | # 27 | # .. note:: 28 | # 29 | # Prefer using :Module:`CheckSymbolExists` instead of this module, 30 | # for the following reasons: 31 | # 32 | # * ``check_function_exists()`` can't detect functions that are inlined 33 | # in headers or specified as a macro. 34 | # 35 | # * ``check_function_exists()`` can't detect anything in the 32-bit 36 | # versions of the Win32 API, because of a mismatch in calling conventions. 37 | # 38 | # * ``check_function_exists()`` only verifies linking, it does not verify 39 | # that the function is declared in system headers. 40 | 41 | macro(CHECK_FUNCTION_EXISTS FUNCTION VARIABLE) 42 | if(NOT DEFINED "${VARIABLE}" OR "x${${VARIABLE}}" STREQUAL "x${VARIABLE}") 43 | set(MACRO_CHECK_FUNCTION_DEFINITIONS 44 | "-DCHECK_FUNCTION_EXISTS=${FUNCTION} ${CMAKE_REQUIRED_FLAGS}") 45 | if(NOT CMAKE_REQUIRED_QUIET) 46 | message(STATUS "Looking for ${FUNCTION}") 47 | endif() 48 | if(CMAKE_REQUIRED_LIBRARIES) 49 | set(CHECK_FUNCTION_EXISTS_ADD_LIBRARIES 50 | LINK_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES}) 51 | else() 52 | set(CHECK_FUNCTION_EXISTS_ADD_LIBRARIES) 53 | endif() 54 | if(CMAKE_REQUIRED_INCLUDES) 55 | set(CHECK_FUNCTION_EXISTS_ADD_INCLUDES 56 | "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_REQUIRED_INCLUDES}") 57 | else() 58 | set(CHECK_FUNCTION_EXISTS_ADD_INCLUDES) 59 | endif() 60 | 61 | if(CMAKE_C_COMPILER_LOADED) 62 | set(_cfe_source ${CMAKE_ROOT}/Modules/CheckFunctionExists.c) 63 | elseif(CMAKE_CXX_COMPILER_LOADED) 64 | set(_cfe_source ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CheckFunctionExists/CheckFunctionExists.cxx) 65 | configure_file(${CMAKE_ROOT}/Modules/CheckFunctionExists.c "${_cfe_source}" COPYONLY) 66 | else() 67 | message(FATAL_ERROR "CHECK_FUNCTION_EXISTS needs either C or CXX language enabled") 68 | endif() 69 | 70 | try_compile(${VARIABLE} 71 | ${CMAKE_BINARY_DIR} 72 | ${_cfe_source} 73 | COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS} 74 | ${CHECK_FUNCTION_EXISTS_ADD_LIBRARIES} 75 | CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_FUNCTION_DEFINITIONS} 76 | "${CHECK_FUNCTION_EXISTS_ADD_INCLUDES}" 77 | OUTPUT_VARIABLE OUTPUT) 78 | unset(_cfe_source) 79 | 80 | if(${VARIABLE}) 81 | set(${VARIABLE} 1 CACHE INTERNAL "Have function ${FUNCTION}") 82 | if(NOT CMAKE_REQUIRED_QUIET) 83 | message(STATUS "Looking for ${FUNCTION} - found") 84 | endif() 85 | file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log 86 | "Determining if the function ${FUNCTION} exists passed with the following output:\n" 87 | "${OUTPUT}\n\n") 88 | else() 89 | if(NOT CMAKE_REQUIRED_QUIET) 90 | message(STATUS "Looking for ${FUNCTION} - not found") 91 | endif() 92 | set(${VARIABLE} "" CACHE INTERNAL "Have function ${FUNCTION}") 93 | file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log 94 | "Determining if the function ${FUNCTION} exists failed with the following output:\n" 95 | "${OUTPUT}\n\n") 96 | endif() 97 | endif() 98 | endmacro() 99 | -------------------------------------------------------------------------------- /cmake/Modules/FindPackageMessage.cmake: -------------------------------------------------------------------------------- 1 | # Distributed under the OSI-approved BSD 3-Clause License. See accompanying 2 | # file Copyright.txt or https://cmake.org/licensing for details. 3 | 4 | #.rst: 5 | # FindPackageMessage 6 | # ------------------ 7 | # 8 | # 9 | # 10 | # FIND_PACKAGE_MESSAGE( "message for user" "find result details") 11 | # 12 | # This macro is intended to be used in FindXXX.cmake modules files. It 13 | # will print a message once for each unique find result. This is useful 14 | # for telling the user where a package was found. The first argument 15 | # specifies the name (XXX) of the package. The second argument 16 | # specifies the message to display. The third argument lists details 17 | # about the find result so that if they change the message will be 18 | # displayed again. The macro also obeys the QUIET argument to the 19 | # find_package command. 20 | # 21 | # Example: 22 | # 23 | # :: 24 | # 25 | # if(X11_FOUND) 26 | # FIND_PACKAGE_MESSAGE(X11 "Found X11: ${X11_X11_LIB}" 27 | # "[${X11_X11_LIB}][${X11_INCLUDE_DIR}]") 28 | # else() 29 | # ... 30 | # endif() 31 | 32 | function(FIND_PACKAGE_MESSAGE pkg msg details) 33 | # Avoid printing a message repeatedly for the same find result. 34 | if(NOT ${pkg}_FIND_QUIETLY) 35 | string(REPLACE "\n" "" details "${details}") 36 | set(DETAILS_VAR FIND_PACKAGE_MESSAGE_DETAILS_${pkg}) 37 | if(NOT "${details}" STREQUAL "${${DETAILS_VAR}}") 38 | # The message has not yet been printed. 39 | message(STATUS "${msg}") 40 | 41 | # Save the find details in the cache to avoid printing the same 42 | # message again. 43 | set("${DETAILS_VAR}" "${details}" 44 | CACHE INTERNAL "Details about finding ${pkg}") 45 | endif() 46 | endif() 47 | endfunction() 48 | -------------------------------------------------------------------------------- /cmake/Modules/GetGitRevisionDescription.cmake.in: -------------------------------------------------------------------------------- 1 | # 2 | # Internal file for GetGitRevisionDescription.cmake 3 | # 4 | # Requires CMake 2.6 or newer (uses the 'function' command) 5 | # 6 | # Original Author: 7 | # 2009-2010 Ryan Pavlik 8 | # http://academic.cleardefinition.com 9 | # Iowa State University HCI Graduate Program/VRAC 10 | # 11 | # Copyright Iowa State University 2009-2010. 12 | # Distributed under the Boost Software License, Version 1.0. 13 | # (See accompanying file LICENSE_1_0.txt or copy at 14 | # http://www.boost.org/LICENSE_1_0.txt) 15 | 16 | set(HEAD_HASH) 17 | 18 | file(READ "@HEAD_FILE@" HEAD_CONTENTS LIMIT 1024) 19 | 20 | string(STRIP "${HEAD_CONTENTS}" HEAD_CONTENTS) 21 | if(HEAD_CONTENTS MATCHES "ref") 22 | # named branch 23 | string(REPLACE "ref: " "" HEAD_REF "${HEAD_CONTENTS}") 24 | if(EXISTS "@GIT_DIR@/${HEAD_REF}") 25 | configure_file("@GIT_DIR@/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY) 26 | else() 27 | configure_file("@GIT_DIR@/packed-refs" "@GIT_DATA@/packed-refs" COPYONLY) 28 | file(READ "@GIT_DATA@/packed-refs" PACKED_REFS) 29 | if(${PACKED_REFS} MATCHES "([0-9a-z]*) ${HEAD_REF}") 30 | set(HEAD_HASH "${CMAKE_MATCH_1}") 31 | endif() 32 | endif() 33 | else() 34 | # detached HEAD 35 | configure_file("@GIT_DIR@/HEAD" "@GIT_DATA@/head-ref" COPYONLY) 36 | endif() 37 | 38 | if(NOT HEAD_HASH) 39 | file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024) 40 | string(STRIP "${HEAD_HASH}" HEAD_HASH) 41 | endif() 42 | -------------------------------------------------------------------------------- /docs/CONTRIBUTING-LINUX.md: -------------------------------------------------------------------------------- 1 | # CONTRIBUTING ON LINUX 2 | 3 | macOS, Ubuntu, and more generally Linux share a very similar configuration for SAI, 4 | with minor differences (for example macOS uses `brew` not `apt`). 5 | 6 | These steps show the example of Debian-based linux distributions (Ubuntu and similar). 7 | 8 | If you're on macOS, or another type of Linux distributions (such as Fedora or Arch 9 | Linux, for example), you may either slightly adapt the below instructions to your 10 | system, or refer to the Leela Zero's original compiling instructions 11 | [here](https://github.com/leela-zero/leela-zero#compiling-autogtp-andor-leela-zero). 12 | 13 | ## Compile autogtp 14 | 15 | ```Shell 16 | # Install qt5 dependencies && \ 17 | sudo apt install -y qt5-default qt5-qmake curl && \ 18 | # Compile autogtp with qmake 19 | cd ~/sai/autogtp && \ 20 | qmake -qt5 && \ 21 | make && \ 22 | # Copy sai binary in build subdirectory in the same directory as autogtp binary && \ 23 | cp ../build/sai . 24 | ``` 25 | 26 | ## Run autogtp 27 | 28 | Then, you can run AutoGTP. The possible options can be found 29 | calling from the command prompt: 30 | 31 | ```Shell 32 | ~/sai/autogtp/autogtp --help 33 | ``` 34 | 35 | To start contributing, run: 36 | 37 | ```Shell 38 | ~/sai/autogtp/autogtp --username --password -g 39 | ``` 40 | 41 | The `-g` argument is optional, you can use it to specify the number of games (n) 42 | you want to play at the same time (depending on your hardware). 43 | 44 | We suggest to use the option `-g2` (or `-g3`, `-g4` or larger) if your computer 45 | is powerful enough to play more than one game at the same time. 46 | 47 | for example (default is one game at a time): 48 | 49 | ```Shell 50 | ~/sai/autogtp/autogtp --username testTutorial --password 123456 51 | ``` 52 | -------------------------------------------------------------------------------- /docs/CONTRIBUTING-WINDOWS.md: -------------------------------------------------------------------------------- 1 | # CONTRIBUTING ON WINDOWS 2 | 3 | Either use your already downloaded pre-compiled SAI release, or 4 | if you're an experienced user, compile your own version of autogtp. 5 | 6 | Here we cover only downloaded ready to use SAI official binaries, if you 7 | want to compile autogtp by yourself, see 8 | [here](https://github.com/leela-zero/leela-zero/tree/next/autogtp#compiling-under-visual-studio---windows). 9 | 10 | ## Setup contributing 11 | 12 | In the SAI latest release you downloaded earlier, double-click on sai.hta. 13 | 14 | Authorization for this operation may be requested, if so please grant it. 15 | 16 | ## Run autogtp 17 | 18 | The possible options can be found calling from the command prompt, 19 | from your SAI's folder: 20 | 21 | ```Shell 22 | autogtp.exe --help 23 | ``` 24 | 25 | To start contributing, run: 26 | 27 | ```Shell 28 | autogtp.exe --username --password -g 29 | ``` 30 | 31 | The `-g` argument is optional, you can use it to specify the number of games (n) 32 | you want to play at the same time (depending on your hardware). 33 | 34 | We suggest to use the option `-g2` (or `-g3`, `-g4` or larger) if your computer 35 | is powerful enough to play more than one game at the same time. 36 | -------------------------------------------------------------------------------- /docs/FAQ-CHINESE.md: -------------------------------------------------------------------------------- 1 | # 常问问题 2 | 3 | 您将在下面找到有关SAI及其答案的最常见问题。 4 | 5 | ## 为什么网络不是每次都变强的 6 | 7 | 从谷歌的论文中可以发现,AZ的网络强度也是有起伏的。而且现在只是在小规模测试阶段,发现问题也是很正常的。请保持耐心。 8 | 9 | ## 为什么比较两个网络强弱时经常下十几盘就不下了 10 | 11 | 这里使用的是概率学意义上强弱,具体来说是SPRT在95%概率下任何一方有超过55%的胜率(ELO的35分),就认为有一方胜出了。谷歌的论文中是下满400盘的。唯一的区别是我们这里的Elo可能不是那么准确,网络的强弱还是可以确定的。 12 | 13 | ## 自对弈时产生的棋谱为什么下得很糟 14 | 15 | 生成自对弈棋谱时,使用的MCTS模拟次数只有3200,还加入了噪声,这是为了增加随机性,之后的训练才有进步的空间。如果用图形界面(如sabiki)加载Leela Zero,并设置好参数与之对弈,你会发现它其实表现得并不赖。 16 | 17 | ## 有些自对弈对局非常短 18 | 19 | 自对弈的增加了随机性,一旦黑棋在开始阶段选择pass,由于贴目的关系,白棋有很大概率也选择pass获胜。短对局由此产生。 20 | 21 | ## 对局结果错误 22 | 23 | Leela Zero使用Tromp-Taylor规则(详见)。虽然与中国规则一样贴7.5目,但为计算方便,并不去除死子。因此,结果与使用中国规则计算可能有所不同。不过,不去除死子并不影响模型的训练结果,因为双方会将死子自行提掉。 24 | -------------------------------------------------------------------------------- /docs/FAQ-ENGLISH.md: -------------------------------------------------------------------------------- 1 | # FAQ 2 | 3 | You will find below most common questions about SAI and their answer. 4 | 5 | ## Why doesn't the network get stronger every time 6 | 7 | AZ also had this behavior, besides we're testing our approach right now. Please be patient. 8 | 9 | ## Why only dozens of games are played when comparing two networks 10 | 11 | We use SPRT to decide if a newly trained network is better. A better network is only chosen if SPRT finds it's 95% confident that the new network has a 55% (boils down to 35 elo) win rate over the previous best network. 12 | 13 | ## Why the game generated during self-play contains quite a few bad moves 14 | 15 | The MCTS playouts of self-play games is only 3200, and with noise added (For randomness of each move thus training has something to learn from). If you load Leela Zero with Sabaki, you'll probably find it is actually not that weak. 16 | 17 | ## Very short self-play games ends with White win 18 | 19 | This is expected. 20 | 21 | Due to randomness of self-play games, once Black choose to pass at the beginning, there is a big chance for White to pass too (7.5 komi advantage for White). See issue [#198](https://github.com/leela-zero/leela-zero/issues/198) for details. 22 | 23 | ## Wrong score 24 | 25 | Leela Zero uses Tromp-Taylor rules (see [here](https://senseis.xmp.net/?TrompTaylorRules). 26 | 27 | Although its komi is 7.5 as in Chinese rule, for simplicity, Tromp-Taylor rules do not remove dead stones. 28 | 29 | Thus, the result may be different from that calcuated using Chinese rule. However, keeping dead stones does not affect training results because both players are expected to capture dead stones themselves. 30 | -------------------------------------------------------------------------------- /docs/RUN-LINUX.md: -------------------------------------------------------------------------------- 1 | # RUN SAI ON LINUX 2 | 3 | macOS, Ubuntu, and more generally Linux share a very similar configuration for SAI, 4 | with minor differences (for example macOS uses `brew` not `apt`). 5 | 6 | These steps show the example of Debian-based linux distributions (Ubuntu and similar). 7 | 8 | If you're on macOS, or another type of Linux distributions (such as Fedora or Arch 9 | Linux, for example), you may either slightly adapt the below instructions to your 10 | system, or refer to the Leela Zero's original compiling instructions 11 | [here](https://github.com/leela-zero/leela-zero#compiling-autogtp-andor-leela-zero). 12 | 13 | ## Compile SAI 14 | 15 | ### 19x19 16 | 17 | To compile the SAI binary in the build subdirectory, first test if your device is OpenCL compatible. To do that, open a shell and run: 18 | 19 | ```Shell 20 | sudo apt install clinfo && clinfo 21 | ``` 22 | 23 | If all is good, your device is compatible with SAI, so you can run this all-in-one command to download and compile SAI: 24 | 25 | ```Shell 26 | # Clone github repo && \ 27 | cd ~ && \ 28 | git clone https://github.com/sai-dev/sai && cd sai && \ 29 | git submodule update --init --recursive && \ 30 | # Install build depedencies && \ 31 | sudo apt install -y cmake g++ libboost-dev libboost-program-options-dev libboost-filesystem-dev opencl-headers ocl-icd-libopencl1 ocl-icd-opencl-dev zlib1g-dev && \ 32 | # Use a stand alone build directory to keep source dir clean && \ 33 | mkdir build && cd build && \ 34 | # Compile sai in build subdirectory with cmake && \ 35 | cmake .. && \ 36 | cmake --build . 37 | ``` 38 | 39 | Sai is installed in `~/sai`, and the sai binary is compiled and ready 40 | to use in `~/sai/build/` 41 | 42 | Optionally, you can test if your build works correctly with: 43 | 44 | ```Shell 45 | ~/sai/tests 46 | ``` 47 | 48 | ### 9x9 49 | 50 | If you'd rather play with a strong SAI 9x9 network, you can compile a 51 | SAI 9x9 executable by editing src/config.cpp. 52 | 53 | A pretty strong 9x9 network is 54 | [S1](http://sai.unich.it/networks/94619dea457de054503cec030269ce842c47055ba51e96db8fee841dfbaf05f9.gz) from the 9x9 paper, downloadable from the link. 55 | 56 | The steps to compile SAI are the same as above. 57 | 58 | ### Run SAI 59 | 60 | Then you can use the main program SAI. 61 | 62 | You have to open a shell and go to the directory with the 63 | program to run it. 64 | 65 | It will need a network to work and networks can be 66 | found on the [server](http://sai.unich.it/). But you can immediately 67 | launch, to see the options: 68 | 69 | ```Shell 70 | ~/sai/build/sai --help 71 | ``` 72 | -------------------------------------------------------------------------------- /docs/RUN-WINDOWS.md: -------------------------------------------------------------------------------- 1 | # RUN SAI ON WINDOWS 2 | 3 | Either use your already downloaded pre-compiled SAI release, or 4 | if you're an experienced user, compile your own version of SAI. 5 | 6 | Here we cover only downloaded ready to use SAI official binaries, see 7 | [Leela Zero's how to COMPILE SAI](https://github.com/leela-zero/leela-zero#example-of-compiling---windows) 8 | if you want to compile SAI by yourself, and adapt these instructions for SAI. 9 | 10 | ## Download latest SAI release 11 | 12 | Open [this page](https://github.com/sai-dev/sai/releases/) and download 13 | the latest release of SAI fitting the characteristics of your computer. 14 | 15 | Then Unzip the archive. 16 | 17 | ## Run SAI 18 | 19 | Then you can use the main program SAI. 20 | 21 | ### 19x19 22 | 23 | You have to open a Windows command prompt in the directory with the program 24 | to run it. 25 | 26 | It will need a network to work and networks can be found on the server. 27 | 28 | But you can immediately launch, to see the options: 29 | 30 | ```Shell 31 | sai.exe --help 32 | ``` 33 | 34 | ### 9x9 35 | 36 | If you'd rather play with a strong SAI 9x9 network, we provide a compiled 37 | 9x9 executable sai9x9.exe but you can also simply run sai9x9.bat and you 38 | will play agains the [S1](http://sai.unich.it/networks/94619dea457de054503cec030269ce842c47055ba51e96db8fee841dfbaf05f9.gz) 39 | network from the 9x9 paper, which is included inside the zip file. 40 | 41 | The steps to run SAI are same as above. 42 | -------------------------------------------------------------------------------- /msvc/.gitignore: -------------------------------------------------------------------------------- 1 | Debug 2 | Release 3 | CPUOnly 4 | packages 5 | .orig 6 | x64 7 | .vs 8 | *.db 9 | *.opendb 10 | *.user -------------------------------------------------------------------------------- /msvc/VS2019/cmake_build.bat: -------------------------------------------------------------------------------- 1 | set PKG_FOLDER="%cd%\msvc\packages" 2 | git submodule update --init --recursive 3 | mkdir build 4 | cd build 5 | set BLAS_HOME="..\msvc\packages\OpenBLAS.0.2.14.1\lib\native" 6 | for /F %%f in ("%features%") do set DEFINES=%DEFINES% -D%%f=1 7 | cmake -G "Visual Studio 15 2017 Win64" %DEFINES% -DCMAKE_PREFIX_PATH="%QTDIR%/lib/cmake/" -DBOOST_ROOT="C:/Libraries/boost_1_65_1" -DBOOST_LIBRARYDIR="C:/Libraries/boost_1_65_1/lib64-msvc-14.1" -DBoost_USE_STATIC_LIBS=ON -DZLIB_ROOT="%PKG_FOLDER%/zlib-msvc14-x64.1.2.11.7795/build/native" -DZLIB_LIBRARY="%PKG_FOLDER%/zlib-msvc14-x64.1.2.11.7795/build/native/zlib-msvc14-x64.targets" -DOpenCL_LIBRARY="%PKG_FOLDER%/opencl-nug.0.777.12/build/native/opencl-nug.targets" -DOpenCL_INCLUDE_DIR="%PKG_FOLDER%/opencl-nug.0.777.12/build/native/include" -DBLAS_LIBRARIES="%PKG_FOLDER%/OpenBLAS.0.2.14.1/build/native/openblas.targets" -Dgtest_force_shared_crt=ON .. 8 | cmake --build . --config Release -- /maxcpucount:1 9 | -------------------------------------------------------------------------------- /msvc/VS2019/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /msvc/VS2022/cmake_build.bat: -------------------------------------------------------------------------------- 1 | set PKG_FOLDER="%cd%\msvc\packages" 2 | git submodule update --init --recursive 3 | mkdir build 4 | cd build 5 | set BLAS_HOME="..\msvc\packages\OpenBLAS.0.2.14.1\lib\native" 6 | for /F %%f in ("%features%") do set DEFINES=%DEFINES% -D%%f=1 7 | cmake -G "Visual Studio 15 2017 Win64" %DEFINES% -DCMAKE_PREFIX_PATH="%QTDIR%/lib/cmake/" -DBOOST_ROOT="C:/Libraries/boost_1_65_1" -DBOOST_LIBRARYDIR="C:/Libraries/boost_1_65_1/lib64-msvc-14.1" -DBoost_USE_STATIC_LIBS=ON -DZLIB_ROOT="%PKG_FOLDER%/zlib-msvc14-x64.1.2.11.7795/build/native" -DZLIB_LIBRARY="%PKG_FOLDER%/zlib-msvc14-x64.1.2.11.7795/build/native/zlib-msvc14-x64.targets" -DOpenCL_LIBRARY="%PKG_FOLDER%/opencl-nug.0.777.12/build/native/opencl-nug.targets" -DOpenCL_INCLUDE_DIR="%PKG_FOLDER%/opencl-nug.0.777.12/build/native/include" -DBLAS_LIBRARIES="%PKG_FOLDER%/OpenBLAS.0.2.14.1/build/native/openblas.targets" -Dgtest_force_shared_crt=ON .. 8 | cmake --build . --config Release -- /maxcpucount:1 9 | -------------------------------------------------------------------------------- /msvc/VS2022/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /msvc/leela-zero2019.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29411.108 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sai", "VS2019\leela-zero.vcxproj", "{7B887BFE-8D2C-46CD-B139-5213434BF218}" 7 | EndProject 8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "autogtp", "VS2019\autogtp.vcxproj", "{B12702AD-ABFB-343A-A199-8E24837244A3}" 9 | EndProject 10 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sai9x9", "VS2019\leela-zero-9x9.vcxproj", "{AC6DA47C-25BD-4FFC-9202-053F48373D1C}" 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | CPUOnly|Win32 = CPUOnly|Win32 15 | CPUOnly|x64 = CPUOnly|x64 16 | Debug|Win32 = Debug|Win32 17 | Debug|x64 = Debug|x64 18 | Release|Win32 = Release|Win32 19 | Release|x64 = Release|x64 20 | EndGlobalSection 21 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 22 | {7B887BFE-8D2C-46CD-B139-5213434BF218}.CPUOnly|Win32.ActiveCfg = CPUOnly|Win32 23 | {7B887BFE-8D2C-46CD-B139-5213434BF218}.CPUOnly|Win32.Build.0 = CPUOnly|Win32 24 | {7B887BFE-8D2C-46CD-B139-5213434BF218}.CPUOnly|x64.ActiveCfg = CPUOnly|x64 25 | {7B887BFE-8D2C-46CD-B139-5213434BF218}.CPUOnly|x64.Build.0 = CPUOnly|x64 26 | {7B887BFE-8D2C-46CD-B139-5213434BF218}.Debug|Win32.ActiveCfg = Debug|Win32 27 | {7B887BFE-8D2C-46CD-B139-5213434BF218}.Debug|Win32.Build.0 = Debug|Win32 28 | {7B887BFE-8D2C-46CD-B139-5213434BF218}.Debug|x64.ActiveCfg = Debug|x64 29 | {7B887BFE-8D2C-46CD-B139-5213434BF218}.Debug|x64.Build.0 = Debug|x64 30 | {7B887BFE-8D2C-46CD-B139-5213434BF218}.Release|Win32.ActiveCfg = Release|Win32 31 | {7B887BFE-8D2C-46CD-B139-5213434BF218}.Release|Win32.Build.0 = Release|Win32 32 | {7B887BFE-8D2C-46CD-B139-5213434BF218}.Release|x64.ActiveCfg = Release|x64 33 | {7B887BFE-8D2C-46CD-B139-5213434BF218}.Release|x64.Build.0 = Release|x64 34 | {B12702AD-ABFB-343A-A199-8E24837244A3}.CPUOnly|Win32.ActiveCfg = CPUOnly|Win32 35 | {B12702AD-ABFB-343A-A199-8E24837244A3}.CPUOnly|Win32.Build.0 = CPUOnly|Win32 36 | {B12702AD-ABFB-343A-A199-8E24837244A3}.CPUOnly|x64.ActiveCfg = CPUOnly|x64 37 | {B12702AD-ABFB-343A-A199-8E24837244A3}.CPUOnly|x64.Build.0 = CPUOnly|x64 38 | {B12702AD-ABFB-343A-A199-8E24837244A3}.Debug|Win32.ActiveCfg = Debug|Win32 39 | {B12702AD-ABFB-343A-A199-8E24837244A3}.Debug|Win32.Build.0 = Debug|Win32 40 | {B12702AD-ABFB-343A-A199-8E24837244A3}.Debug|x64.ActiveCfg = Debug|x64 41 | {B12702AD-ABFB-343A-A199-8E24837244A3}.Debug|x64.Build.0 = Debug|x64 42 | {B12702AD-ABFB-343A-A199-8E24837244A3}.Release|Win32.ActiveCfg = Release|Win32 43 | {B12702AD-ABFB-343A-A199-8E24837244A3}.Release|Win32.Build.0 = Release|Win32 44 | {B12702AD-ABFB-343A-A199-8E24837244A3}.Release|x64.ActiveCfg = Release|x64 45 | {B12702AD-ABFB-343A-A199-8E24837244A3}.Release|x64.Build.0 = Release|x64 46 | {AC6DA47C-25BD-4FFC-9202-053F48373D1C}.CPUOnly|Win32.ActiveCfg = CPUOnly|Win32 47 | {AC6DA47C-25BD-4FFC-9202-053F48373D1C}.CPUOnly|Win32.Build.0 = CPUOnly|Win32 48 | {AC6DA47C-25BD-4FFC-9202-053F48373D1C}.CPUOnly|x64.ActiveCfg = CPUOnly|x64 49 | {AC6DA47C-25BD-4FFC-9202-053F48373D1C}.CPUOnly|x64.Build.0 = CPUOnly|x64 50 | {AC6DA47C-25BD-4FFC-9202-053F48373D1C}.Debug|Win32.ActiveCfg = Debug|Win32 51 | {AC6DA47C-25BD-4FFC-9202-053F48373D1C}.Debug|Win32.Build.0 = Debug|Win32 52 | {AC6DA47C-25BD-4FFC-9202-053F48373D1C}.Debug|x64.ActiveCfg = Debug|x64 53 | {AC6DA47C-25BD-4FFC-9202-053F48373D1C}.Debug|x64.Build.0 = Debug|x64 54 | {AC6DA47C-25BD-4FFC-9202-053F48373D1C}.Release|Win32.ActiveCfg = Release|Win32 55 | {AC6DA47C-25BD-4FFC-9202-053F48373D1C}.Release|Win32.Build.0 = Release|Win32 56 | {AC6DA47C-25BD-4FFC-9202-053F48373D1C}.Release|x64.ActiveCfg = Release|x64 57 | {AC6DA47C-25BD-4FFC-9202-053F48373D1C}.Release|x64.Build.0 = Release|x64 58 | EndGlobalSection 59 | GlobalSection(SolutionProperties) = preSolution 60 | HideSolutionNode = FALSE 61 | EndGlobalSection 62 | GlobalSection(ExtensibilityGlobals) = postSolution 63 | Qt5Version = $(DefaultQtVersion) 64 | SolutionGuid = {D4C31DFC-30DA-4030-9A6D-70F1E6851A81} 65 | EndGlobalSection 66 | EndGlobal 67 | -------------------------------------------------------------------------------- /msvc/sai.hta: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | Insert Parameters for SAI 8 | 50 | 51 | 52 |

Insert Parameters for Launching SAI

53 |
54 |

Computername: 

55 |

Password: 

56 |

Optional Parameters: 

57 | 58 |

59 |
60 | 61 | -------------------------------------------------------------------------------- /msvc/sai9x9.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | sai9x9.exe -w 94619dea457de054503cec030269ce842c47055ba51e96db8fee841dfbaf05f9.gz --noponder -p 0 -v 1000 --komi 7.5 --lambda 0.5 -r 5 -t 6 --batchsize 5 --nrsymm --restrict_tt %1 %2 %3 %4 %5 %6 %7 %8 %9 3 | -------------------------------------------------------------------------------- /src/CPUPipe.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of SAI, which is a fork of Leela Zero. 3 | Copyright (C) 2017-2018 Junhee Yoo and contributors 4 | Copyright (C) 2019 SAI Team 5 | 6 | SAI is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SAI is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SAI. If not, see . 18 | 19 | Additional permission under GNU GPL version 3 section 7 20 | 21 | If you modify this Program, or any covered work, by linking or 22 | combining it with NVIDIA Corporation's libraries from the 23 | NVIDIA CUDA Toolkit and/or the NVIDIA CUDA Deep Neural 24 | Network library and/or the NVIDIA TensorRT inference library 25 | (or a modified version of those libraries), containing parts covered 26 | by the terms of the respective license agreement, the licensors of 27 | this Program grant you additional permission to convey the resulting 28 | work. 29 | */ 30 | 31 | #ifndef CPUPIPE_H_INCLUDED 32 | #define CPUPIPE_H_INCLUDED 33 | #include "config.h" 34 | 35 | #include 36 | #include 37 | 38 | #include "ForwardPipe.h" 39 | 40 | class CPUPipe : public ForwardPipe { 41 | public: 42 | virtual void initialize(const int channels); 43 | virtual void forward(const std::vector& input, 44 | std::vector& output_pol, 45 | std::vector& output_val); 46 | 47 | virtual void push_weights(unsigned int filter_size, 48 | unsigned int channels, 49 | unsigned int outputs, 50 | std::shared_ptr weights); 51 | private: 52 | void winograd_transform_in(const std::vector& in, 53 | std::vector& V, 54 | const int C); 55 | 56 | void winograd_sgemm(const std::vector& U, 57 | const std::vector& V, 58 | std::vector& M, 59 | const int C, const int K); 60 | 61 | void winograd_transform_out(const std::vector& M, 62 | std::vector& Y, 63 | const int K); 64 | 65 | void winograd_convolve3(const int outputs, 66 | const std::vector& input, 67 | const std::vector& U, 68 | std::vector& V, 69 | std::vector& M, 70 | std::vector& output); 71 | 72 | 73 | int m_input_channels; 74 | 75 | // Input + residual block tower 76 | std::shared_ptr m_weights; 77 | }; 78 | #endif 79 | -------------------------------------------------------------------------------- /src/FastState.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of SAI, which is a fork of Leela Zero. 3 | Copyright (C) 2017-2019 Gian-Carlo Pascutto and contributors 4 | Copyright (C) 2018-2019 SAI Team 5 | 6 | SAI is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SAI is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SAI. If not, see . 18 | 19 | Additional permission under GNU GPL version 3 section 7 20 | 21 | If you modify this Program, or any covered work, by linking or 22 | combining it with NVIDIA Corporation's libraries from the 23 | NVIDIA CUDA Toolkit and/or the NVIDIA CUDA Deep Neural 24 | Network library and/or the NVIDIA TensorRT inference library 25 | (or a modified version of those libraries), containing parts covered 26 | by the terms of the respective license agreement, the licensors of 27 | this Program grant you additional permission to convey the resulting 28 | work. 29 | */ 30 | 31 | #ifndef FASTSTATE_H_INCLUDED 32 | #define FASTSTATE_H_INCLUDED 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | #include "FullBoard.h" 41 | 42 | class FastState { 43 | public: 44 | // Order of enum below is reflected in the bitset: do not change it! 45 | enum : char 46 | { 47 | RANDOM, // chosen move is not the one with the highest LCB 48 | BLUNDER, // chosen move is a blunder (win rate drop >= cfg_blunder_thr) 49 | NOTPOL1ST, // chosen move is not the one with the highest policy 50 | 51 | NUM_FLAGS // must be last 52 | }; 53 | 54 | typedef std::bitset move_flags_t; 55 | 56 | void init_game(int size, float komi); 57 | void reset_game(); 58 | void reset_board(); 59 | 60 | bool is_move_legal(int color, int vertex) const; 61 | 62 | void set_komi(float komi); 63 | void add_komi(float delta); 64 | float get_komi() const; 65 | void set_handicap(int hcap); 66 | int get_handicap() const; 67 | float get_komi_adj() const { return get_komi() + get_handicap(); } 68 | int get_passes() const; 69 | int get_to_move() const; 70 | void set_to_move(int tomove); 71 | void set_passes(int val); 72 | void increment_passes(); 73 | 74 | float final_score() const; 75 | std::uint64_t get_symmetry_hash(int symmetry) const; 76 | 77 | size_t get_movenum() const; 78 | int get_last_move() const; 79 | void display_state(); 80 | void display_legal(int color, bool gtp_std = false); 81 | std::string move_to_text(int move); 82 | 83 | void reset_comment_data(); 84 | void set_last_move_flags(const move_flags_t & flags); 85 | bool is_blunder() const { return m_last_move_flags[BLUNDER]; }; 86 | bool is_random() const { return m_last_move_flags[RANDOM]; }; 87 | bool is_policy_1st() const { return !m_last_move_flags[NOTPOL1ST]; }; 88 | std::string flags_to_text() const { return m_last_move_flags.to_string(); } 89 | 90 | size_t get_randcount() const { return m_randcount; } 91 | void inc_randcount() { ++m_randcount; } 92 | 93 | void init_allowed_blunders(); 94 | bool is_blunder_allowed() const; 95 | int get_allowed_blunders() const; 96 | 97 | bool is_symmetry_invariant(const int symmetry) const; 98 | 99 | void play_move(int vertex); 100 | void play_move(int color, int vertex); 101 | 102 | FullBoard board; 103 | 104 | float get_alpkt(float alpha) const { 105 | return (board.black_to_move() ? alpha : -alpha) - get_komi_adj(); 106 | } 107 | 108 | private: 109 | float m_komi; 110 | int m_handicap; 111 | int m_passes; 112 | int m_komove; 113 | size_t m_movenum; 114 | int m_lastmove; 115 | 116 | // the flags attached to the last chosen move 117 | move_flags_t m_last_move_flags; 118 | 119 | // number of moves chosen randomly until now 120 | size_t m_randcount; 121 | 122 | // keeps count of the number of blunders we are 123 | // still allowed to play; -1 means no limit 124 | int m_allowed_blunders = -1; 125 | 126 | protected: 127 | void set_movenum(size_t movenum); 128 | }; 129 | 130 | #endif 131 | -------------------------------------------------------------------------------- /src/ForwardPipe.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of SAI, which is a fork of Leela Zero. 3 | Copyright (C) 2018-2019 Junhee Yoo and contributors 4 | Copyright (C) 2019 SAI Team 5 | 6 | SAI is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SAI is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SAI. If not, see . 18 | 19 | Additional permission under GNU GPL version 3 section 7 20 | 21 | If you modify this Program, or any covered work, by linking or 22 | combining it with NVIDIA Corporation's libraries from the 23 | NVIDIA CUDA Toolkit and/or the NVIDIA CUDA Deep Neural 24 | Network library and/or the NVIDIA TensorRT inference library 25 | (or a modified version of those libraries), containing parts covered 26 | by the terms of the respective license agreement, the licensors of 27 | this Program grant you additional permission to convey the resulting 28 | work. 29 | */ 30 | 31 | #ifndef FORWARDPIPE_H_INCLUDED 32 | #define FORWARDPIPE_H_INCLUDED 33 | 34 | #include 35 | #include 36 | 37 | #include "config.h" 38 | 39 | class ForwardPipe { 40 | public: 41 | class ForwardPipeWeights { 42 | public: 43 | // Input + residual block tower 44 | std::vector> m_conv_weights; 45 | std::vector> m_conv_biases; 46 | std::vector> m_batchnorm_means; 47 | std::vector> m_batchnorm_stddevs; 48 | 49 | // Policy head 50 | std::vector> m_conv_pol_w; // channels*policy_outputs 51 | std::vector> m_conv_pol_b; // policy_outputs 52 | std::vector> m_bn_pol_w1; // policy_outputs 53 | std::vector> m_bn_pol_w2; // policy_outputs 54 | 55 | // Value head 56 | std::vector m_conv_val_w; // channels*val_outputs 57 | std::vector m_conv_val_b; // val_outputs 58 | std::vector m_bn_val_w1; 59 | std::vector m_bn_val_w2; 60 | 61 | std::vector m_conv_val_pool_w; // channels*val_outputs 62 | std::vector m_conv_val_pool_b; // val_outputs 63 | std::vector m_bn_val_pool_w1; 64 | std::vector m_bn_val_pool_w2; 65 | }; 66 | 67 | virtual ~ForwardPipe() = default; 68 | 69 | virtual void initialize(const int channels) = 0; 70 | virtual bool needs_autodetect() { return false; }; 71 | virtual void forward(const std::vector& input, 72 | std::vector& output_pol, 73 | std::vector& output_val) = 0; 74 | virtual void push_weights(unsigned int filter_size, 75 | unsigned int channels, 76 | unsigned int outputs, 77 | std::shared_ptr weights) = 0; 78 | 79 | virtual void drain() {} 80 | virtual void resume() {} 81 | }; 82 | 83 | #endif 84 | -------------------------------------------------------------------------------- /src/FullBoard.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of SAI, which is a fork of Leela Zero. 3 | Copyright (C) 2017-2019 Gian-Carlo Pascutto and contributors 4 | Copyright (C) 2018-2019 SAI Team 5 | 6 | SAI is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SAI is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SAI. If not, see . 18 | 19 | Additional permission under GNU GPL version 3 section 7 20 | 21 | If you modify this Program, or any covered work, by linking or 22 | combining it with NVIDIA Corporation's libraries from the 23 | NVIDIA CUDA Toolkit and/or the NVIDIA CUDA Deep Neural 24 | Network library and/or the NVIDIA TensorRT inference library 25 | (or a modified version of those libraries), containing parts covered 26 | by the terms of the respective license agreement, the licensors of 27 | this Program grant you additional permission to convey the resulting 28 | work. 29 | */ 30 | 31 | #ifndef FULLBOARD_H_INCLUDED 32 | #define FULLBOARD_H_INCLUDED 33 | 34 | #include "config.h" 35 | #include 36 | #include "FastBoard.h" 37 | 38 | class FullBoard : public FastBoard { 39 | public: 40 | int remove_string(int i); 41 | int update_board(const int color, const int i); 42 | 43 | std::uint64_t get_hash() const; 44 | std::uint64_t get_ko_hash() const; 45 | void set_to_move(int tomove); 46 | 47 | void reset_board(int size); 48 | void display_board(int lastmove = -1) const; 49 | bool remove_dead_stones(const FullBoard & tt_endboard); 50 | 51 | bool last_forced() const { return m_lastforced; } 52 | 53 | std::uint64_t calc_hash(int komove = NO_VERTEX) const; 54 | std::uint64_t calc_symmetry_hash(int komove, int symmetry) const; 55 | std::uint64_t calc_ko_hash() const; 56 | 57 | std::uint64_t m_hash; 58 | std::uint64_t m_ko_hash; 59 | 60 | private: 61 | template 62 | std::uint64_t calc_hash(int komove, Function transform) const; 63 | bool m_lastforced{false}; 64 | }; 65 | 66 | #endif 67 | -------------------------------------------------------------------------------- /src/GameState.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of SAI, which is a fork of Leela Zero. 3 | Copyright (C) 2017-2019 Gian-Carlo Pascutto and contributors 4 | Copyright (C) 2018-2019 SAI Team 5 | 6 | SAI is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SAI is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SAI. If not, see . 18 | 19 | Additional permission under GNU GPL version 3 section 7 20 | 21 | If you modify this Program, or any covered work, by linking or 22 | combining it with NVIDIA Corporation's libraries from the 23 | NVIDIA CUDA Toolkit and/or the NVIDIA CUDA Deep Neural 24 | Network library and/or the NVIDIA TensorRT inference library 25 | (or a modified version of those libraries), containing parts covered 26 | by the terms of the respective license agreement, the licensors of 27 | this Program grant you additional permission to convey the resulting 28 | work. 29 | */ 30 | 31 | #ifndef GAMESTATE_H_INCLUDED 32 | #define GAMESTATE_H_INCLUDED 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | #include "FastState.h" 40 | #include "FullBoard.h" 41 | #include "KoState.h" 42 | #include "TimeControl.h" 43 | 44 | class Network; 45 | 46 | class GameState : public KoState { 47 | public: 48 | explicit GameState() = default; 49 | explicit GameState(const KoState* rhs) { 50 | // Copy in fields from base class. 51 | *(static_cast(this)) = *rhs; 52 | anchor_game_history(); 53 | } 54 | void init_game(int size, float komi, bool value_head_sai = true); 55 | void reset_game(); 56 | bool set_fixed_handicap(int stones); 57 | int set_fixed_handicap_2(int stones); 58 | void place_free_handicap(int stones, Network & network); 59 | void anchor_game_history(); 60 | 61 | void rewind(); /* undo infinite */ 62 | bool undo_move(); 63 | bool forward_move(); 64 | std::shared_ptr get_past_state(int moves_ago) const; 65 | const FullBoard& get_past_board(int moves_ago) const; 66 | const std::vector>& get_game_history() const; 67 | 68 | void play_move(int vertex); 69 | void play_move(int color, int vertex); 70 | bool play_textmove(std::string color, const std::string& vertex); 71 | 72 | void start_clock(int color); 73 | void stop_clock(int color); 74 | const TimeControl& get_timecontrol() const; 75 | void set_timecontrol(const TimeControl& timecontrol); 76 | void set_timecontrol(int maintime, int byotime, int byostones, 77 | int byoperiods); 78 | void adjust_time(int color, int time, int stones); 79 | 80 | void display_state(); 81 | bool has_resigned() const; 82 | int who_resigned() const; 83 | StateEval get_state_eval() const; 84 | void set_state_eval(const StateEval& ev); 85 | // void copy_last_rnd_move_num (); 86 | std::string eval_comment(bool print_header = false) const; 87 | bool score_agreed() const; 88 | std::pair get_accepted_scores() const { return m_acceptedscore; } 89 | float get_final_accepted_score() const; 90 | void update_accepted_score(std::tuple node_stats, bool switch_player = false); 91 | bool is_cpu_color() const; 92 | void set_cpu_color(int which_color); 93 | std::pair get_last_think() const; 94 | void set_last_think(float alpkt) { 95 | m_last_think_alpkt = alpkt; 96 | m_last_think_movenum = get_movenum(); 97 | } 98 | float get_opp_avgloss() const; 99 | void add_opp_ptsloss(float alpkt_new); 100 | 101 | private: 102 | bool valid_handicap(int stones); 103 | 104 | std::vector> game_history; 105 | TimeControl m_timecontrol; 106 | int m_resigned{FastBoard::EMPTY}; 107 | std::pair m_acceptedscore = {-1 * NUM_INTERSECTIONS, NUM_INTERSECTIONS}; 108 | int m_cpu_color{FastBoard::EMPTY}; 109 | int m_last_think_movenum{-1}; 110 | float m_last_think_alpkt{0.0f}; 111 | int m_opp_movenum{0}; 112 | float m_opp_lostpts{0.0f}; 113 | }; 114 | 115 | #endif 116 | -------------------------------------------------------------------------------- /src/Im2Col.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of SAI, which is a fork of Leela Zero. 3 | Copyright (C) 2017-2019 Gian-Carlo Pascutto and contributors 4 | 5 | SAI is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | SAI is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with SAI. If not, see . 17 | 18 | Additional permission under GNU GPL version 3 section 7 19 | 20 | If you modify this Program, or any covered work, by linking or 21 | combining it with NVIDIA Corporation's libraries from the 22 | NVIDIA CUDA Toolkit and/or the NVIDIA CUDA Deep Neural 23 | Network library and/or the NVIDIA TensorRT inference library 24 | (or a modified version of those libraries), containing parts covered 25 | by the terms of the respective license agreement, the licensors of 26 | this Program grant you additional permission to convey the resulting 27 | work. 28 | */ 29 | 30 | #ifndef IM2COL_H_INCLUDED 31 | #define IM2COL_H_INCLUDED 32 | 33 | #include 34 | #include 35 | #include 36 | 37 | template 38 | void im2col(const int channels, 39 | const std::vector& input, 40 | std::vector& output) { 41 | constexpr unsigned int height = BOARD_SIZE; 42 | constexpr unsigned int width = BOARD_SIZE; 43 | 44 | constexpr int pad = (filter_size / 2); 45 | constexpr unsigned int output_h = height + 2 * pad - filter_size + 1; 46 | constexpr unsigned int output_w = width + 2 * pad - filter_size + 1; 47 | 48 | const float* data_im = input.data(); 49 | float* data_col = output.data(); 50 | 51 | for (int channel = channels; channel--; data_im += NUM_INTERSECTIONS) { 52 | for (unsigned int kernel_row = 0; kernel_row < filter_size; kernel_row++) { 53 | for (unsigned int kernel_col = 0; kernel_col < filter_size; kernel_col++) { 54 | int input_row = -pad + kernel_row; 55 | for (int output_rows = output_h; output_rows; output_rows--) { 56 | if (unsigned(input_row) < height) { 57 | int input_col = -pad + kernel_col; 58 | for (int output_col = output_w; output_col; output_col--) { 59 | if (unsigned(input_col) < width) { 60 | *(data_col++) = 61 | data_im[input_row * width + input_col]; 62 | } else { 63 | *(data_col++) = 0; 64 | } 65 | input_col++; 66 | } 67 | } else { 68 | for (int output_cols = output_w; output_cols; output_cols--) { 69 | *(data_col++) = 0; 70 | } 71 | } 72 | input_row++; 73 | } 74 | } 75 | } 76 | } 77 | } 78 | 79 | template <> 80 | void im2col<1>(const int channels, 81 | const std::vector& input, 82 | std::vector& output) { 83 | auto outSize = size_t{channels * static_cast(NUM_INTERSECTIONS)}; 84 | assert(output.size() == outSize); 85 | std::copy(begin(input), begin(input) + outSize, begin(output)); 86 | } 87 | 88 | #endif 89 | -------------------------------------------------------------------------------- /src/KoState.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of SAI, which is a fork of Leela Zero. 3 | Copyright (C) 2017-2019 Gian-Carlo Pascutto and contributors 4 | Copyright (C) 2018-2019 SAI Team 5 | 6 | SAI is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SAI is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SAI. If not, see . 18 | 19 | Additional permission under GNU GPL version 3 section 7 20 | 21 | If you modify this Program, or any covered work, by linking or 22 | combining it with NVIDIA Corporation's libraries from the 23 | NVIDIA CUDA Toolkit and/or the NVIDIA CUDA Deep Neural 24 | Network library and/or the NVIDIA TensorRT inference library 25 | (or a modified version of those libraries), containing parts covered 26 | by the terms of the respective license agreement, the licensors of 27 | this Program grant you additional permission to convey the resulting 28 | work. 29 | */ 30 | 31 | #include "config.h" 32 | #include "KoState.h" 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | #include "FastBoard.h" 40 | #include "FastState.h" 41 | #include "FullBoard.h" 42 | 43 | void KoState::init_game(int size, float komi) { 44 | assert(size <= BOARD_SIZE); 45 | 46 | FastState::init_game(size, komi); 47 | 48 | m_ko_hash_history.clear(); 49 | m_ko_hash_history.emplace_back(board.get_ko_hash()); 50 | } 51 | 52 | bool KoState::superko() const { 53 | auto first = crbegin(m_ko_hash_history); 54 | auto last = crend(m_ko_hash_history); 55 | 56 | auto res = std::find(++first, last, board.get_ko_hash()); 57 | 58 | return (res != last); 59 | } 60 | 61 | void KoState::reset_game() { 62 | FastState::reset_game(); 63 | 64 | m_ko_hash_history.clear(); 65 | m_ko_hash_history.push_back(board.get_ko_hash()); 66 | const StateEval void_ev; 67 | set_state_eval(void_ev); 68 | } 69 | 70 | void KoState::play_move(int vertex) { 71 | play_move(get_to_move(), vertex); 72 | } 73 | 74 | void KoState::play_move(int color, int vertex) { 75 | if (vertex != FastBoard::RESIGN) { 76 | FastState::play_move(color, vertex); 77 | } 78 | m_ko_hash_history.push_back(board.get_ko_hash()); 79 | } 80 | 81 | StateEval KoState::get_state_eval() const { 82 | return m_ev; 83 | } 84 | 85 | void KoState::set_state_eval(const StateEval& ev) { 86 | m_ev = ev; 87 | } 88 | -------------------------------------------------------------------------------- /src/KoState.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of SAI, which is a fork of Leela Zero. 3 | Copyright (C) 2017-2019 Gian-Carlo Pascutto and contributors 4 | Copyright (C) 2018-2019 SAI Team 5 | 6 | SAI is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SAI is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SAI. If not, see . 18 | 19 | Additional permission under GNU GPL version 3 section 7 20 | 21 | If you modify this Program, or any covered work, by linking or 22 | combining it with NVIDIA Corporation's libraries from the 23 | NVIDIA CUDA Toolkit and/or the NVIDIA CUDA Deep Neural 24 | Network library and/or the NVIDIA TensorRT inference library 25 | (or a modified version of those libraries), containing parts covered 26 | by the terms of the respective license agreement, the licensors of 27 | this Program grant you additional permission to convey the resulting 28 | work. 29 | */ 30 | 31 | #ifndef KOSTATE_H_INCLUDED 32 | #define KOSTATE_H_INCLUDED 33 | 34 | #include "config.h" 35 | 36 | #include 37 | #include 38 | 39 | #include "FastState.h" 40 | #include "FullBoard.h" 41 | 42 | struct StateEval { 43 | size_t visits = 0; 44 | float alpkt = 0.0f; 45 | float pi = 0.5f; 46 | float agent_x_lambda = 0.0f; 47 | float agent_x_mu = 0.0f; 48 | float agent_eval_avg = 0.5f; 49 | float alpkt_tree = 0.0f; 50 | float beta_tree = 1.0f; 51 | 52 | StateEval(int visits, float alpkt, float beta, float pi, 53 | float agent_x_lambda, float agent_x_mu, 54 | float agent_eval_avg, 55 | float alpkt_tree) 56 | : visits(visits), alpkt(alpkt), pi(pi), 57 | agent_x_lambda(agent_x_lambda), 58 | agent_x_mu(agent_x_mu), agent_eval_avg(agent_eval_avg), 59 | alpkt_tree(alpkt_tree), beta_tree(beta) 60 | {} 61 | 62 | StateEval() {} 63 | }; 64 | 65 | class KoState : public FastState { 66 | public: 67 | void init_game(int size, float komi); 68 | bool superko() const; 69 | void reset_game(); 70 | 71 | StateEval get_state_eval() const; 72 | void set_state_eval(const StateEval& ev); 73 | 74 | void play_move(int vertex); 75 | void play_move(int color, int vertex); 76 | 77 | private: 78 | std::vector m_ko_hash_history; 79 | StateEval m_ev; 80 | }; 81 | 82 | #endif 83 | -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | THE_OS := $(shell uname -s) 2 | 3 | default: 4 | @echo "Detected OS: ${THE_OS}" 5 | $(MAKE) CC=gcc CXX=g++ \ 6 | CXXFLAGS='$(CXXFLAGS) -Wall -Wextra -Wno-ignored-attributes -Wno-deprecated-copy -pipe -O3 -g -ffast-math -flto -march=native -std=c++14 -DNDEBUG' \ 7 | LDFLAGS='$(LDFLAGS) -flto -g' \ 8 | sai 9 | 10 | debug: 11 | @echo "Detected OS: ${THE_OS}" 12 | $(MAKE) CC=gcc CXX=g++ \ 13 | CXXFLAGS='$(CXXFLAGS) -Wall -Wextra -Wno-ignored-attributes -Wno-deprecated-copy -pipe -Og -g -std=c++14' \ 14 | LDFLAGS='$(LDFLAGS) -g' \ 15 | sai 16 | 17 | clang: 18 | @echo "Detected OS: ${THE_OS}" 19 | $(MAKE) CC=clang CXX=clang++ \ 20 | CXXFLAGS='$(CXXFLAGS) -Wall -Wextra -Wno-missing-braces -O3 -ffast-math -flto -march=native -std=c++14 -DNDEBUG' \ 21 | LDFLAGS='$(LDFLAGS) -flto -fuse-linker-plugin' \ 22 | sai 23 | 24 | DYNAMIC_LIBS = -lboost_system -lboost_filesystem -lboost_program_options -lpthread -lz 25 | LIBS = 26 | 27 | ifeq ($(THE_OS),Linux) 28 | # for Linux with OpenBLAS 29 | CXXFLAGS += -I/usr/include/openblas -I./Eigen 30 | DYNAMIC_LIBS += -lopenblas 31 | DYNAMIC_LIBS += -lOpenCL 32 | endif 33 | ifeq ($(THE_OS),Darwin) 34 | # for macOS (comment out the Linux part) 35 | LIBS += -framework Accelerate 36 | LIBS += -framework OpenCL 37 | CXXFLAGS += -I./Eigen 38 | CXXFLAGS += -I/System/Library/Frameworks/Accelerate.framework/Versions/Current/Headers 39 | endif 40 | 41 | # for MKL instead of OpenBLAS 42 | #DYNAMIC_LIBS += -lmkl_rt 43 | #CXXFLAGS += -I/opt/intel/mkl/include 44 | #LDFLAGS += -L/opt/intel/mkl/lib/intel64/ 45 | 46 | CXXFLAGS += -I. 47 | CPPFLAGS += -MD -MP 48 | 49 | sources = Network.cpp FullBoard.cpp KoState.cpp Training.cpp \ 50 | TimeControl.cpp UCTSearch.cpp GameState.cpp Leela.cpp \ 51 | SGFParser.cpp Timing.cpp Utils.cpp FastBoard.cpp SHA256.cpp \ 52 | SGFTree.cpp Zobrist.cpp FastState.cpp GTP.cpp Random.cpp \ 53 | SMP.cpp UCTNode.cpp UCTNodePointer.cpp UCTNodeRoot.cpp \ 54 | OpenCL.cpp OpenCLScheduler.cpp NNCache.cpp Tuner.cpp CPUPipe.cpp 55 | 56 | objects = $(sources:.cpp=.o) 57 | deps = $(sources:%.cpp=%.d) 58 | 59 | -include $(deps) 60 | 61 | %.o: %.cpp 62 | $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $< 63 | 64 | # For compatibility with Leela Zero 65 | leelaz: sai 66 | 67 | sai: $(objects) 68 | $(CXX) $(LDFLAGS) -o $@ $^ $(LIBS) $(DYNAMIC_LIBS) 69 | 70 | clean: 71 | -$(RM) sai $(objects) $(deps) 72 | 73 | .PHONY: clean default debug clang 74 | -------------------------------------------------------------------------------- /src/NNCache.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of SAI, which is a fork of Leela Zero. 3 | Copyright (C) 2017-2019 Michael O and contributors 4 | 5 | SAI is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | SAI is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with SAI. If not, see . 17 | 18 | Additional permission under GNU GPL version 3 section 7 19 | 20 | If you modify this Program, or any covered work, by linking or 21 | combining it with NVIDIA Corporation's libraries from the 22 | NVIDIA CUDA Toolkit and/or the NVIDIA CUDA Deep Neural 23 | Network library and/or the NVIDIA TensorRT inference library 24 | (or a modified version of those libraries), containing parts covered 25 | by the terms of the respective license agreement, the licensors of 26 | this Program grant you additional permission to convey the resulting 27 | work. 28 | */ 29 | 30 | #include "config.h" 31 | #include 32 | #include 33 | 34 | #include "NNCache.h" 35 | #include "Utils.h" 36 | #include "UCTSearch.h" 37 | #include "GTP.h" 38 | 39 | const int NNCache::MAX_CACHE_COUNT; 40 | const int NNCache::MIN_CACHE_COUNT; 41 | const size_t NNCache::ENTRY_SIZE; 42 | 43 | NNCache::NNCache(int size) : m_size(size) {} 44 | 45 | bool NNCache::lookup(std::uint64_t hash, Netresult & result) { 46 | std::lock_guard lock(m_mutex); 47 | ++m_lookups; 48 | 49 | auto iter = m_cache.find(hash); 50 | if (iter == m_cache.end()) { 51 | return false; // Not found. 52 | } 53 | 54 | const auto& entry = iter->second; 55 | 56 | // Found it. 57 | ++m_hits; 58 | result = entry->result; 59 | return true; 60 | } 61 | 62 | void NNCache::insert(std::uint64_t hash, 63 | const Netresult& result) { 64 | std::lock_guard lock(m_mutex); 65 | 66 | if (m_cache.find(hash) != m_cache.end()) { 67 | return; // Already in the cache. 68 | } 69 | 70 | m_cache.emplace(hash, std::make_unique(result)); 71 | m_order.push_back(hash); 72 | ++m_inserts; 73 | 74 | // If the cache is too large, remove the oldest entry. 75 | if (m_order.size() > m_size) { 76 | m_cache.erase(m_order.front()); 77 | m_order.pop_front(); 78 | } 79 | } 80 | 81 | void NNCache::resize(int size) { 82 | m_size = size; 83 | while (m_order.size() > m_size) { 84 | m_cache.erase(m_order.front()); 85 | m_order.pop_front(); 86 | } 87 | } 88 | 89 | void NNCache::clear() { 90 | m_cache.clear(); 91 | m_order.clear(); 92 | } 93 | 94 | void NNCache::set_size_from_playouts(int max_playouts) { 95 | // cache hits are generally from last several moves so setting cache 96 | // size based on playouts increases the hit rate while balancing memory 97 | // usage for low playout instances. 150'000 cache entries is ~208 MiB 98 | constexpr auto num_cache_moves = 3; 99 | auto max_playouts_per_move = 100 | std::min(max_playouts, 101 | UCTSearch::UNLIMITED_PLAYOUTS / num_cache_moves); 102 | auto max_size = num_cache_moves * max_playouts_per_move; 103 | max_size = std::min(MAX_CACHE_COUNT, std::max(MIN_CACHE_COUNT, max_size)); 104 | resize(max_size); 105 | } 106 | 107 | void NNCache::dump_stats() { 108 | Utils::myprintf( 109 | "NNCache: %d/%d hits/lookups = %.1f%% hitrate, %d inserts, %u size\n", 110 | m_hits, m_lookups, 100. * m_hits / (m_lookups + 1), 111 | m_inserts, m_cache.size()); 112 | } 113 | 114 | size_t NNCache::get_estimated_size() { 115 | return m_order.size() * NNCache::ENTRY_SIZE; 116 | } 117 | -------------------------------------------------------------------------------- /src/NNCache.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of SAI, which is a fork of Leela Zero. 3 | Copyright (C) 2017-2019 Michael O and contributors 4 | 5 | SAI is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | SAI is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with SAI. If not, see . 17 | 18 | Additional permission under GNU GPL version 3 section 7 19 | 20 | If you modify this Program, or any covered work, by linking or 21 | combining it with NVIDIA Corporation's libraries from the 22 | NVIDIA CUDA Toolkit and/or the NVIDIA CUDA Deep Neural 23 | Network library and/or the NVIDIA TensorRT inference library 24 | (or a modified version of those libraries), containing parts covered 25 | by the terms of the respective license agreement, the licensors of 26 | this Program grant you additional permission to convey the resulting 27 | work. 28 | */ 29 | 30 | #ifndef NNCACHE_H_INCLUDED 31 | #define NNCACHE_H_INCLUDED 32 | 33 | #include "config.h" 34 | 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | 41 | class NNCache { 42 | public: 43 | 44 | // Maximum size of the cache in number of items. 45 | static constexpr int MAX_CACHE_COUNT = 150'000; 46 | 47 | // Minimum size of the cache in number of items. 48 | static constexpr int MIN_CACHE_COUNT = 6'000; 49 | 50 | struct Netresult { 51 | // 19x19 board positions 52 | std::array policy; 53 | 54 | // pass 55 | float policy_pass; 56 | 57 | // winrate 58 | float value; 59 | 60 | // sigmoid alpha 61 | float alpha; 62 | 63 | // sigmoid beta 64 | float beta; 65 | 66 | bool is_sai; 67 | 68 | // more general sigmoid may have two beta values 69 | float beta2; 70 | 71 | Netresult() : policy_pass(0.0f), value(0.0f), alpha(0.0f), beta(0.0f), is_sai(false), 72 | beta2(-1.0f) { 73 | policy.fill(0.0f); 74 | } 75 | }; 76 | 77 | static constexpr size_t ENTRY_SIZE = 78 | sizeof(Netresult) 79 | + sizeof(std::uint64_t) 80 | + sizeof(std::unique_ptr); 81 | 82 | NNCache(int size = MAX_CACHE_COUNT); // ~ 208MiB 83 | 84 | // Set a reasonable size gives max number of playouts 85 | void set_size_from_playouts(int max_playouts); 86 | 87 | // Resize NNCache 88 | void resize(int size); 89 | void clear(); 90 | 91 | // Try and find an existing entry. 92 | bool lookup(std::uint64_t hash, Netresult & result); 93 | 94 | // Insert a new entry. 95 | void insert(std::uint64_t hash, 96 | const Netresult& result); 97 | 98 | // Return the hit rate ratio. 99 | std::pair hit_rate() const { 100 | return {m_hits, m_lookups}; 101 | } 102 | 103 | void dump_stats(); 104 | 105 | // Return the estimated memory consumption of the cache. 106 | size_t get_estimated_size(); 107 | private: 108 | 109 | std::mutex m_mutex; 110 | 111 | size_t m_size; 112 | 113 | // Statistics 114 | int m_hits{0}; 115 | int m_lookups{0}; 116 | int m_inserts{0}; 117 | 118 | struct Entry { 119 | Entry(const Netresult& r) 120 | : result(r) {} 121 | Netresult result; // ~ 1.4KiB 122 | }; 123 | 124 | // Map from hash to {features, result} 125 | std::unordered_map> m_cache; 126 | // Order entries were added to the map. 127 | std::deque m_order; 128 | }; 129 | 130 | #endif 131 | -------------------------------------------------------------------------------- /src/Random.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of SAI, which is a fork of Leela Zero. 3 | Copyright (C) 2017-2019 Gian-Carlo Pascutto and contributors 4 | 5 | SAI is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | SAI is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with SAI. If not, see . 17 | 18 | Additional permission under GNU GPL version 3 section 7 19 | 20 | If you modify this Program, or any covered work, by linking or 21 | combining it with NVIDIA Corporation's libraries from the 22 | NVIDIA CUDA Toolkit and/or the NVIDIA CUDA Deep Neural 23 | Network library and/or the NVIDIA TensorRT inference library 24 | (or a modified version of those libraries), containing parts covered 25 | by the terms of the respective license agreement, the licensors of 26 | this Program grant you additional permission to convey the resulting 27 | work. 28 | */ 29 | 30 | #include "config.h" 31 | #include "Random.h" 32 | 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | #include "GTP.h" 39 | #include "Utils.h" 40 | 41 | Random& Random::get_Rng() { 42 | static thread_local Random s_rng{0}; 43 | return s_rng; 44 | } 45 | 46 | Random::Random(std::uint64_t seed) { 47 | if (seed == 0) { 48 | size_t thread_id = 49 | std::hash()(std::this_thread::get_id()); 50 | seedrandom(cfg_rng_seed ^ std::uint64_t(thread_id)); 51 | } else { 52 | seedrandom(seed); 53 | } 54 | } 55 | 56 | // This is xoroshiro128+. 57 | // Note that the last bit isn't entirely random, so don't use it, 58 | // if possible. 59 | std::uint64_t Random::gen() { 60 | const std::uint64_t s0 = m_s[0]; 61 | std::uint64_t s1 = m_s[1]; 62 | const std::uint64_t result = s0 + s1; 63 | 64 | s1 ^= s0; 65 | m_s[0] = Utils::rotl(s0, 55) ^ s1 ^ (s1 << 14); 66 | m_s[1] = Utils::rotl(s1, 36); 67 | 68 | return result; 69 | } 70 | 71 | std::uint64_t Random::randuint64(const uint64_t max) { 72 | const uint64_t inclusive_max = max - 1; 73 | return std::uniform_int_distribution{0, inclusive_max}(*this); 74 | } 75 | 76 | std::uint64_t Random::randuint64() { 77 | return gen(); 78 | } 79 | 80 | static std::uint64_t splitmix64(std::uint64_t z) { 81 | z += 0x9e3779b97f4a7c15; 82 | z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9; 83 | z = (z ^ (z >> 27)) * 0x94d049bb133111eb; 84 | return z ^ (z >> 31); 85 | } 86 | 87 | void Random::seedrandom(std::uint64_t seed) { 88 | // Initialize state of xoroshiro128+ by transforming the seed 89 | // with the splitmix64 algorithm. 90 | // As suggested by http://xoroshiro.di.unimi.it/xoroshiro128plus.c 91 | m_s[0] = splitmix64(seed); 92 | m_s[1] = splitmix64(m_s[0]); 93 | } 94 | 95 | -------------------------------------------------------------------------------- /src/Random.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of SAI, which is a fork of Leela Zero. 3 | Copyright (C) 2017-2019 Gian-Carlo Pascutto and contributors 4 | 5 | SAI is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | SAI is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with SAI. If not, see . 17 | 18 | Additional permission under GNU GPL version 3 section 7 19 | 20 | If you modify this Program, or any covered work, by linking or 21 | combining it with NVIDIA Corporation's libraries from the 22 | NVIDIA CUDA Toolkit and/or the NVIDIA CUDA Deep Neural 23 | Network library and/or the NVIDIA TensorRT inference library 24 | (or a modified version of those libraries), containing parts covered 25 | by the terms of the respective license agreement, the licensors of 26 | this Program grant you additional permission to convey the resulting 27 | work. 28 | */ 29 | 30 | #ifndef RANDOM_H_INCLUDED 31 | #define RANDOM_H_INCLUDED 32 | 33 | #include "config.h" 34 | #include 35 | #include 36 | 37 | /* 38 | Random number generator xoroshiro128+ 39 | */ 40 | class Random { 41 | public: 42 | Random() = delete; 43 | Random(std::uint64_t seed = 0); 44 | void seedrandom(std::uint64_t s); 45 | 46 | // Random numbers from [0, max - 1] 47 | template 48 | std::uint32_t randfix() { 49 | static_assert(0 < MAX && 50 | MAX < std::numeric_limits::max(), 51 | "randfix out of range"); 52 | // Last bit isn't random, so don't use it in isolation. We specialize 53 | // this case. 54 | static_assert(MAX != 2, "don't isolate the LSB with xoroshiro128+"); 55 | return gen() % MAX; 56 | } 57 | 58 | std::uint64_t randuint64(); 59 | 60 | // Random number from [0, max - 1] 61 | std::uint64_t randuint64(const std::uint64_t max); 62 | 63 | // return the thread local RNG 64 | static Random& get_Rng(); 65 | 66 | // UniformRandomBitGenerator interface 67 | using result_type = std::uint64_t; 68 | constexpr static result_type min() { 69 | return std::numeric_limits::min(); 70 | } 71 | constexpr static result_type max() { 72 | return std::numeric_limits::max(); 73 | } 74 | result_type operator()() { 75 | return gen(); 76 | } 77 | 78 | private: 79 | std::uint64_t gen(); 80 | std::uint64_t m_s[2]; 81 | }; 82 | 83 | // Specialization for last bit: use sign test 84 | template<> 85 | inline std::uint32_t Random::randfix<2>() { 86 | return (gen() > (std::numeric_limits::max() / 2)); 87 | } 88 | 89 | #endif 90 | -------------------------------------------------------------------------------- /src/SGFParser.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of SAI, which is a fork of Leela Zero. 3 | Copyright (C) 2017-2019 Gian-Carlo Pascutto and contributors 4 | 5 | SAI is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | SAI is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with SAI. If not, see . 17 | 18 | Additional permission under GNU GPL version 3 section 7 19 | 20 | If you modify this Program, or any covered work, by linking or 21 | combining it with NVIDIA Corporation's libraries from the 22 | NVIDIA CUDA Toolkit and/or the NVIDIA CUDA Deep Neural 23 | Network library and/or the NVIDIA TensorRT inference library 24 | (or a modified version of those libraries), containing parts covered 25 | by the terms of the respective license agreement, the licensors of 26 | this Program grant you additional permission to convey the resulting 27 | work. 28 | */ 29 | 30 | #ifndef SGFPARSER_H_INCLUDED 31 | #define SGFPARSER_H_INCLUDED 32 | 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | #include "SGFTree.h" 41 | 42 | class SGFParser { 43 | private: 44 | static std::string parse_property_name(std::istringstream & strm); 45 | static bool parse_property_value(std::istringstream & strm, std::string & result); 46 | public: 47 | static std::string chop_from_file(std::string fname, size_t index); 48 | static std::vector chop_all(std::string fname, 49 | size_t stopat = SIZE_MAX); 50 | static std::vector chop_stream(std::istream& ins, 51 | size_t stopat = SIZE_MAX); 52 | static void parse(std::istringstream & strm, SGFTree * node); 53 | }; 54 | 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /src/SGFTree.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of SAI, which is a fork of Leela Zero. 3 | Copyright (C) 2017-2019 Gian-Carlo Pascutto and contributors 4 | Copyright (C) 2019 SAI Team 5 | 6 | SAI is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SAI is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SAI. If not, see . 18 | 19 | Additional permission under GNU GPL version 3 section 7 20 | 21 | If you modify this Program, or any covered work, by linking or 22 | combining it with NVIDIA Corporation's libraries from the 23 | NVIDIA CUDA Toolkit and/or the NVIDIA CUDA Deep Neural 24 | Network library and/or the NVIDIA TensorRT inference library 25 | (or a modified version of those libraries), containing parts covered 26 | by the terms of the respective license agreement, the licensors of 27 | this Program grant you additional permission to convey the resulting 28 | work. 29 | */ 30 | 31 | 32 | #ifndef SGFTREE_H_INCLUDED 33 | #define SGFTREE_H_INCLUDED 34 | 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | 41 | #include "FastBoard.h" 42 | #include "GameState.h" 43 | #include "KoState.h" 44 | #include "TimeControl.h" 45 | 46 | class SGFTree { 47 | public: 48 | static constexpr auto EOT = 0; // End-Of-Tree marker 49 | 50 | SGFTree() = default; 51 | void init_state(); 52 | 53 | const KoState * get_state() const; 54 | GameState follow_mainline_state(unsigned int movenum = 999) const; 55 | std::vector get_mainline() const; 56 | 57 | void load_from_file(const std::string& filename, int index = 0); 58 | void load_from_string(const std::string& gamebuff); 59 | 60 | void add_property(std::string property, std::string value); 61 | SGFTree * add_child(); 62 | const SGFTree * get_child(size_t count) const; 63 | int get_move(int tomove) const; 64 | std::pair get_colored_move() const; 65 | bool is_initialized() const { 66 | return m_initialized; 67 | } 68 | FastBoard::vertex_t get_winner() const; 69 | 70 | static std::string state_to_string(GameState& state, 71 | int compcolor, 72 | bool selfplay = false); 73 | 74 | private: 75 | void populate_states(); 76 | void apply_move(int color, int move); 77 | void apply_move(int move); 78 | void copy_state(const SGFTree& state); 79 | int string_to_vertex(const std::string& move) const; 80 | 81 | using PropertyMap = std::multimap; 82 | 83 | bool m_initialized{false}; 84 | KoState m_state; 85 | std::shared_ptr m_timecontrol_ptr; 86 | FastBoard::vertex_t m_winner{FastBoard::INVAL}; 87 | std::vector m_children; 88 | PropertyMap m_properties; 89 | }; 90 | 91 | #endif 92 | -------------------------------------------------------------------------------- /src/SHA256.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of SAI, which is a fork of Leela Zero. 3 | Copyright (C) 2005, 2007 Olivier Gay 4 | Copyright (C) 2018-2019 SAI Team 5 | 6 | SAI is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SAI is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SAI. If not, see . 18 | 19 | Additional permission under GNU GPL version 3 section 7 20 | 21 | If you modify this Program, or any covered work, by linking or 22 | combining it with NVIDIA Corporation's libraries from the 23 | NVIDIA CUDA Toolkit and/or the NVIDIA CUDA Deep Neural 24 | Network library and/or the NVIDIA TensorRT inference library 25 | (or a modified version of those libraries), containing parts covered 26 | by the terms of the respective license agreement, the licensors of 27 | this Program grant you additional permission to convey the resulting 28 | work. 29 | */ 30 | 31 | #ifndef SHA256_H 32 | #define SHA256_H 33 | #include 34 | 35 | class SHA256 36 | { 37 | protected: 38 | typedef unsigned char uint8; 39 | typedef unsigned int uint32; 40 | typedef unsigned long long uint64; 41 | 42 | const static uint32 sha256_k[]; 43 | static const unsigned int SHA224_256_BLOCK_SIZE = (512/8); 44 | public: 45 | static std::string sha256(const std::string & input); 46 | void init(); 47 | void update(const unsigned char *message, unsigned int len); 48 | void final(unsigned char *digest); 49 | static const unsigned int DIGEST_SIZE = ( 256 / 8); 50 | 51 | protected: 52 | void transform(const unsigned char *message, unsigned int block_nb); 53 | unsigned int m_tot_len; 54 | unsigned int m_len; 55 | unsigned char m_block[2*SHA224_256_BLOCK_SIZE]; 56 | uint32 m_h[8]; 57 | }; 58 | 59 | #define SHA2_SHFR(x, n) (x >> n) 60 | #define SHA2_ROTR(x, n) ((x >> n) | (x << ((sizeof(x) << 3) - n))) 61 | #define SHA2_ROTL(x, n) ((x << n) | (x >> ((sizeof(x) << 3) - n))) 62 | #define SHA2_CH(x, y, z) ((x & y) ^ (~x & z)) 63 | #define SHA2_MAJ(x, y, z) ((x & y) ^ (x & z) ^ (y & z)) 64 | #define SHA256_F1(x) (SHA2_ROTR(x, 2) ^ SHA2_ROTR(x, 13) ^ SHA2_ROTR(x, 22)) 65 | #define SHA256_F2(x) (SHA2_ROTR(x, 6) ^ SHA2_ROTR(x, 11) ^ SHA2_ROTR(x, 25)) 66 | #define SHA256_F3(x) (SHA2_ROTR(x, 7) ^ SHA2_ROTR(x, 18) ^ SHA2_SHFR(x, 3)) 67 | #define SHA256_F4(x) (SHA2_ROTR(x, 17) ^ SHA2_ROTR(x, 19) ^ SHA2_SHFR(x, 10)) 68 | #define SHA2_UNPACK32(x, str) \ 69 | { \ 70 | *((str) + 3) = (uint8) ((x) ); \ 71 | *((str) + 2) = (uint8) ((x) >> 8); \ 72 | *((str) + 1) = (uint8) ((x) >> 16); \ 73 | *((str) + 0) = (uint8) ((x) >> 24); \ 74 | } 75 | #define SHA2_PACK32(str, x) \ 76 | { \ 77 | *(x) = ((uint32) *((str) + 3) ) \ 78 | | ((uint32) *((str) + 2) << 8) \ 79 | | ((uint32) *((str) + 1) << 16) \ 80 | | ((uint32) *((str) + 0) << 24); \ 81 | } 82 | #endif 83 | -------------------------------------------------------------------------------- /src/SMP.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of SAI, which is a fork of Leela Zero. 3 | Copyright (C) 2017-2019 Gian-Carlo Pascutto and contributors 4 | 5 | SAI is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | SAI is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with SAI. If not, see . 17 | 18 | Additional permission under GNU GPL version 3 section 7 19 | 20 | If you modify this Program, or any covered work, by linking or 21 | combining it with NVIDIA Corporation's libraries from the 22 | NVIDIA CUDA Toolkit and/or the NVIDIA CUDA Deep Neural 23 | Network library and/or the NVIDIA TensorRT inference library 24 | (or a modified version of those libraries), containing parts covered 25 | by the terms of the respective license agreement, the licensors of 26 | this Program grant you additional permission to convey the resulting 27 | work. 28 | */ 29 | 30 | 31 | #include "SMP.h" 32 | 33 | #include 34 | #include 35 | 36 | SMP::Mutex::Mutex() { 37 | m_lock = false; 38 | } 39 | 40 | SMP::Lock::Lock(Mutex & m) { 41 | m_mutex = &m; 42 | lock(); 43 | } 44 | 45 | void SMP::Lock::lock() { 46 | assert(!m_owns_lock); 47 | // Test and Test-and-Set reduces memory contention 48 | // However, just trying to Test-and-Set first improves performance in almost 49 | // all cases 50 | while (m_mutex->m_lock.exchange(true, std::memory_order_acquire)) { 51 | while (m_mutex->m_lock.load(std::memory_order_relaxed)); 52 | } 53 | m_owns_lock = true; 54 | } 55 | 56 | void SMP::Lock::unlock() { 57 | assert(m_owns_lock); 58 | auto lock_held = m_mutex->m_lock.exchange(false, std::memory_order_release); 59 | 60 | // If this fails it means we are unlocking an unlocked lock 61 | #ifdef NDEBUG 62 | (void)lock_held; 63 | #else 64 | assert(lock_held); 65 | #endif 66 | m_owns_lock = false; 67 | } 68 | 69 | SMP::Lock::~Lock() { 70 | // If we don't claim to hold the lock, 71 | // don't bother trying to unlock in the destructor. 72 | if (m_owns_lock) { 73 | unlock(); 74 | } 75 | } 76 | 77 | size_t SMP::get_num_cpus() { 78 | return std::thread::hardware_concurrency(); 79 | } 80 | -------------------------------------------------------------------------------- /src/SMP.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of SAI, which is a fork of Leela Zero. 3 | Copyright (C) 2017-2019 Gian-Carlo Pascutto and contributors 4 | 5 | SAI is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | SAI is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with SAI. If not, see . 17 | 18 | Additional permission under GNU GPL version 3 section 7 19 | 20 | If you modify this Program, or any covered work, by linking or 21 | combining it with NVIDIA Corporation's libraries from the 22 | NVIDIA CUDA Toolkit and/or the NVIDIA CUDA Deep Neural 23 | Network library and/or the NVIDIA TensorRT inference library 24 | (or a modified version of those libraries), containing parts covered 25 | by the terms of the respective license agreement, the licensors of 26 | this Program grant you additional permission to convey the resulting 27 | work. 28 | */ 29 | 30 | 31 | #ifndef SMP_H_INCLUDED 32 | #define SMP_H_INCLUDED 33 | 34 | #include "config.h" 35 | 36 | #include 37 | #include 38 | 39 | namespace SMP { 40 | size_t get_num_cpus(); 41 | 42 | class Mutex { 43 | public: 44 | Mutex(); 45 | ~Mutex() = default; 46 | friend class Lock; 47 | private: 48 | std::atomic m_lock; 49 | }; 50 | 51 | class Lock { 52 | public: 53 | explicit Lock(Mutex & m); 54 | ~Lock(); 55 | void lock(); 56 | void unlock(); 57 | private: 58 | Mutex * m_mutex; 59 | bool m_owns_lock{false}; 60 | }; 61 | } 62 | 63 | // Avoids accidentally creating a temporary 64 | #define LOCK(mutex, lock) SMP::Lock lock((mutex)) 65 | 66 | #endif 67 | -------------------------------------------------------------------------------- /src/ThreadPool.h: -------------------------------------------------------------------------------- 1 | #ifndef THREADPOOL_H_INCLUDED 2 | #define THREADPOOL_H_INCLUDED 3 | /* 4 | Extended from code: 5 | Copyright (c) 2012 Jakob Progsch, Václav Zeman 6 | Modifications: 7 | Copyright (c) 2017-2019 Gian-Carlo Pascutto and contributors 8 | 9 | This software is provided 'as-is', without any express or implied 10 | warranty. In no event will the authors be held liable for any damages 11 | arising from the use of this software. 12 | 13 | Permission is granted to anyone to use this software for any purpose, 14 | including commercial applications, and to alter it and redistribute it 15 | freely, subject to the following restrictions: 16 | 17 | 1. The origin of this software must not be misrepresented; you must not 18 | claim that you wrote the original software. If you use this software 19 | in a product, an acknowledgment in the product documentation would be 20 | appreciated but is not required. 21 | 22 | 2. Altered source versions must be plainly marked as such, and must not be 23 | misrepresented as being the original software. 24 | 25 | 3. This notice may not be removed or altered from any source 26 | distribution. 27 | */ 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | namespace Utils { 40 | 41 | class ThreadPool { 42 | public: 43 | ThreadPool() = default; 44 | ~ThreadPool(); 45 | 46 | // create worker threads. This version has no initializers. 47 | void initialize(std::size_t); 48 | 49 | // add an extra thread. The thread calls initializer() before doing anything, 50 | // so that the user can initialize per-thread data structures before doing work. 51 | void add_thread(std::function initializer); 52 | template 53 | auto add_task(F&& f, Args&&... args) 54 | -> std::future::type>; 55 | private: 56 | std::vector m_threads; 57 | std::queue> m_tasks; 58 | 59 | std::mutex m_mutex; 60 | std::condition_variable m_condvar; 61 | bool m_exit{false}; 62 | }; 63 | 64 | inline void ThreadPool::add_thread(std::function initializer) { 65 | m_threads.emplace_back([this, initializer] { 66 | initializer(); 67 | for (;;) { 68 | std::function task; 69 | { 70 | std::unique_lock lock(m_mutex); 71 | m_condvar.wait(lock, [this]{ return m_exit || !m_tasks.empty(); }); 72 | if (m_exit && m_tasks.empty()) { 73 | return; 74 | } 75 | task = std::move(m_tasks.front()); 76 | m_tasks.pop(); 77 | } 78 | task(); 79 | } 80 | }); 81 | } 82 | 83 | inline void ThreadPool::initialize(size_t threads) { 84 | for (size_t i = 0; i < threads; i++) { 85 | add_thread([](){} /* null function */); 86 | } 87 | } 88 | 89 | template 90 | auto ThreadPool::add_task(F&& f, Args&&... args) 91 | -> std::future::type> { 92 | using return_type = typename std::result_of::type; 93 | 94 | auto task = std::make_shared< std::packaged_task >( 95 | std::bind(std::forward(f), std::forward(args)...) 96 | ); 97 | 98 | std::future res = task->get_future(); 99 | { 100 | std::unique_lock lock(m_mutex); 101 | m_tasks.emplace([task](){(*task)();}); 102 | } 103 | m_condvar.notify_one(); 104 | return res; 105 | } 106 | 107 | inline ThreadPool::~ThreadPool() { 108 | { 109 | std::unique_lock lock(m_mutex); 110 | m_exit = true; 111 | } 112 | m_condvar.notify_all(); 113 | for (std::thread & worker : m_threads) { 114 | worker.join(); 115 | } 116 | } 117 | 118 | class ThreadGroup { 119 | public: 120 | ThreadGroup(ThreadPool & pool) : m_pool(pool) {} 121 | template 122 | void add_task(F&& f, Args&&... args) { 123 | m_taskresults.emplace_back( 124 | m_pool.add_task(std::forward(f), std::forward(args)...) 125 | ); 126 | } 127 | void wait_all() { 128 | for (auto && result : m_taskresults) { 129 | result.get(); 130 | } 131 | } 132 | private: 133 | ThreadPool & m_pool; 134 | std::vector> m_taskresults; 135 | }; 136 | 137 | } 138 | 139 | #endif 140 | -------------------------------------------------------------------------------- /src/TimeControl.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of SAI, which is a fork of Leela Zero. 3 | Copyright (C) 2017-2019 Gian-Carlo Pascutto and contributors 4 | 5 | SAI is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | SAI is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with SAI. If not, see . 17 | 18 | Additional permission under GNU GPL version 3 section 7 19 | 20 | If you modify this Program, or any covered work, by linking or 21 | combining it with NVIDIA Corporation's libraries from the 22 | NVIDIA CUDA Toolkit and/or the NVIDIA CUDA Deep Neural 23 | Network library and/or the NVIDIA TensorRT inference library 24 | (or a modified version of those libraries), containing parts covered 25 | by the terms of the respective license agreement, the licensors of 26 | this Program grant you additional permission to convey the resulting 27 | work. 28 | */ 29 | 30 | 31 | #ifndef TIMECONTROL_H_INCLUDED 32 | #define TIMECONTROL_H_INCLUDED 33 | 34 | #include 35 | #include 36 | #include 37 | 38 | #include "config.h" 39 | #include "Timing.h" 40 | 41 | class TimeControl { 42 | public: 43 | /* 44 | Initialize time control. Timing info is per GTP and in centiseconds 45 | */ 46 | TimeControl(int maintime = 60 * 60 * 100, 47 | int byotime = 0, int byostones = 0, 48 | int byoperiods = 0); 49 | 50 | void start(int color); 51 | void stop(int color); 52 | int max_time_for_move(int boardsize, int color, size_t movenum) const; 53 | void adjust_time(int color, int time, int stones); 54 | void display_times(); 55 | void reset_clocks(); 56 | bool can_accumulate_time(int color) const; 57 | size_t opening_moves(int boardsize) const; 58 | std::string to_text_sgf() const; 59 | static std::shared_ptr make_from_text_sgf( 60 | const std::string& maintime, const std::string& byoyomi, 61 | const std::string& black_time_left, const std::string& white_time_left, 62 | const std::string& black_moves_left, const std::string& white_moves_left); 63 | private: 64 | std::string stones_left_to_text_sgf(const int color) const; 65 | void display_color_time(int color); 66 | int get_moves_expected(int boardsize, size_t movenum) const; 67 | 68 | int m_maintime; 69 | int m_byotime; 70 | int m_byostones; 71 | int m_byoperiods; 72 | 73 | std::array m_remaining_time; /* main time per player */ 74 | std::array m_stones_left; /* stones to play in byo period */ 75 | std::array m_periods_left; /* byo periods */ 76 | std::array m_inbyo; /* player is in byo yomi */ 77 | 78 | std::array m_times; /* storage for player times */ 79 | }; 80 | 81 | #endif 82 | -------------------------------------------------------------------------------- /src/Timing.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of SAI, which is a fork of Leela Zero. 3 | Copyright (C) 2017-2019 Gian-Carlo Pascutto and contributors 4 | 5 | SAI is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | SAI is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with SAI. If not, see . 17 | 18 | Additional permission under GNU GPL version 3 section 7 19 | 20 | If you modify this Program, or any covered work, by linking or 21 | combining it with NVIDIA Corporation's libraries from the 22 | NVIDIA CUDA Toolkit and/or the NVIDIA CUDA Deep Neural 23 | Network library and/or the NVIDIA TensorRT inference library 24 | (or a modified version of those libraries), containing parts covered 25 | by the terms of the respective license agreement, the licensors of 26 | this Program grant you additional permission to convey the resulting 27 | work. 28 | */ 29 | 30 | #include "Timing.h" 31 | 32 | #include 33 | 34 | 35 | int Time::timediff_centis(Time start, Time end) { 36 | return std::chrono::duration_cast 37 | (end.m_time - start.m_time).count() / 10; 38 | } 39 | 40 | double Time::timediff_seconds(Time start, Time end) { 41 | return std::chrono::duration(end.m_time - start.m_time).count(); 42 | } 43 | 44 | Time::Time() { 45 | m_time = std::chrono::steady_clock::now(); 46 | } 47 | -------------------------------------------------------------------------------- /src/Timing.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of SAI, which is a fork of Leela Zero. 3 | Copyright (C) 2017-2019 Gian-Carlo Pascutto and contributors 4 | 5 | SAI is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | SAI is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with SAI. If not, see . 17 | 18 | Additional permission under GNU GPL version 3 section 7 19 | 20 | If you modify this Program, or any covered work, by linking or 21 | combining it with NVIDIA Corporation's libraries from the 22 | NVIDIA CUDA Toolkit and/or the NVIDIA CUDA Deep Neural 23 | Network library and/or the NVIDIA TensorRT inference library 24 | (or a modified version of those libraries), containing parts covered 25 | by the terms of the respective license agreement, the licensors of 26 | this Program grant you additional permission to convey the resulting 27 | work. 28 | */ 29 | 30 | #ifndef TIMING_H_INCLUDED 31 | #define TIMING_H_INCLUDED 32 | 33 | #include 34 | 35 | class Time { 36 | public: 37 | /* sets to current time */ 38 | Time(); 39 | 40 | /* time difference in centiseconds */ 41 | static int timediff_centis(Time start, Time end); 42 | 43 | /* time difference in seconds */ 44 | static double timediff_seconds(Time start, Time end); 45 | 46 | private: 47 | std::chrono::steady_clock::time_point m_time; 48 | }; 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /src/Training.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of SAI, which is a fork of Leela Zero. 3 | Copyright (C) 2017-2019 Gian-Carlo Pascutto and contributors 4 | Copyright (C) 2018-2019 SAI Team 5 | 6 | SAI is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SAI is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SAI. If not, see . 18 | 19 | Additional permission under GNU GPL version 3 section 7 20 | 21 | If you modify this Program, or any covered work, by linking or 22 | combining it with NVIDIA Corporation's libraries from the 23 | NVIDIA CUDA Toolkit and/or the NVIDIA CUDA Deep Neural 24 | Network library and/or the NVIDIA TensorRT inference library 25 | (or a modified version of those libraries), containing parts covered 26 | by the terms of the respective license agreement, the licensors of 27 | this Program grant you additional permission to convey the resulting 28 | work. 29 | */ 30 | 31 | #ifndef TRAINING_H_INCLUDED 32 | #define TRAINING_H_INCLUDED 33 | 34 | #include "config.h" 35 | 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | 42 | #include "GameState.h" 43 | #include "Network.h" 44 | #include "UCTNode.h" 45 | 46 | class TimeStep { 47 | public: 48 | using BoardPlane = std::bitset; 49 | using NNPlanes = std::vector; 50 | NNPlanes planes; 51 | std::vector probabilities; 52 | int to_move; 53 | float net_winrate; 54 | float root_uct_winrate; 55 | float child_uct_winrate; 56 | int bestmove_visits; 57 | float komi; 58 | size_t movenum; 59 | bool is_blunder; 60 | UCTStats uct_stats; 61 | }; 62 | 63 | std::ostream& operator<< (std::ostream& stream, const TimeStep& timestep); 64 | std::istream& operator>> (std::istream& stream, TimeStep& timestep); 65 | 66 | class OutputChunker { 67 | public: 68 | OutputChunker(const std::string& basename, bool compress = false); 69 | ~OutputChunker(); 70 | void append(const std::string& str); 71 | 72 | // Group this many games in a batch. 73 | static constexpr size_t CHUNK_SIZE = 32; 74 | private: 75 | std::string gen_chunk_name() const; 76 | void flush_chunks(); 77 | size_t m_game_count{0}; 78 | size_t m_chunk_count{0}; 79 | std::string m_buffer; 80 | std::string m_basename; 81 | bool m_compress{false}; 82 | }; 83 | 84 | class Training { 85 | public: 86 | static void clear_training(); 87 | static void dump_training(int winner_color, 88 | const std::string& out_filename, 89 | const std::string& hash); 90 | static void dump_debug(const std::string& out_filename); 91 | static void record(Network & network, GameState& state, UCTNode& node); 92 | 93 | static void dump_supervised(const std::string& sgf_file, 94 | const std::string& out_filename); 95 | static void save_training(const std::string& filename); 96 | static void load_training(const std::string& filename); 97 | 98 | private: 99 | static TimeStep::NNPlanes get_planes(const GameState* const state); 100 | static void process_game(GameState& state, size_t& train_pos, int who_won, 101 | const std::vector& tree_moves, 102 | OutputChunker& outchunker); 103 | static void dump_training(int winner_color, 104 | OutputChunker& outchunker, 105 | const std::string& hash = ""); 106 | static void dump_debug(OutputChunker& outchunker); 107 | static void save_training(std::ofstream& out); 108 | static void load_training(std::ifstream& in); 109 | static std::vector m_data; 110 | }; 111 | 112 | #endif 113 | -------------------------------------------------------------------------------- /src/Tuner.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of SAI, which is a fork of Leela Zero. 3 | Copyright (C) 2017-2019 Gian-Carlo Pascutto and contributors 4 | 5 | SAI is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | SAI is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with SAI. If not, see . 17 | 18 | Additional permission under GNU GPL version 3 section 7 19 | 20 | If you modify this Program, or any covered work, by linking or 21 | combining it with NVIDIA Corporation's libraries from the 22 | NVIDIA CUDA Toolkit and/or the NVIDIA CUDA Deep Neural 23 | Network library and/or the NVIDIA TensorRT inference library 24 | (or a modified version of those libraries), containing parts covered 25 | by the terms of the respective license agreement, the licensors of 26 | this Program grant you additional permission to convey the resulting 27 | work. 28 | */ 29 | 30 | 31 | #ifndef SGEMM_TUNER_H_INCLUDED 32 | #define SGEMM_TUNER_H_INCLUDED 33 | 34 | #include "config.h" 35 | #include 36 | #include 37 | #include 38 | 39 | using Configurations = std::pair>; 40 | using Parameters = std::map; 41 | 42 | template class OpenCL; 43 | 44 | template 45 | class Tuner { 46 | OpenCL & m_opencl; 47 | cl::Context m_context; 48 | cl::Device m_device; 49 | bool m_use_tensorcore = false; 50 | public: 51 | std::string tune_sgemm(const int m, const int n, const int k, 52 | const int batch_size, const int runs = 4); 53 | std::string load_sgemm_tuners(const int m, const int n, const int k, 54 | const int batch_size); 55 | 56 | // list of device types that was tuned in this run. 57 | // This is to prevent the same device from being tuned multiple times. 58 | static std::vector tuned_devices; 59 | 60 | // version 0 : Initial release 61 | // version 1 : Tuner with additional tensor cores (parameter TCE) 62 | static constexpr auto TUNER_VERSION = 1; 63 | 64 | Tuner(OpenCL & opencl, cl::Context context, cl::Device device) : 65 | m_opencl(opencl), m_context(context), m_device(device) {} 66 | 67 | void enable_tensorcore(); 68 | private: 69 | void store_sgemm_tuners(const int m, const int n, const int k, 70 | const int batch_size, std::string tuners); 71 | bool valid_config_sgemm(Parameters p, bool exhaustive); 72 | std::string parameters_to_defines(const Parameters& p); 73 | std::string parameters_to_string(const Parameters& p); 74 | Parameters get_parameters_by_int(const std::vector& opts, 75 | const int n); 76 | std::string sgemm_tuners_from_line(std::string line, const int m, 77 | const int n, const int k, 78 | const int batch_size); 79 | std::vector build_valid_params(); 80 | }; 81 | 82 | #endif 83 | -------------------------------------------------------------------------------- /src/Utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of SAI, which is a fork of Leela Zero. 3 | Copyright (C) 2017-2019 Gian-Carlo Pascutto and contributors 4 | Copyright (C) 2018 SAI Team 5 | 6 | SAI is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SAI is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SAI. If not, see . 18 | 19 | Additional permission under GNU GPL version 3 section 7 20 | 21 | If you modify this Program, or any covered work, by linking or 22 | combining it with NVIDIA Corporation's libraries from the 23 | NVIDIA CUDA Toolkit and/or the NVIDIA CUDA Deep Neural 24 | Network library and/or the NVIDIA TensorRT inference library 25 | (or a modified version of those libraries), containing parts covered 26 | by the terms of the respective license agreement, the licensors of 27 | this Program grant you additional permission to convey the resulting 28 | work. 29 | */ 30 | 31 | #ifndef UTILS_H_INCLUDED 32 | #define UTILS_H_INCLUDED 33 | 34 | #include "config.h" 35 | 36 | #include 37 | #include 38 | #include 39 | 40 | #include "ThreadPool.h" 41 | 42 | extern Utils::ThreadPool thread_pool; 43 | 44 | namespace Utils { 45 | void myprintf_error(const char *fmt, ...); 46 | void myprintf(const char *fmt, ...); 47 | void gtp_printf(int id, const char *fmt, ...); 48 | void gtp_printf_raw(const char *fmt, ...); 49 | void gtp_fail_printf(int id, const char *fmt, ...); 50 | void log_input(const std::string& input); 51 | bool input_pending(); 52 | float sigmoid_interval_avg(float alpkt, float beta, float beta2, float s, float t); 53 | double log_sigmoid(double x); 54 | float median(std::vector & sample); 55 | float winner (float score); 56 | bool parse_agent_params(std::array ¶ms, const std::string &str); 57 | void dump_agent_params(); 58 | bool agent_color_dependent(); 59 | 60 | template 61 | void atomic_add(std::atomic &f, T d) { 62 | T old = f.load(); 63 | while (!f.compare_exchange_weak(old, old + d)); 64 | } 65 | 66 | template 67 | T rotl(const T x, const int k) { 68 | return (x << k) | (x >> (std::numeric_limits::digits - k)); 69 | } 70 | 71 | inline bool is7bit(int c) { 72 | return c >= 0 && c <= 127; 73 | } 74 | 75 | size_t ceilMultiple(size_t a, size_t b); 76 | 77 | const std::string leelaz_file(std::string file); 78 | 79 | void create_z_table(); 80 | float cached_t_quantile(int v); 81 | } 82 | 83 | #endif 84 | -------------------------------------------------------------------------------- /src/Zobrist.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of SAI, which is a fork of Leela Zero. 3 | Copyright (C) 2017-2019 Gian-Carlo Pascutto and contributors 4 | 5 | SAI is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | SAI is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with SAI. If not, see . 17 | 18 | Additional permission under GNU GPL version 3 section 7 19 | 20 | If you modify this Program, or any covered work, by linking or 21 | combining it with NVIDIA Corporation's libraries from the 22 | NVIDIA CUDA Toolkit and/or the NVIDIA CUDA Deep Neural 23 | Network library and/or the NVIDIA TensorRT inference library 24 | (or a modified version of those libraries), containing parts covered 25 | by the terms of the respective license agreement, the licensors of 26 | this Program grant you additional permission to convey the resulting 27 | work. 28 | */ 29 | 30 | 31 | #include "config.h" 32 | #include "Zobrist.h" 33 | #include "Random.h" 34 | 35 | std::array, 4> Zobrist::zobrist; 36 | std::array Zobrist::zobrist_ko; 37 | std::array, 2> Zobrist::zobrist_pris; 38 | std::array Zobrist::zobrist_pass; 39 | 40 | void Zobrist::init_zobrist(Random& rng) { 41 | for (int i = 0; i < 4; i++) { 42 | for (int j = 0; j < FastBoard::NUM_VERTICES; j++) { 43 | Zobrist::zobrist[i][j] = rng.randuint64(); 44 | } 45 | } 46 | 47 | for (int j = 0; j < FastBoard::NUM_VERTICES; j++) { 48 | Zobrist::zobrist_ko[j] = rng.randuint64(); 49 | } 50 | 51 | for (int i = 0; i < 2; i++) { 52 | for (int j = 0; j < FastBoard::NUM_VERTICES * 2; j++) { 53 | Zobrist::zobrist_pris[i][j] = rng.randuint64(); 54 | } 55 | } 56 | 57 | for (int i = 0; i < 5; i++) { 58 | Zobrist::zobrist_pass[i] = rng.randuint64(); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/Zobrist.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of SAI, which is a fork of Leela Zero. 3 | Copyright (C) 2017-2019 Gian-Carlo Pascutto and contributors 4 | 5 | SAI is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | SAI is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with SAI. If not, see . 17 | 18 | Additional permission under GNU GPL version 3 section 7 19 | 20 | If you modify this Program, or any covered work, by linking or 21 | combining it with NVIDIA Corporation's libraries from the 22 | NVIDIA CUDA Toolkit and/or the NVIDIA CUDA Deep Neural 23 | Network library and/or the NVIDIA TensorRT inference library 24 | (or a modified version of those libraries), containing parts covered 25 | by the terms of the respective license agreement, the licensors of 26 | this Program grant you additional permission to convey the resulting 27 | work. 28 | */ 29 | 30 | #ifndef ZOBRIST_H_INCLUDED 31 | #define ZOBRIST_H_INCLUDED 32 | 33 | #include "config.h" 34 | 35 | #include 36 | #include 37 | 38 | #include "FastBoard.h" 39 | #include "Random.h" 40 | 41 | class Zobrist { 42 | public: 43 | static constexpr auto zobrist_empty = 0x1234567887654321; 44 | static constexpr auto zobrist_blacktomove = 0xABCDABCDABCDABCD; 45 | 46 | static std::array, 4> zobrist; 47 | static std::array zobrist_ko; 48 | static std::array, 2> zobrist_pris; 49 | static std::array zobrist_pass; 50 | 51 | static void init_zobrist(Random& rng); 52 | }; 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /src/kernels/clblast/xgemm_batched.opencl: -------------------------------------------------------------------------------- 1 | 2 | // ================================================================================================= 3 | // This file is part of the CLBlast project. The project is licensed under Apache Version 2.0. This 4 | // project loosely follows the Google C++ styleguide and uses a tab-size of two spaces and a max- 5 | // width of 100 characters per line. 6 | // 7 | // Author(s): 8 | // Cedric Nugteren 9 | // 10 | // This file contains the batched version of the non-direct GEMM kernel. See part 1 for information 11 | // about the non-batched version of the kernel. 12 | // 13 | // ================================================================================================= 14 | 15 | // Enables loading of this file using the C++ pre-processor's #include (C++11 standard raw string 16 | // literal). Comment-out this line for syntax-highlighting when developing. 17 | R"( 18 | 19 | // ================================================================================================= 20 | 21 | // Main entry point of the kernel. This is the regular full version. 22 | __kernel __attribute__((reqd_work_group_size(MDIMC, NDIMC, 1))) 23 | void XgemmBatched(const int kSizeM, const int kSizeN, const int kSizeK, 24 | const __global memM* restrict agm, 25 | const __global memN* restrict bgm, 26 | __global memM* restrict cgm) { 27 | const int batch = get_group_id(2); 28 | 29 | // Sets the offsets 30 | const int a_offset = kSizeM*kSizeK*batch; 31 | const int b_offset = kSizeK*kSizeN*batch; 32 | const int c_offset = kSizeM*kSizeN*batch; 33 | const __global memM* restrict agm_ = &agm[a_offset / VWM]; 34 | const __global memN* restrict bgm_ = &bgm[b_offset / VWN]; 35 | __global memM* restrict cgm_ = &cgm[c_offset / VWM]; 36 | 37 | // Allocates workgroup-private memory (local memory) 38 | #if SA == 1 39 | __local memM alm[KWG * MWG/VWM]; 40 | #endif 41 | #if SB == 1 42 | __local memN blm[KWG * NWG/VWN]; 43 | #endif 44 | 45 | // Computes the matrix-multiplication and stores the result in global memory 46 | #if SA == 1 && SB == 1 47 | XgemmBody(kSizeM, kSizeN, kSizeK, agm_, bgm_, cgm_, alm, blm); 48 | #elif SA == 1 49 | XgemmBody(kSizeM, kSizeN, kSizeK, agm_, bgm_, cgm_, alm); 50 | #elif SB == 1 51 | XgemmBody(kSizeM, kSizeN, kSizeK, agm_, bgm_, cgm_, blm); 52 | #else 53 | XgemmBody(kSizeM, kSizeN, kSizeK, agm_, bgm_, cgm_); 54 | #endif 55 | } 56 | 57 | // ================================================================================================= 58 | 59 | // End of the C++11 raw string literal 60 | )" 61 | 62 | // ================================================================================================= 63 | -------------------------------------------------------------------------------- /src/kernels/clblast/xgemm_part2.opencl: -------------------------------------------------------------------------------- 1 | 2 | // ================================================================================================= 3 | // This file is part of the CLBlast project. The project is licensed under Apache Version 2.0. This 4 | // project loosely follows the Google C++ styleguide and uses a tab-size of two spaces and a max- 5 | // width of 100 characters per line. 6 | // 7 | // Author(s): 8 | // Cedric Nugteren 9 | // 10 | // This is part 2 of 4 of the GEMM kernel. See part 1 for more information. 11 | // 12 | // ================================================================================================= 13 | 14 | // Enables loading of this file using the C++ pre-processor's #include (C++11 standard raw string 15 | // literal). Comment-out this line for syntax-highlighting when developing. 16 | R"( 17 | 18 | // ================================================================================================= 19 | 20 | // The vectorised multiply-add function 21 | INLINE_FUNC realM MultiplyAddVector(realM cvec, const realM avec, const real bval) { 22 | #if USE_VECTOR_MAD == 1 23 | cvec += avec * bval; 24 | #else 25 | #if VWM == 1 26 | MultiplyAdd(cvec, avec, bval); 27 | #elif VWM == 2 28 | MultiplyAdd(cvec.x , avec.x, bval); 29 | MultiplyAdd(cvec.y , avec.y, bval); 30 | #elif VWM == 4 31 | MultiplyAdd(cvec.x , avec.x, bval); 32 | MultiplyAdd(cvec.y , avec.y, bval); 33 | MultiplyAdd(cvec.z , avec.z, bval); 34 | MultiplyAdd(cvec.w , avec.w, bval); 35 | #elif VWM == 8 36 | MultiplyAdd(cvec.s0, avec.s0, bval); 37 | MultiplyAdd(cvec.s1, avec.s1, bval); 38 | MultiplyAdd(cvec.s2, avec.s2, bval); 39 | MultiplyAdd(cvec.s3, avec.s3, bval); 40 | MultiplyAdd(cvec.s4, avec.s4, bval); 41 | MultiplyAdd(cvec.s5, avec.s5, bval); 42 | MultiplyAdd(cvec.s6, avec.s6, bval); 43 | MultiplyAdd(cvec.s7, avec.s7, bval); 44 | #elif VWM == 16 45 | MultiplyAdd(cvec.s0, avec.s0, bval); 46 | MultiplyAdd(cvec.s1, avec.s1, bval); 47 | MultiplyAdd(cvec.s2, avec.s2, bval); 48 | MultiplyAdd(cvec.s3, avec.s3, bval); 49 | MultiplyAdd(cvec.s4, avec.s4, bval); 50 | MultiplyAdd(cvec.s5, avec.s5, bval); 51 | MultiplyAdd(cvec.s6, avec.s6, bval); 52 | MultiplyAdd(cvec.s7, avec.s7, bval); 53 | MultiplyAdd(cvec.s8, avec.s8, bval); 54 | MultiplyAdd(cvec.s9, avec.s9, bval); 55 | MultiplyAdd(cvec.sA, avec.sA, bval); 56 | MultiplyAdd(cvec.sB, avec.sB, bval); 57 | MultiplyAdd(cvec.sC, avec.sC, bval); 58 | MultiplyAdd(cvec.sD, avec.sD, bval); 59 | MultiplyAdd(cvec.sE, avec.sE, bval); 60 | MultiplyAdd(cvec.sF, avec.sF, bval); 61 | #endif 62 | #endif 63 | return cvec; 64 | } 65 | 66 | // ================================================================================================= 67 | 68 | // Merges the results in Cpm with the global array in Cgm. 69 | INLINE_FUNC void StoreResults(__global memM* cgm, realM cpm[NWI*MWI/VWM], const int kSizeM) { 70 | #pragma unroll 71 | for (int _ni = 0; _ni < NWI; _ni += 1) { 72 | #pragma unroll 73 | for (int _mi = 0; _mi < MWI/VWM; _mi += 1) { 74 | #if STRM == 0 75 | int mg = _mi + get_local_id(0)*(MWI/VWM); 76 | #elif STRM == 1 77 | int mg = get_local_id(0) + _mi*MDIMC; 78 | #endif 79 | #if STRN == 0 80 | int ng = _ni + get_local_id(1)*NWI; 81 | #elif STRN == 1 82 | int ng = _ni%VWN + get_local_id(1)*VWN + (_ni/VWN)*VWN*NDIMC; 83 | #endif 84 | int idm = mg + GetGroupID0() * (MWG/VWM); 85 | int idn = ng + GetGroupID1() * NWG; 86 | int index = idn*(kSizeM/VWM) + idm; 87 | 88 | #ifdef FP16_STORAGE 89 | #if VWM == 1 90 | vstorea_half(cpm[_ni * (MWI/VWM) + _mi], index, (__global half*)cgm); 91 | #elif VWM == 2 92 | vstorea_half2(cpm[_ni * (MWI/VWM) + _mi], index, (__global half*)cgm); 93 | #elif VWM == 4 94 | vstorea_half4(cpm[_ni * (MWI/VWM) + _mi], index, (__global half*)cgm); 95 | #elif VWM == 8 96 | vstorea_half8(cpm[_ni * (MWI/VWM) + _mi], index, (__global half*)cgm); 97 | #elif VWM == 16 98 | vstorea_half16(cpm[_ni * (MWI/VWM) + _mi], index, (__global half*)cgm); 99 | #endif 100 | #else 101 | cgm[index] = cpm[_ni * (MWI/VWM) + _mi]; 102 | #endif 103 | } 104 | } 105 | } 106 | 107 | // ================================================================================================= 108 | 109 | // End of the C++11 raw string literal 110 | )" 111 | 112 | // ================================================================================================= 113 | -------------------------------------------------------------------------------- /src/kernels/tensorcore_test.opencl: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of SAI, which is a fork of Leela Zero. 3 | Copyright (C) 2017-2018 Gian-Carlo Pascutto and contributors 4 | 5 | SAI is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | SAI is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with SAI. If not, see . 17 | */ 18 | 19 | 20 | // This kernel simply tests if the host can compile a wmma insturction. 21 | // Not intended to be run at all. 22 | 23 | // Enables loading of this file using the C++ pre-processor's #include (C++11 standard raw string 24 | // literal). Comment-out this line for syntax-highlighting when developing. 25 | R"( 26 | 27 | __kernel void tensorcore_test(__global int * ptr) { 28 | asm( 29 | ".reg .b32 a0, a1, a2, a3, a4, a5, a6, a7;\n" 30 | "wmma.load.a.sync.aligned.m16n16k16.shared.row.f16 {a0,a1,a2,a3,a4,a5,a6,a7}, [%0];\n" : : "l"(ptr) 31 | ); 32 | } 33 | 34 | // End of the C++11 raw string literal 35 | )" 36 | -------------------------------------------------------------------------------- /training/elf/elf_convert.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import numpy as np 3 | import sys 4 | import torch 5 | 6 | net = torch.load(sys.argv[1]) 7 | state = net['state_dict'] 8 | 9 | def tensor_to_str(t): 10 | return ' '.join(map(str, np.array(t).flatten())) 11 | 12 | def convert_block(t, name): 13 | weight = np.array(t[name + '.0.weight']) 14 | bias = np.array(t[name + '.0.bias']) 15 | bn_gamma = np.array(t[name + '.1.weight']) 16 | bn_beta = np.array(t[name + '.1.bias']) 17 | bn_mean = np.array(t[name + '.1.running_mean']) 18 | bn_var = np.array(t[name + '.1.running_var']) 19 | 20 | # y1 = weight * x + bias 21 | # y2 = gamma * (y1 - mean) / sqrt(var + e) + beta 22 | 23 | # convolution: [out, in, x, y] 24 | 25 | weight *= bn_gamma[:, np.newaxis, np.newaxis, np.newaxis] 26 | 27 | bias = bn_gamma * bias + bn_beta * np.sqrt(bn_var + 1e-5) 28 | 29 | bn_mean *= bn_gamma 30 | 31 | return [weight, bias, bn_mean, bn_var] 32 | 33 | def write_block(f, b): 34 | for w in b: 35 | f.write(' '.join(map(str, w.flatten())) + '\n') 36 | 37 | if 0: 38 | for key in state.keys(): 39 | print(key, state[key].shape) 40 | 41 | with open('elf_converted_weights.txt', 'w') as f: 42 | # version 2 means value head is for black, not for side to move 43 | f.write('2\n') 44 | if 'init_conv.0.weight' in state: 45 | b = convert_block(state, 'init_conv') 46 | else: 47 | b = convert_block(state, 'init_conv.module') 48 | 49 | # Permutate input planes 50 | p = [0, 2, 4, 6, 8, 10, 12, 14, 1, 3, 5, 7, 9, 11, 13, 15, 16, 17] 51 | 52 | b[0] = b[0][:,p,:,:] 53 | 54 | write_block(f, b) 55 | for block in range(20): 56 | b = convert_block(state, 'resnet.module.resnet.{}.conv_lower'.format(block)) 57 | write_block(f, b) 58 | b = convert_block(state, 'resnet.module.resnet.{}.conv_upper'.format(block)) 59 | write_block(f, b) 60 | b = convert_block(state, 'pi_final_conv') 61 | write_block(f, b) 62 | f.write(tensor_to_str(state['pi_linear.weight']) + '\n') 63 | f.write(tensor_to_str(state['pi_linear.bias']) + '\n') 64 | b = convert_block(state, 'value_final_conv') 65 | write_block(f, b) 66 | f.write(tensor_to_str(state['value_linear1.weight']) + '\n') 67 | f.write(tensor_to_str(state['value_linear1.bias']) + '\n') 68 | f.write(tensor_to_str(state['value_linear2.weight']) + '\n') 69 | f.write(tensor_to_str(state['value_linear2.bias']) + '\n') 70 | -------------------------------------------------------------------------------- /training/tf/average_weights.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # 3 | # This file is part of SAI, which is a fork of Leela Zero. 4 | # Copyright (C) 2017 Henrik Forsten 5 | # 6 | # SAI is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # SAI is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with SAI. If not, see . 18 | 19 | import argparse 20 | import numpy as np 21 | 22 | def swa(inputs, output, weights=None): 23 | """ Average weights of the weight files. 24 | 25 | inputs : List of filenames to use as inputs 26 | output : String of output filename 27 | weights : List of numbers to use for weighting the inputs 28 | """ 29 | 30 | out_weights = [] 31 | 32 | if weights == None: 33 | weights = [1.0]*len(inputs) 34 | 35 | if len(weights) != len(inputs): 36 | raise ValueError("Number of weights doesn't match number of input files") 37 | 38 | # Normalize weights 39 | weights = [float(w)/sum(weights) for w in weights] 40 | 41 | for count, filename in enumerate(inputs): 42 | with open(filename, 'r') as f: 43 | weights_in = [] 44 | for line in f: 45 | weights_in.append(weights[count] * np.array(list(map(float, line.split(' '))))) 46 | if count == 0: 47 | out_weights = weights_in 48 | else: 49 | if len(out_weights) != len(weights_in): 50 | raise ValueError("Nets have different sizes") 51 | for e, w in enumerate(weights_in): 52 | if len(w) != len(out_weights[e]): 53 | raise ValueError("Nets have different sizes") 54 | out_weights[e] += w 55 | 56 | with open(output, 'w') as f: 57 | for e, w in enumerate(out_weights): 58 | if e == 0: 59 | #Version 60 | f.write('1\n') 61 | else: 62 | f.write(' '.join(map(str, w)) + '\n') 63 | 64 | if __name__ == "__main__": 65 | parser = argparse.ArgumentParser(description='Average weight files.') 66 | parser.add_argument('-i', '--inputs', nargs='+', 67 | help='List of input weight files') 68 | parser.add_argument('-w', '--weights', type=float, nargs='+', 69 | help='List of weights to use for the each weight file during averaging.') 70 | parser.add_argument('-o', '--output', help='Output filename') 71 | 72 | args = parser.parse_args() 73 | 74 | swa(args.inputs, args.output, args.weights) 75 | -------------------------------------------------------------------------------- /training/tf/dumper/mongo_training.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import gzip 4 | import pymongo 5 | 6 | client = pymongo.MongoClient() 7 | db = client.test 8 | 9 | # MongoDB closes idle cursors after 10 minutes unless specific 10 | # options are given. That means this query will time out before 11 | # we finish. Rather than keeping it alive, increase the default 12 | # batch size so we're sure to get all networks in the first fetch. 13 | networks = db.networks.find(None, {"_id": False, "hash": True}).\ 14 | sort("_id", pymongo.DESCENDING).batch_size(5000) 15 | 16 | game_count = 0 17 | total_game_count = 0 18 | chunk_file = None 19 | 20 | def get_chunk_name(hash): 21 | return "train_" + hash[0:8] + "_" + str(chunk_count) + ".gz" 22 | 23 | for net in networks: 24 | print("Searching for {}".format(net['hash'])) 25 | 26 | games = db.games.\ 27 | find({"networkhash": net['hash']}, 28 | {"_id": False, "data": True}) 29 | 30 | chunk_count = 0 31 | if chunk_file: 32 | chunk_file.close() 33 | chunk_file = gzip.open(get_chunk_name(net['hash']), 'w', 1) 34 | 35 | for game in games: 36 | game_data = game['data'] 37 | chunk_file.write(game_data.encode("ascii")) 38 | game_count += 1 39 | total_game_count += 1 40 | if game_count >= 64: 41 | chunk_file.close() 42 | chunk_count += 1 43 | chunk_file = gzip.open(get_chunk_name(net['hash']), 'w', 1) 44 | game_count = 0 45 | print("Net {} Chunk {} written".format(net['hash'][0:8], chunk_count)) 46 | if total_game_count >= 275000: 47 | chunk_file.close() 48 | quit() 49 | 50 | chunk_file.close() 51 | -------------------------------------------------------------------------------- /training/tf/gammadiff.py: -------------------------------------------------------------------------------- 1 | #!/home/vandertic/tf-gpu-1.13.1/bin/python 2 | 3 | import sys 4 | import os 5 | import numpy as np 6 | 7 | for arg in sys.argv[1:]: 8 | base = os.path.basename(arg) 9 | name, ext = os.path.splitext(base) 10 | if ext != '.gamma': 11 | # print(f'No: {ext}') 12 | continue 13 | print(name) 14 | 15 | file = open(arg, 'r') 16 | 17 | i = 0 18 | 19 | line = file.readline() 20 | 21 | while line != "": 22 | i += 1 23 | line = line.split() 24 | line = [float(x) for x in line] 25 | line = np.array(line) 26 | norm = np.linalg.norm(np.log(line)) 27 | diff = line - 1 28 | print(i, len(diff), diff.min(), diff.max(), norm) 29 | 30 | line = file.readline() 31 | 32 | -------------------------------------------------------------------------------- /training/tf/mixprec.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | 3 | 4 | def float32_variable_storage_getter(getter, name, shape=None, dtype=None, 5 | initializer=None, regularizer=None, 6 | trainable=True, 7 | *args, **kwargs): 8 | """Custom variable getter that forces trainable variables to be stored in 9 | float32 precision and then casts them to the training precision.""" 10 | storage_dtype = tf.float32 if trainable else dtype 11 | variable = getter(name, shape, dtype=storage_dtype, 12 | initializer=initializer, 13 | regularizer=regularizer, 14 | trainable=trainable, 15 | *args, **kwargs) 16 | if trainable and dtype != tf.float32: 17 | cast_name = name + '/fp16_cast' 18 | try: 19 | cast_variable = tf.get_default_graph().get_tensor_by_name( 20 | cast_name + ':0') 21 | except KeyError: 22 | cast_variable = tf.cast(variable, dtype, name=cast_name) 23 | cast_variable._ref = variable._ref 24 | variable = cast_variable 25 | return variable 26 | 27 | 28 | class LossScalingOptimizer(tf.train.Optimizer): 29 | """An optimizer that scales loss and un-scales gradients.""" 30 | 31 | def __init__(self, optimizer, 32 | scale=None, 33 | name="LossScalingOptimizer", 34 | use_locking=False): 35 | super(LossScalingOptimizer, self).__init__( 36 | name=name, use_locking=use_locking) 37 | self._optimizer = optimizer 38 | self._scale = float(scale) if scale is not None else 1.0 39 | 40 | def compute_gradients(self, loss, var_list=None, *args, **kwargs): 41 | if self._scale != 1.0: 42 | loss = tf.scalar_mul(self._scale, loss) 43 | gradvar = self._optimizer.compute_gradients(loss, var_list, *args, **kwargs) 44 | gradvar = [(tf.scalar_mul(1. / self._scale, g), v) for g, v in gradvar] 45 | return gradvar 46 | 47 | def apply_gradients(self, *args, **kwargs): 48 | return self._optimizer.apply_gradients(*args, **kwargs) 49 | -------------------------------------------------------------------------------- /training/tf/net_to_model.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import os 3 | import sys 4 | from config import * 5 | from tfprocess import TFProcess 6 | 7 | with open(sys.argv[1], 'r') as f: 8 | weights = [] 9 | for e, line in enumerate(f): 10 | if e == 0: 11 | #Version 12 | print("Version", line.strip()) 13 | if line != WEIGHTS_FILE_VER + '\n': 14 | raise ValueError("Unknown version {}".format(line.strip())) 15 | else: 16 | weights.append(list(map(float, line.split(' ')))) 17 | if e == 2: 18 | channels = len(line.split(' ')) 19 | print("Channels", channels) 20 | 21 | blocks = e - (4 + 14) 22 | # if blocks % 8 != 0: 23 | # raise ValueError("Inconsistent number of weights in the file") 24 | # blocks //= 8 25 | # print("Blocks", blocks) 26 | 27 | tfprocess = TFProcess(12, channels, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) 28 | tfprocess.init(batch_size=1, gpus_num=1) 29 | tfprocess.replace_weights(weights) 30 | path = os.path.join(os.getcwd(), "leelaz-model") 31 | save_path = tfprocess.saver.save(tfprocess.session, path, global_step=0) 32 | -------------------------------------------------------------------------------- /training/tf/quantize_weights.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import sys, os, argparse 3 | 4 | def format_n(x): 5 | x = float(x) 6 | x = '{:.3g}'.format(x) 7 | x = x.replace('e-0', 'e-') 8 | if x.startswith('0.'): 9 | x = x[1:] 10 | if x.startswith('-0.'): 11 | x = '-' + x[2:] 12 | return x 13 | 14 | if __name__ == "__main__": 15 | 16 | parser = argparse.ArgumentParser( 17 | description='Quantize network file to decrease the file size.') 18 | parser.add_argument("input", 19 | help='Input file', type=str) 20 | 21 | parser.add_argument("-o", "--output", 22 | help='Output file. Defaults to input + "_quantized"', 23 | required=False, type=str, default=None) 24 | 25 | args = parser.parse_args() 26 | 27 | if args.output == None: 28 | output_name = os.path.splitext(sys.argv[1]) 29 | output_name = output_name[0] + '_quantized' + output_name[1] 30 | else: 31 | output_name = args.output 32 | output = open(output_name, 'w') 33 | 34 | calculate_error = True 35 | error = 0 36 | 37 | with open(args.input, 'r') as f: 38 | for line in f: 39 | line = line.split(' ') 40 | lineq = list(map(format_n, line)) 41 | 42 | if calculate_error: 43 | e = sum((float(line[i]) - float(lineq[i]))**2 for i in range(len(line))) 44 | error += e/len(line) 45 | output.write(' '.join(lineq) + '\n') 46 | 47 | if calculate_error: 48 | print('Weight file difference L2-norm: {}'.format(error**0.5)) 49 | 50 | output.close() 51 | -------------------------------------------------------------------------------- /training/tf/requirements.txt: -------------------------------------------------------------------------------- 1 | bleach==1.5.0 2 | enum34==1.1.6 3 | futures==3.1.1 4 | html5lib==0.9999999 5 | Markdown==2.6.9 6 | numpy==1.13.3 7 | protobuf==3.4.0 8 | scipy==1.0.0 9 | six==1.11.0 10 | tensorflow>=1.12.1 11 | tensorflow-tensorboard==0.4.0rc2 12 | Werkzeug==0.15.3 13 | -------------------------------------------------------------------------------- /training/tf/save-gamma.py: -------------------------------------------------------------------------------- 1 | #!/home/vandertic/tf-gpu-1.13.1/bin/python 2 | 3 | import sys 4 | import os 5 | from tfprocess import TFProcess 6 | 7 | tfprocess = TFProcess(12, 256, 0.05, 1000, 1000, 1000, 5, 1, 1, 0, 0, 1, 2, 0) 8 | tfprocess.init(128, logbase="../gamma", macrobatch=4) 9 | 10 | for arg in sys.argv[1:]: 11 | base = os.path.basename(arg) 12 | name, ext = os.path.splitext(base) 13 | if ext != '.meta': 14 | # print(f'No: {ext}') 15 | continue 16 | print(name) 17 | rest = os.path.splitext(arg)[0] 18 | tfprocess.restore(rest) 19 | tfprocess.save_gamma_weights(rest + ".gamma") 20 | -------------------------------------------------------------------------------- /training/tf/save-w.py: -------------------------------------------------------------------------------- 1 | from tfprocess import TFProcess 2 | tfprocess = TFProcess(12, 256, 0.05, 1000, 1000, 1000, 5, 1, 1, 0, 0, 1, 2, 0) 3 | tfprocess.init(128, logbase="test00", macrobatch=4) 4 | tfprocess.restore("../g26d-76897f32-4920h") 5 | tfprocess.save_leelaz_weights("prova") 6 | -------------------------------------------------------------------------------- /training/tf/shufflebuffer.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # 3 | # This file is part of SAI, which is a fork of Leela Zero. 4 | # Copyright (C) 2018 Michael O 5 | # Copyright (C) 2018-2019 SAI Team 6 | # 7 | # SAI is free software: you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation, either version 3 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # SAI is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with SAI. If not, see . 19 | 20 | import random 21 | import unittest 22 | 23 | class ShuffleBuffer: 24 | def __init__(self, elem_size, elem_count): 25 | """ 26 | A shuffle buffer for fixed sized elements. 27 | 28 | Manages 'elem_count' items in a fixed buffer, each item being exactly 29 | 'elem_size' bytes. 30 | """ 31 | assert elem_size > 0, elem_size 32 | assert elem_count > 0, elem_count 33 | # Size of each element. 34 | self.elem_size = elem_size 35 | # Number of elements in the buffer. 36 | self.elem_count = elem_count 37 | # Fixed size buffer used to hold all the element. 38 | self.buffer = bytearray(elem_size * elem_count) 39 | # Number of elements actually contained in the buffer. 40 | self.used = 0 41 | 42 | def extract(self): 43 | """ 44 | Return an item from the shuffle buffer. 45 | 46 | If the buffer is empty, returns None 47 | """ 48 | if self.used < 1: 49 | return None 50 | # The items in the shuffle buffer are held in shuffled order 51 | # so returning the last item is sufficient. 52 | self.used -= 1 53 | i = self.used 54 | return self.buffer[i * self.elem_size : (i+1) * self.elem_size] 55 | 56 | def insert_or_replace(self, item): 57 | """ 58 | Inserts 'item' into the shuffle buffer, returning 59 | a random item. 60 | 61 | If the buffer is not yet full, returns None 62 | """ 63 | assert len(item) == self.elem_size, len(item) 64 | # putting the new item in a random location, and appending 65 | # the displaced item to the end of the buffer achieves a full 66 | # random shuffle (Fisher-Yates) 67 | if self.used > 0: 68 | # swap 'item' with random item in buffer. 69 | i = random.randint(0, self.used-1) 70 | old_item = self.buffer[i * self.elem_size : (i+1) * self.elem_size] 71 | self.buffer[i * self.elem_size : (i+1) * self.elem_size] = item 72 | item = old_item 73 | # If the buffer isn't yet full, append 'item' to the end of the buffer. 74 | if self.used < self.elem_count: 75 | # Not yet full, so place the returned item at the end of the buffer. 76 | i = self.used 77 | self.buffer[i * self.elem_size : (i+1) * self.elem_size] = item 78 | self.used += 1 79 | return None 80 | return item 81 | 82 | 83 | class ShuffleBufferTest(unittest.TestCase): 84 | def test_extract(self): 85 | sb = ShuffleBuffer(3, 1) 86 | r = sb.extract() 87 | assert r == None, r # empty buffer => None 88 | r = sb.insert_or_replace(b'111') 89 | assert r == None, r # buffer not yet full => None 90 | r = sb.extract() 91 | assert r == b'111', r # one item in buffer => item 92 | r = sb.extract() 93 | assert r == None, r # buffer empty => None 94 | def test_wrong_size(self): 95 | sb = ShuffleBuffer(3, 1) 96 | try: 97 | sb.insert_or_replace(b'1') # wrong length, so should throw. 98 | assert False # Should not be reached. 99 | except: 100 | pass 101 | def test_insert_or_replace(self): 102 | n=10 # number of test items. 103 | items=[bytes([x,x,x]) for x in range(n)] 104 | sb = ShuffleBuffer(elem_size=3, elem_count=2) 105 | out=[] 106 | for i in items: 107 | r = sb.insert_or_replace(i) 108 | if not r is None: 109 | out.append(r) 110 | # Buffer size is 2, 10 items, should be 8 seen so far. 111 | assert len(out) == n - 2, len(out) 112 | # Get the last two items. 113 | out.append(sb.extract()) 114 | out.append(sb.extract()) 115 | assert sorted(items) == sorted(out), (items, out) 116 | # Check that buffer is empty 117 | r = sb.extract() 118 | assert r is None, r 119 | 120 | 121 | if __name__ == '__main__': 122 | unittest.main() 123 | -------------------------------------------------------------------------------- /training/tf/test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | import os 4 | 5 | if os.path.exists('request-save-model'): 6 | print('yes') 7 | else: 8 | print('no') 9 | -------------------------------------------------------------------------------- /utils/KomiSample.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define MULT 20 // 40 6 | #define COEFF 2.0f // shrink coefficient for dispersion 7 | #define RESERVE 0.0 // 0.3f 8 | #define OFFICIAL_KOMI 9.0 // 9.5f 9 | #define SHIFT 0.0 // 0.5f 10 | constexpr double step=0.5; 11 | 12 | double distrib (double x, double mean, double dev) { 13 | return 1.0/(1.0+std::exp(-(x-mean)/dev)); 14 | } 15 | 16 | double inv_dist (double p, double mean, double dev) { 17 | return mean + dev * std::log(p/(1.0-p)); 18 | } 19 | 20 | int main (int argc, char* argv[]) { 21 | 22 | unsigned int totalgames = 5120; 23 | 24 | if(argc >= 2) { 25 | totalgames = std::stoi(argv[1]); 26 | } 27 | 28 | 29 | 30 | std::string tmp; 31 | std::cin >> tmp; 32 | const auto alpha = std::stof(tmp); 33 | const auto mean = alpha + SHIFT; 34 | 35 | std::cin >> tmp; 36 | const auto beta = std::stof(tmp); 37 | const auto dev = 1.0/(beta*COEFF); 38 | 39 | // std::cout << "Read parameters: alpha=" << alpha 40 | // << ", beta=" << beta << std::endl 41 | // << "Sample size " << N 42 | // << ", coefficient " << COEFF << std::endl; 43 | 44 | const unsigned int blocks = std::lround(totalgames*(1.0-RESERVE)/double(MULT)); 45 | const unsigned int reserved_games = totalgames - blocks*MULT; 46 | 47 | const auto lowest_real = inv_dist(0.5/blocks, mean, dev) - 0.5 * step; 48 | const auto highest_real = inv_dist(1.0 - 0.5/blocks, mean, dev) + 0.5 * step; 49 | const auto lowest_komi = OFFICIAL_KOMI + step * std::ceil( (lowest_real - OFFICIAL_KOMI) / step ); 50 | const auto highest_komi = OFFICIAL_KOMI + step * std::ceil( (highest_real - OFFICIAL_KOMI) / step - 1.0 ); 51 | 52 | for (auto k = lowest_komi ; k < highest_komi + 0.5*step ; k += step) { 53 | const auto games = std::round(blocks * distrib(k + 0.5*step, mean, dev)) 54 | -std::round(blocks * distrib(k - 0.5*step, mean, dev)) 55 | + (std::abs(k-OFFICIAL_KOMI) < 0.5*step ? reserved_games : 0); 56 | if (games>0) { 57 | std::cout << "curl -F number_to_play=" << games * MULT 58 | << " -F komi=" << k 59 | << " -F other_options=\"${SAI_OTHEROPTIONS}\" $KOMIS_CMD_STRING" 60 | << std::endl; 61 | } 62 | } 63 | 64 | return 0; 65 | } 66 | -------------------------------------------------------------------------------- /utils/NetColorEval.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | std::array weightswht = {0.001, 0.001, 0.001, 0.03088321, 0.01211115, 6 | 0.37131672, 0.02297181, 0.40003006, 0.49160695, 0.01789272, 7 | 0.08280381, 0.06084046, 0.02789337, 0.2503669, 0.62004198}; 8 | 9 | std::array weightsblk = {0.001, 0.00597199, 0.02775871, 0.10541281, 0.15726762, 10 | 0.37896146, 0.28796306, 0.48513024, 0.03057332, 0.05677957, 11 | 0.16795283, 0.12024328, 0.20015829, 0.60185867, 0.22877867}; 12 | 13 | 14 | 15 | int main(int argc, char* argv[]) { 16 | bool as_black_too=true; 17 | 18 | if(argc >= 2) { 19 | std::string arg = argv[1]; 20 | if(0 == arg.compare(std::string{"-w"})) { 21 | as_black_too=false; 22 | } 23 | } 24 | 25 | std::string buf; 26 | std::cin >> buf >> buf; 27 | 28 | float val = 0.0f; 29 | for (auto i = 0; i<15 ; ++i) { 30 | float winswht, losswht, winsblk, lossblk; 31 | std::cin >> winsblk >> winswht >> lossblk >> losswht; 32 | auto wrwht = 0.5f; 33 | if (winswht+losswht>=1.0f) { 34 | wrwht = winswht/(winswht+losswht); 35 | } 36 | val += wrwht*weightswht[i]; 37 | if (as_black_too) { 38 | auto wrblk = 0.5f; 39 | if (winsblk+lossblk>=1.0f) { 40 | wrblk = winsblk/(winsblk+lossblk); 41 | } 42 | val += wrblk*weightsblk[i]; 43 | } 44 | } 45 | 46 | std::cout << val << std::endl; 47 | 48 | return 0; 49 | } 50 | -------------------------------------------------------------------------------- /utils/NetEval.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | std::array means = {0.9533274235, 0.9287059913, 0.8929619049, 0.7879189113, 0.7221856119, 5 | 0.5671358464, 0.6534111856, 0.2734502325, 0.165120555, 0.7405820716, 6 | 0.3864972585, 0.340824635, 0.6591981697, 0.3688741877, 0.2167708809}; 7 | 8 | std::array pca_w = {0.04, 0.0616, 0.0926, 0.1797, 0.2244, 9 | 0.3818, 0.3166, 0.3733, 0.1388, 0.1859, 10 | 0.3066, 0.2164, 0.3151, 0.4145, 0.2288}; 11 | 12 | 13 | int main() { 14 | float val = 0.0f; 15 | 16 | for (auto i = 0; i<15 ; ++i) { 17 | float wins, losses; 18 | std::cin >> wins >> losses; 19 | auto wr = 0.5f; 20 | if (wins+losses>=1.0f) { 21 | wr = wins/(wins+losses); 22 | } 23 | val += (wr-means[i])*pca_w[i]; 24 | } 25 | 26 | std::cout << val << std::endl; 27 | 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /utils/NetGenEval.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | const std::array weightswht = {0.001, 0.001, 0.001, 0.03088321, 0.01211115, 8 | 0.37131672, 0.02297181, 0.40003006, 0.49160695, 0.01789272, 9 | 0.08280381, 0.06084046, 0.02789337, 0.2503669, 0.62004198}; 10 | 11 | const std::array weightsblk = {0.001, 0.00597199, 0.02775871, 0.10541281, 0.15726762, 12 | 0.37896146, 0.28796306, 0.48513024, 0.03057332, 0.05677957, 13 | 0.16795283, 0.12024328, 0.20015829, 0.60185867, 0.22877867}; 14 | 15 | const std::array weightsold = {0.04, 0.0616, 0.0926, 0.1797, 0.2244, 16 | 0.3818, 0.3166, 0.3733, 0.1388, 0.1859, 17 | 0.3066, 0.2164, 0.3151, 0.4145, 0.2288}; 18 | 19 | const float oldavg = 1.77021488; 20 | 21 | 22 | class rv { 23 | public: 24 | int n() const { return m_num; } 25 | float mean() const { return m_mean; } 26 | float var() const { return m_var; } 27 | float sd() const { return m_sd; } 28 | void update(int wins, int loss, float wheight); 29 | 30 | private: 31 | int m_num{0}; 32 | float m_mean{0.0f}; 33 | float m_var{0.0f}; 34 | float m_sd{0.0f}; 35 | }; 36 | 37 | 38 | void rv::update(int wins, int loss, float weight) { 39 | auto winrate = 0.5f; 40 | auto wr_var = 1.0f; 41 | 42 | const auto num = std::max( 0.5f, float(wins * loss) ); 43 | const auto den = wins + loss; 44 | 45 | if (den >= 1) { 46 | winrate = float(wins)/den; 47 | wr_var = num / (den*den*den); // X(n-X)/n^3 = p(1-p)/n 48 | } 49 | 50 | m_num++; 51 | m_mean += winrate * weight; 52 | m_var += wr_var * weight * weight; 53 | m_sd = std::sqrt(m_var); 54 | } 55 | 56 | int main() { 57 | std::string buf; 58 | std::cin >> buf >> buf; 59 | 60 | rv newwht, newblk, sumwht, sumblk, oldpca; 61 | 62 | for (auto i = 0; i<15 ; ++i) { 63 | float winswht, losswht, winsblk, lossblk; 64 | std::cin >> winsblk >> winswht >> lossblk >> losswht; 65 | 66 | newwht.update(winswht, losswht, weightswht[i]); 67 | newblk.update(winsblk, lossblk, weightsblk[i]); 68 | sumwht.update(winswht, losswht, 1.0f); 69 | sumblk.update(winsblk, lossblk, 1.0f); 70 | oldpca.update(winswht+winsblk, losswht+lossblk, weightsold[i]); 71 | } 72 | 73 | std::cout << newwht.mean() << " " << newwht.sd() << " " 74 | << newwht.mean()+newblk.mean() << " " << std::sqrt(newwht.var()+newblk.var()) << " " 75 | << sumwht.mean() << " " << sumwht.sd() << " " 76 | << sumwht.mean()+sumblk.mean() << " " << std::sqrt(sumwht.var()+sumblk.var()) << " " 77 | << oldpca.mean()-oldavg << " " << oldpca.sd() 78 | << std::endl; 79 | 80 | return 0; 81 | } 82 | -------------------------------------------------------------------------------- /utils/PanelColorParse.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() { 6 | std::array panelhash = { 7 | "2991c83a", 8 | "bc627734", 9 | "bfb90b36", 10 | "2c5e522d", 11 | "d9c5d4fb", 12 | "1272232d", 13 | "3b0df457", 14 | "ad4f55da", 15 | "3c6c1c4b", 16 | "739dff8e", 17 | "ff16cc71", 18 | "83f30a3e", 19 | "344fb61f", 20 | "afd1c7e9", 21 | "12537226" 22 | }; 23 | // std::array, 15> result; 24 | 25 | for (size_t i=0 ; i<15 ; ++i) { 26 | std::string hash; 27 | std::cin >> hash; 28 | 29 | if (hash!=panelhash[i]) { 30 | std::cerr << "Expected panel hash " << panelhash[i] 31 | << ", observed" << hash << std::endl; 32 | return 1; 33 | } 34 | 35 | std::array result; 36 | int games=0; 37 | 38 | for (size_t j=0 ; j<4 ; ++j) { 39 | std::cin >> result[j]; 40 | games += result[j]; 41 | } 42 | 43 | if (games < 100) { 44 | std::cerr << "Panel hash " << panelhash[i] 45 | << " has only " << games 46 | << ", but at least 100 were expected." << std::endl; 47 | return 1; 48 | } 49 | for (size_t j=0 ; j<4 ; ++j) { 50 | std::cout << result[j]; 51 | if (i<14 || j<3) { 52 | std::cout << " "; 53 | } 54 | } 55 | } 56 | std::cout << std::endl; 57 | 58 | return 0; 59 | } 60 | -------------------------------------------------------------------------------- /utils/ParseChunks.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This program counts the (approximate) number of nodes created for 3 | all the games in a chunk. 4 | 5 | Usage: 6 | gunzip * -c | nodecount 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | //#define VISITS 160 17 | #define GOBAN_SIZE 9 18 | 19 | struct one_komi_stats { 20 | float komi; 21 | unsigned int bwg; 22 | unsigned int bwm; 23 | unsigned int wwg; 24 | unsigned int wwm; 25 | unsigned int mvs; 26 | }; 27 | 28 | bool compare(const one_komi_stats& a, const one_komi_stats& b) { 29 | return a.komi &stats) { 34 | unsigned int j; 35 | 36 | for (j=0 ; j stats; 63 | 64 | while (std::cin >> buf) { 65 | ++line; 66 | 67 | // check whether the goban is empty 68 | int chknil = buf.compare(hexnil); // 0 if goban empty (1/16) 69 | for (int i=0; i<15; i++) { 70 | 71 | // skip the 16 lines describing the position 72 | std::cin >> buf; 73 | ++line; 74 | 75 | // check whether this is the starting position, otherwise 1 76 | if (!chknil && buf.compare(hexnil)) 77 | chknil = 1; 78 | } 79 | 80 | // skip line 17, with the player and komi 81 | int stm; 82 | std::cin >> stm; 83 | std::cin >> komi; 84 | ++line; 85 | 86 | j = komi_index(komi, stats); 87 | ++stats[j].mvs; 88 | 89 | for (int i=0; i> polprb; 95 | 96 | // assert (0 == ((int)round(1000*polprb*(VISITS-1)) % 1000)); 97 | } 98 | ++line; 99 | 100 | // skip line 19, with the winner 101 | std::cin >> winner; 102 | ++line; 103 | ++moves; 104 | 105 | // if starting position, the former maxnodes should have never 106 | // been subtracted, because after the last position there is no 107 | // more tree re-use 108 | if (!chknil && stm == 0) { 109 | assert (winner == 0 || winner == 1 || winner == -1); 110 | ++games; 111 | if (lastwinner == 1) { 112 | ++stats[j].bwg; 113 | stats[j].bwm += moves; 114 | } 115 | else if (lastwinner == -1) { 116 | ++stats[j].wwg; 117 | stats[j].wwm += moves; 118 | } 119 | moves = 0; 120 | lastwinner = winner; 121 | } 122 | 123 | } 124 | if (lastwinner == 1) { 125 | ++stats[j].bwg; 126 | stats[j].bwm += moves; 127 | } 128 | else if (lastwinner == -1) { 129 | ++stats[j].wwg; 130 | stats[j].wwm += moves; 131 | } 132 | 133 | sort(stats.begin(), stats.end(), compare); 134 | 135 | std::cout << "Total games found: " << games << std::endl; 136 | for (unsigned int j=0 ; j 7 | #include 8 | #include 9 | 10 | #define PLANES 17 // was 18 11 | #define LAYERS 2 12 | #define FILTERS 64 13 | #define GOBAN_AREA 81 // now on 9x9 14 | #define MOVES 82 15 | #define VHEADFILTERS 64 16 | #define VHEADS 2 17 | 18 | int weights_line (int input, int output) // a line of n weights 19 | { 20 | std::random_device rd; 21 | std::mt19937 gen{rd()}; 22 | std::normal_distribution d{0,1}; 23 | 24 | std::cout << std::endl; 25 | 26 | const int n=input*output; 27 | 28 | // standard deviation is as prescribed by Xavier initialization 29 | const float s=std::sqrt(2.0f/(input+output)); 30 | 31 | for (int i = 0; i2.0f); 38 | if (i == 0) 39 | std::cout << x*s; 40 | else 41 | std::cout << " " << x*s; 42 | } 43 | 44 | return 0; 45 | } 46 | 47 | int const_line (int n, float x) 48 | { 49 | std::cout << std::endl 50 | << x; 51 | for (int i = 1; i. 17 | */ 18 | 19 | #include "Results.h" 20 | #include "../autogtp/Game.h" 21 | #include "SPRT.h" 22 | #include 23 | #include 24 | 25 | void Results::addGameResult(Sprt::GameResult result, int side) { 26 | m_gamesPlayed++; 27 | if (result == Sprt::GameResult::Win) { 28 | if (side == Game::BLACK) 29 | m_blackWins++; 30 | else 31 | m_whiteWins++; 32 | } else { 33 | if (side == Game::BLACK) 34 | m_blackLosses++; 35 | else 36 | m_whiteLosses++; 37 | } 38 | } 39 | 40 | std::string winPercentColumn(int wins, int games) { 41 | auto line = QString::asprintf(" %4d %5.2f%%", wins, 42 | 100.0f * (wins / (float)games)); 43 | return line.toStdString(); 44 | } 45 | 46 | void Results::printResults(const QString& firstNetName, 47 | const QString& secondNetName) const { 48 | /* 49 | Produces reports in this format. 50 | ABCD1234 v DEFG5678 (176 games) 51 | wins black white 52 | ABDC1234 65 36.93% 37 42.53% 28 31.46% 53 | DEFG5678 111 63.07% 61 68.54% 50 57.47% 54 | 98 55.68% 78 44.32% 55 | */ 56 | auto first_name = firstNetName.leftJustified(8, ' ', true)\ 57 | .toStdString(); 58 | auto second_name = secondNetName.leftJustified(8, ' ', true)\ 59 | .toStdString(); 60 | 61 | // Results for player one 62 | auto p1_wins = m_blackWins + m_whiteWins; 63 | auto p1_losses = m_blackLosses + m_whiteLosses; 64 | 65 | // Results for black vs white 66 | auto black_wins = m_blackWins + m_whiteLosses; 67 | auto white_wins = m_whiteWins + m_blackLosses; 68 | 69 | // Formatted title line 70 | auto title_line = QString::asprintf("%13s %-11s %-11s %s\n", 71 | "", "wins", "black", "white"); 72 | 73 | std::cout 74 | << first_name << " v " << second_name 75 | << " ( " << m_gamesPlayed << " games)" << std::endl; 76 | std::cout << title_line.toStdString(); 77 | std::cout 78 | << first_name 79 | << winPercentColumn(p1_wins, m_gamesPlayed) 80 | << winPercentColumn(m_blackWins, black_wins) 81 | << winPercentColumn(m_whiteWins, white_wins) << std::endl; 82 | std::cout 83 | << second_name 84 | << winPercentColumn(p1_losses, m_gamesPlayed) 85 | << winPercentColumn(m_whiteLosses, black_wins) 86 | << winPercentColumn(m_blackLosses, white_wins) << std::endl; 87 | std::cout 88 | << std::string(20, ' ') 89 | << winPercentColumn(black_wins, m_gamesPlayed) 90 | << winPercentColumn(white_wins, m_gamesPlayed) << std::endl; 91 | } 92 | 93 | QTextStream& operator<<(QTextStream& stream, const Results& r) { 94 | stream << r.m_gamesPlayed << ' '; 95 | stream << r.m_blackWins << ' ' << r.m_blackLosses << ' '; 96 | stream << r.m_whiteWins << ' ' << r.m_whiteLosses << Qt::endl; 97 | return stream; 98 | } 99 | 100 | QTextStream& operator>>(QTextStream& stream, Results& r) { 101 | stream >> r.m_gamesPlayed; 102 | stream >> r.m_blackWins; 103 | stream >> r.m_blackLosses; 104 | stream >> r.m_whiteWins; 105 | stream >> r.m_whiteLosses; 106 | return stream; 107 | } 108 | -------------------------------------------------------------------------------- /validation/Results.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Leela Zero. 3 | Copyright (C) 2017-2018 Seth Troisi 4 | 5 | Leela Zero is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | Leela Zero is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with Leela Zero. If not, see . 17 | */ 18 | 19 | #ifndef RESULTS_H 20 | #define RESULTS_H 21 | 22 | #include "SPRT.h" 23 | #include 24 | 25 | 26 | class Results { 27 | public: 28 | Results() = default; 29 | int getGamesPlayed() const { return m_gamesPlayed; } 30 | void addGameResult(Sprt::GameResult result, int side); 31 | void printResults(const QString& firstNetName, 32 | const QString& secondNetName) const; 33 | 34 | friend QTextStream& operator<<(QTextStream& stream, const Results& r); 35 | friend QTextStream& operator>>(QTextStream& stream, Results& r); 36 | private: 37 | int m_gamesPlayed{0}; 38 | int m_blackWins{0}; 39 | int m_blackLosses{0}; 40 | int m_whiteWins{0}; 41 | int m_whiteLosses{0}; 42 | }; 43 | 44 | #endif // RESULT_H 45 | -------------------------------------------------------------------------------- /validation/SPRT.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Leela Zero. 3 | Copyright (C) 2017-2018 Marco Calignano 4 | originally taken from Cute Chess (http://github.com/cutechess) 5 | Copyright (C) 2016 Ilari Pihlajisto 6 | 7 | Leela Zero is free software: you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation, either version 3 of the License, or 10 | (at your option) any later version. 11 | 12 | Leela Zero is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with Leela Zero. If not, see . 19 | */ 20 | 21 | #ifndef SPRT_H 22 | #define SPRT_H 23 | /*! 24 | * \brief A Sequential Probability Ratio Test 25 | * 26 | * The Sprt class implements a Sequential Probability Ratio Test (SPRT) that 27 | * can be used as a termination criterion for stopping a match between two 28 | * players when the Elo difference is known to be outside of the specified 29 | * interval. 30 | * 31 | * \sa http://en.wikipedia.org/wiki/Sequential_probability_ratio_test 32 | */ 33 | 34 | #include 35 | #include 36 | #include 37 | 38 | class Sprt 39 | { 40 | public: 41 | /*! The result of the test. */ 42 | enum Result 43 | { 44 | Continue, //!< Continue monitoring 45 | AcceptH0, //!< Accept null hypothesis H0 46 | AcceptH1 //!< Accept alternative hypothesis H1 47 | }; 48 | 49 | /*! The result of a chess game. */ 50 | enum GameResult 51 | { 52 | NoResult = 0, //!< Game ended with no result 53 | Win, //!< First player won 54 | Loss, //!< First player lost 55 | Draw, //!< Game was drawn 56 | NotEnded //!< Game was interrupted 57 | }; 58 | 59 | /*! The status of the test. */ 60 | struct Status 61 | { 62 | Result result; //!< Test result 63 | double llr; //!< Log-likelihood ratio 64 | double lBound; //!< Lower bound 65 | double uBound; //!< Upper bound 66 | }; 67 | 68 | /*! Creates a new uninitialized Sprt object. */ 69 | Sprt(); 70 | 71 | /*! 72 | * Returns true if the SPRT is uninitialized; otherwise 73 | * returns false. 74 | */ 75 | bool isNull() const; 76 | 77 | /*! 78 | * Initializes the SPRT. 79 | * 80 | * \a elo0 is the Elo difference between player A and 81 | * player B for H0 and \a elo1 for H1. 82 | * 83 | * \a alpha is the maximum probability for a type I error and 84 | * \a beta for a type II error outside interval [elo0, elo1]. 85 | */ 86 | void initialize(double elo0, double elo1, 87 | double alpha, double beta); 88 | 89 | /*! Returns the current status of the test. */ 90 | Status status() const; 91 | 92 | /*! Returns current win/draw/loss score. */ 93 | std::tuple getWDL() const; 94 | 95 | /*! 96 | * Updates the test with \a result. 97 | * 98 | * After calling this function, status() should be called to 99 | * check if H0 or H1 can be accepted. 100 | */ 101 | void addGameResult(GameResult result); 102 | friend QTextStream& operator<<(QTextStream& stream, const Sprt& sprt); 103 | friend QTextStream& operator>>(QTextStream& stream, Sprt& sprt); 104 | private: 105 | double m_elo0; 106 | double m_elo1; 107 | double m_alpha; 108 | double m_beta; 109 | int m_wins; 110 | int m_losses; 111 | int m_draws; 112 | mutable QMutex m_mutex; 113 | }; 114 | 115 | #endif // SPRT_H 116 | -------------------------------------------------------------------------------- /validation/Validation.h: -------------------------------------------------------------------------------- 1 | #ifndef VALIDATION_H 2 | #define VALIDATION_H 3 | /* 4 | This file is part of Leela Zero. 5 | Copyright (C) 2017-2018 Marco Calignano 6 | 7 | Leela Zero is free software: you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation, either version 3 of the License, or 10 | (at your option) any later version. 11 | 12 | Leela Zero is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with Leela Zero. If not, see . 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include "SPRT.h" 28 | #include "../autogtp/Game.h" 29 | #include "Results.h" 30 | 31 | class ValidationWorker : public QThread { 32 | Q_OBJECT 33 | public: 34 | 35 | enum { 36 | RUNNING = 0, 37 | FINISHING 38 | }; 39 | ValidationWorker() = default; 40 | ValidationWorker(const ValidationWorker& w) : QThread(w.parent()) {} 41 | ~ValidationWorker() = default; 42 | void init(const QString& gpuIndex, 43 | const QVector& engines, 44 | const QString& keep, 45 | int expected); 46 | void run() override; 47 | void doFinish() { m_state.storeRelaxed(FINISHING); } 48 | 49 | signals: 50 | void resultReady(Sprt::GameResult r, int net_one_color); 51 | private: 52 | QVector m_engines; 53 | int m_expected; 54 | QString m_keepPath; 55 | QAtomicInt m_state; 56 | }; 57 | 58 | class Validation : public QObject { 59 | Q_OBJECT 60 | 61 | public: 62 | Validation(const int gpus, const int games, 63 | const QStringList& gpusList, 64 | QVector& engines, 65 | const QString& keep, 66 | QMutex* mutex, 67 | const float& h0, 68 | const float& h1); 69 | ~Validation() = default; 70 | void startGames(); 71 | void wait(); 72 | void loadSprt(); 73 | signals: 74 | void sendQuit(); 75 | public slots: 76 | void getResult(Sprt::GameResult result, int net_one_color); 77 | void storeSprt(); 78 | private: 79 | QMutex* m_mainMutex; 80 | QMutex m_syncMutex; 81 | Sprt m_statistic; 82 | Results m_results; 83 | QVector m_gamesThreads; 84 | int m_games; 85 | int m_gpus; 86 | QStringList m_gpusList; 87 | QVector& m_engines; 88 | QString m_keepPath; 89 | void quitThreads(); 90 | void saveSprt(); 91 | void printSprtStatus(const Sprt::Status& status); 92 | }; 93 | 94 | #endif 95 | -------------------------------------------------------------------------------- /validation/validation.pro: -------------------------------------------------------------------------------- 1 | QT -= gui 2 | 3 | TARGET = validation 4 | CONFIG += c++14 5 | CONFIG += warn_on 6 | CONFIG += console 7 | CONFIG -= app_bundle 8 | 9 | TEMPLATE = app 10 | 11 | SOURCES += main.cpp \ 12 | ../autogtp/Game.cpp \ 13 | SPRT.cpp \ 14 | Validation.cpp \ 15 | Results.cpp 16 | 17 | HEADERS += \ 18 | ../autogtp/Game.h \ 19 | SPRT.h \ 20 | Validation.h \ 21 | Results.h \ 22 | ../autogtp/Console.h 23 | --------------------------------------------------------------------------------