From 170e830a7a55c952efc8e5d44945fd9cc3833425 Mon Sep 17 00:00:00 2001 From: borg323 <39573933+borg323@users.noreply.github.com> Date: Mon, 28 Oct 2024 23:29:07 +0200 Subject: [PATCH 001/212] clean up onnx casts (#2084) --- src/neural/onnx/converter.cc | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/neural/onnx/converter.cc b/src/neural/onnx/converter.cc index 605e77fbd5..88878c87ba 100644 --- a/src/neural/onnx/converter.cc +++ b/src/neural/onnx/converter.cc @@ -467,8 +467,10 @@ std::string Converter::MakeLayerNorm(OnnxBuilder* builder, if (!options_.alt_layernorm) { return builder->LayerNormalization(name, input, gammas, betas, 1, eps); } - auto in = - builder->Cast(name + "/to_float", input, pblczero::TensorProto::FLOAT); + auto in = input; + if (GetDataType() != pblczero::TensorProto::FLOAT) { + in = builder->Cast(name + "/to_float", in, pblczero::TensorProto::FLOAT); + } auto flow = builder->ReduceMean(name + "/mean", in, {1}); in = builder->Sub(name + "/centered", in, flow); flow = builder->Mul(name + "/squared", in, in); @@ -479,7 +481,9 @@ std::string Converter::MakeLayerNorm(OnnxBuilder* builder, flow = builder->Sqrt(name + "/std", flow); flow = builder->Reciprocal(name + "/inv_std", flow); flow = builder->Mul(name + "/normalized", in, flow); - flow = builder->Cast(name + "/to_data_type", flow, GetDataType()); + if (GetDataType() != pblczero::TensorProto::FLOAT) { + flow = builder->Cast(name + "/to_data_type", flow, GetDataType()); + } flow = builder->Mul(name + "/gammas", flow, gammas); flow = builder->Add(name + "/betas", flow, betas); return flow; From b725fb2eb8c6125925a897f2eb835a19d3a371cd Mon Sep 17 00:00:00 2001 From: borg323 <39573933+borg323@users.noreply.github.com> Date: Mon, 28 Oct 2024 23:29:33 +0200 Subject: [PATCH 002/212] onnx make alt_mish work with other data types (#2082) --- src/neural/onnx/converter.cc | 24 +++++++++++++++++------- src/neural/xla/network_xla.cc | 2 ++ src/neural/xla/onnx2hlo.cc | 28 ++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 7 deletions(-) diff --git a/src/neural/onnx/converter.cc b/src/neural/onnx/converter.cc index 88878c87ba..19bb48c7ac 100644 --- a/src/neural/onnx/converter.cc +++ b/src/neural/onnx/converter.cc @@ -250,8 +250,7 @@ std::string Converter::EndOptionalBf16Fix(OnnxBuilder* builder, std::string Converter::MakeMish(OnnxBuilder* builder, const std::string& input, const std::string& name) { - if (!options_.alt_mish || options_.opset < 9 || - options_.data_type != WeightsToOnnxConverterOptions::DataType::kFloat32) { + if (!options_.alt_mish || options_.opset < 9) { std::string flow = input; flow = StartOptionalBf16Fix(builder, flow, name); if (options_.opset >= 18) { @@ -263,20 +262,31 @@ std::string Converter::MakeMish(OnnxBuilder* builder, const std::string& input, flow = builder->Tanh(name + "/tanh", flow); return builder->Mul(name, flow, input); } else { + auto in = input; + if (options_.data_type != + WeightsToOnnxConverterOptions::DataType::kFloat32) { + in = builder->Cast(name + "/to_float", in, + pblczero::TensorProto::FLOAT); + } const OnnxConst& two = static_cast(FloatOnnxConst({2.0f}, {1})); const OnnxConst& zero = static_cast(FloatOnnxConst({0.0f}, {1})); - auto e = builder->Exp(name + "/exp", input); + auto e = builder->Exp(name + "/exp", in); auto flow = builder->Add(name + "/e+2", e, two); auto n = builder->Mul(name + "/n", e, flow); flow = builder->Add(name + "/n+2", n, two); - auto d = builder->Div(name + "/d", input, flow); + auto d = builder->Div(name + "/d", in, flow); auto f = builder->Mul(name + "/n*d", n, d); flow = builder->Mul(name + "/2*d", d, two); - auto t = builder->Sub(name + "/in-2*d", input, flow); - flow = builder->Greater(name + "/compare", input, zero); - return builder->Where(name, flow, t, f); + auto t = builder->Sub(name + "/in-2*d", in, flow); + flow = builder->Greater(name + "/compare", in, zero); + flow = builder->Where(name, flow, t, f); + if (options_.data_type != + WeightsToOnnxConverterOptions::DataType::kFloat32) { + flow = builder->Cast(name + "/to_data_type", flow, GetDataType()); + } + return flow; } } diff --git a/src/neural/xla/network_xla.cc b/src/neural/xla/network_xla.cc index 055105db88..447a45c7b0 100644 --- a/src/neural/xla/network_xla.cc +++ b/src/neural/xla/network_xla.cc @@ -303,6 +303,8 @@ std::unique_ptr MakeXlaNetwork(const std::optional& w, WeightsToOnnxConverterOptions::StringToDataType( opts.GetOrDefault("datatype", "f32")); onnx_converter_options.opset = 22; // For full onnx bfloat16 support. + onnx_converter_options.alt_mish = + opts.GetOrDefault("alt_mish", false); auto converted = ConvertWeightsToOnnx(*w, onnx_converter_options); options = FillXlaRunnerFromOnnx(converted.onnx_model(), runner.get(), max_batch_size, steps, io_type); diff --git a/src/neural/xla/onnx2hlo.cc b/src/neural/xla/onnx2hlo.cc index a33923de25..effe987447 100644 --- a/src/neural/xla/onnx2hlo.cc +++ b/src/neural/xla/onnx2hlo.cc @@ -474,6 +474,8 @@ class Onnx2HloConverter { onnx_op_to_builder_["Gather"] = &Onnx2HloConverter::OpGather; onnx_op_to_builder_["GlobalAveragePool"] = &Onnx2HloConverter::OpGlobalAveragePool; + onnx_op_to_builder_["Greater"] = &Onnx2HloConverter::OpGreater; + onnx_op_to_builder_["Exp"] = &Onnx2HloConverter::OpExp; onnx_op_to_builder_["Expand"] = &Onnx2HloConverter::OpExpand; onnx_op_to_builder_["Identity"] = &Onnx2HloConverter::OpIdentity; onnx_op_to_builder_["LayerNormalization"] = @@ -502,6 +504,7 @@ class Onnx2HloConverter { onnx_op_to_builder_["Tanh"] = &Onnx2HloConverter::OpTanh; onnx_op_to_builder_["Transpose"] = &Onnx2HloConverter::OpTranspose; onnx_op_to_builder_["Unsqueeze"] = &Onnx2HloConverter::OpUnsqueeze; + onnx_op_to_builder_["Where"] = &Onnx2HloConverter::OpWhere; } Onnx2HloResult Convert(const pblczero::ModelProto& onnx_model, @@ -1492,6 +1495,31 @@ class Onnx2HloConverter { return {builder_.Multiply(flow, input)}; } + std::vector OpExp(const pblczero::NodeProto& node) { + CheckKnownAttributes(node, 1, {}); + auto* input = GetInput(node, 0); + return {builder_.Exponential(input)}; + } + + std::vector OpGreater(const pblczero::NodeProto& node) { + CheckKnownAttributes(node, 2, {}); + auto* lhs = GetInput(node, 0); + auto* rhs = GetInput(node, 1); + std::tie(lhs, rhs) = EqualizeShape(lhs, rhs); + return {builder_.Compare(lhs, rhs, "GT")}; + } + + std::vector OpWhere(const pblczero::NodeProto& node) { + CheckKnownAttributes(node, 3, {}); + auto* pred = GetInput(node, 0); + auto* on_true = GetInput(node, 1); + auto* on_false = GetInput(node, 2); + std::tie(on_true, on_false) = EqualizeShape(on_true, on_false); + std::tie(pred, on_true) = EqualizeShape(pred, on_true); + std::tie(pred, on_false) = EqualizeShape(pred, on_false); + return {builder_.Select(pred, on_true, on_false)}; + } + ///////////////////////////////////////////////////////////////////////////// // Helper computations ///////////////////////////////////////////////////////////////////////////// From 96f98aface79bb548cb6d2f2877f69c699d3e67a Mon Sep 17 00:00:00 2001 From: borg323 <39573933+borg323@users.noreply.github.com> Date: Mon, 28 Oct 2024 23:30:05 +0200 Subject: [PATCH 003/212] fix xla with multiple devices (#2081) --- src/neural/xla/hlo.proto | 15 +++++++++++++++ src/neural/xla/xla_runner.cc | 11 ++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/neural/xla/hlo.proto b/src/neural/xla/hlo.proto index 6ced6f938d..ba1fe21653 100644 --- a/src/neural/xla/hlo.proto +++ b/src/neural/xla/hlo.proto @@ -354,6 +354,15 @@ message CompileEnvOptionProto { required OptionOverrideProto value = 2; } +message XlaDeviceAssignmentProto { + optional int32 replica_count = 1; + optional int32 computation_count = 2; + message ComputationDevice { + repeated int64 replica_device_ids = 1; + } + repeated ComputationDevice computation_devices = 3; +} + message ExecutableBuildOptionsProto { // If set, this is the device to build the computation for. Valid // device_ordinal values are: 0 to # of devices - 1. These values are @@ -386,6 +395,12 @@ message ExecutableBuildOptionsProto { // Whether HLOs should be deduplicated. optional bool deduplicate_hlo = 8; + // If set, this specifies a static device assignment for the computation. + // Otherwise, the computation will be compiled generically and can be run with + // any device assignment compatible with the computation's replica and + // partition counts. + optional XlaDeviceAssignmentProto device_assignment = 9; + // Whether input and output buffers are aliased if the associated parameter is // passed-through XLA modules without being changed. optional bool alias_passthrough_params = 10; diff --git a/src/neural/xla/xla_runner.cc b/src/neural/xla/xla_runner.cc index eaef957535..766c617fc8 100644 --- a/src/neural/xla/xla_runner.cc +++ b/src/neural/xla/xla_runner.cc @@ -124,7 +124,16 @@ void XlaRunner::AddModule(size_t minibatch_size, pblczero::CompileOptionsProto options; options.mutable_executable_build_options()->set_num_replicas(1); options.mutable_executable_build_options()->set_num_partitions(1); - options.mutable_executable_build_options()->set_device_ordinal(device_); + options.mutable_executable_build_options() + ->mutable_device_assignment() + ->set_replica_count(1); + options.mutable_executable_build_options() + ->mutable_device_assignment() + ->set_computation_count(1); + options.mutable_executable_build_options() + ->mutable_device_assignment() + ->add_computation_devices() + ->add_replica_device_ids(device_); auto executable = pjrt_client_->CompileHlo(module.OutputAsString(), options.OutputAsString()); executables_.push_back({minibatch_size, std::move(executable)}); From dfcd1c314150b93125697491bef1221841443c18 Mon Sep 17 00:00:00 2001 From: Ikko Eltociear Ashimine Date: Mon, 25 Nov 2024 06:32:23 +0900 Subject: [PATCH 004/212] chore: update configfile.cc (#2085) --- src/utils/configfile.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/configfile.cc b/src/utils/configfile.cc index 1205c73f71..98bded5862 100644 --- a/src/utils/configfile.cc +++ b/src/utils/configfile.cc @@ -142,7 +142,7 @@ bool ConfigFile::ParseFile(std::string& filename) { if (line.substr(0, 1) == "#") continue; // Skip blank lines. if (line.length() == 0) continue; - // Allow long form arugments that omit '--'. If omitted, add here. + // Allow long form arguments that omit '--'. If omitted, add here. if (line.substr(0, 1) != "-" && line.substr(0, 2) != "--") { line = "--" + line; } From 92390211f7ac33fe2c40c53ae131efbf174ab79a Mon Sep 17 00:00:00 2001 From: borg323 <39573933+borg323@users.noreply.github.com> Date: Mon, 16 Dec 2024 13:31:11 +0200 Subject: [PATCH 005/212] Move to C++20 (#2088) * update circleci * update appveyor android builds * update appveyor to vs2019 * build with c++20 * fix for vs2019 breakage * update circleci meson for macos --- .circleci/config.yml | 29 +++++++++++++++++------ appveyor.yml | 38 +++++++++++++++--------------- cross-files/aarch64-linux-android | 12 +++++----- cross-files/armv7a-linux-android | 12 +++++----- meson.build | 2 +- scripts/appveyor_android_build.cmd | 4 ++-- scripts/appveyor_win_package.cmd | 2 +- src/neural/xla/onnx2hlo.cc | 2 +- 8 files changed, 58 insertions(+), 43 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 18233fd872..deb02e1560 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -2,26 +2,41 @@ version: 2 jobs: build: docker: - - image: danieluranga/leela_chess_zero-lc0_ubuntu_builder:0.0.8 + - image: nvidia/cuda:11.6.1-cudnn8-devel-ubuntu20.04 steps: - checkout + - run: + name: Install build tools + command: | + apt-get update + apt-get -y install git python3-pip gcc-10 g++-10 clang-12 zlib1g zlib1g-dev + pip3 install meson==0.63 + pip3 install ninja - run: name: "Pull Submodules" command: git submodule update --init - - run: - name: Update Meson - command: pip3 install --upgrade meson==0.58.1 - run: name: Meson GCC environment: - CC: gcc-8 - CXX: g++-8 + CC: gcc-10 + CXX: g++-10 command: meson build-gcc -Dgtest=false + - run: + name: Meson Clang + environment: + CC: clang-12 + CXX: clang++-12 + command: meson build-clang -Dgtest=false - run: name: Build GCC command: | cd build-gcc ninja -j 4 + - run: + name: Build Clang + command: | + cd build-clang + ninja -j 4 "mac": macos: xcode: 14.1.0 @@ -34,7 +49,7 @@ jobs: - run: name: Install build tools command: | - pip3 install meson==0.63 + pip3 install meson==1.3.0 pip3 install ninja curl -LJOs https://github.com/ispc/ispc/releases/download/v1.21.0/ispc-v1.21.0-macOS.universal.tar.gz tar xf ispc-v1.21.0-macOS.universal.tar.gz diff --git a/appveyor.yml b/appveyor.yml index 543b60f4bf..1afa3789ea 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -2,7 +2,7 @@ version: '{build}' configuration: Release platform: x64 image: -- Visual Studio 2017 +- Visual Studio 2019 environment: matrix: - NAME: gpu-nvidia-cudnn @@ -47,7 +47,7 @@ install: - cmd: set NET_HASH=3e3444370b9fe413244fdc79671a490e19b93d3cca1669710ffeac890493d198 - cmd: IF NOT %OPENCL%==true IF NOT %DX%==true set NET=791556 - cmd: IF NOT %OPENCL%==true IF NOT %DX%==true set NET_HASH=f404e156ceb2882470fd8c032b8754af0fa0b71168328912eaef14671a256e34 -- cmd: call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" amd64 +- cmd: call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" amd64 - cmd: set DNNL_NAME=dnnl_win_1.5.0_cpu_vcomp - cmd: IF %NAME%==cpu-dnnl IF NOT EXIST C:\cache\%DNNL_NAME% appveyor DownloadFile https://github.com/oneapi-src/oneDNN/releases/download/v1.5/dnnl_win_1.5.0_cpu_vcomp.zip - cmd: IF %NAME%==cpu-dnnl IF NOT EXIST C:\cache\%DNNL_NAME% 7z x dnnl_win_1.5.0_cpu_vcomp.zip -oC:\cache @@ -65,26 +65,26 @@ install: - cmd: IF %ISPC%==true IF NOT EXIST C:\cache\ispc-v1.13.0-windows appveyor DownloadFile https://github.com/ispc/ispc/releases/download/v1.13.0/ispc-v1.13.0-windows.zip - cmd: IF %ISPC%==true IF NOT EXIST C:\cache\ispc-v1.13.0-windows 7z x ispc-v1.13.0-windows.zip -oC:\cache\ispc-v1.13.0-windows - cmd: IF %ISPC%==true set PATH=C:\cache\ispc-v1.13.0-windows\bin;%PATH% -- cmd: set "CUDA_PATH=C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.0" +- cmd: set "CUDA_PATH=C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.1" - cmd: IF %CUDNN%==true IF NOT EXIST "%CUDA_PATH%\cuda" set CUDNN_INSTALL=1 -- cmd: IF DEFINED CUDNN_INSTALL appveyor DownloadFile https://developer.nvidia.com/compute/cuda/10.0/Prod/network_installers/cuda_10.0.130_win10_network -- cmd: IF DEFINED CUDNN_INSTALL cuda_10.0.130_win10_network -s nvcc_10.0 cublas_dev_10.0 cublas_10.0 cudart_10.0 -- cmd: IF DEFINED CUDNN_INSTALL appveyor DownloadFile http://developer.download.nvidia.com/compute/redist/cudnn/v7.4.2/cudnn-10.0-windows10-x64-v7.4.2.24.zip -- cmd: IF DEFINED CUDNN_INSTALL 7z x cudnn-10.0-windows10-x64-v7.4.2.24.zip -o"%CUDA_PATH%" +- cmd: IF DEFINED CUDNN_INSTALL appveyor DownloadFile https://developer.download.nvidia.com/compute/cuda/10.1/Prod/network_installers/cuda_10.1.243_win10_network.exe +- cmd: IF DEFINED CUDNN_INSTALL cuda_10.1.243_win10_network -s nvcc_10.1 cublas_dev_10.1 cublas_10.1 cudart_10.1 +- cmd: IF DEFINED CUDNN_INSTALL appveyor DownloadFile https://developer.download.nvidia.com/compute/redist/cudnn/v7.5.1/cudnn-10.1-windows10-x64-v7.5.1.10.zip +- cmd: IF DEFINED CUDNN_INSTALL 7z x cudnn-10.1-windows10-x64-v7.5.1.10.zip -o"%CUDA_PATH%" - cmd: IF %CUDNN%==false set "CUDA_PATH=C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.1" - cmd: IF %CUDA%==true IF NOT EXIST "%CUDA_PATH%" set CUDA_INSTALL=1 - cmd: IF DEFINED CUDA_INSTALL appveyor DownloadFile https://developer.download.nvidia.com/compute/cuda/11.1.0/network_installers/cuda_11.1.0_win10_network.exe - cmd: IF DEFINED CUDA_INSTALL cuda_11.1.0_win10_network.exe -s nvcc_11.1 cublas_dev_11.1 cublas_11.1 cudart_11.1 documentation_11.1 - cmd: IF %CUDA%==true set PATH=%CUDA_PATH%\bin;%PATH% -- cmd: set PATH=C:\Python36;C:\Python36\scripts;%PATH% -- cmd: pip3 install --upgrade meson==0.55.3 -- cmd: set MIMALLOC_PATH=C:\cache\mimalloc-1.7.1 -- cmd: IF %ANDROID%==false IF NOT EXIST "%MIMALLOC_PATH%" appveyor DownloadFile https://github.com/microsoft/mimalloc/archive/refs/tags/v1.7.1.zip -- cmd: IF %ANDROID%==false IF NOT EXIST "%MIMALLOC_PATH%" 7z x v1.7.1.zip -oC:\cache\ -- cmd: IF %ANDROID%==false IF NOT EXIST "%MIMALLOC_PATH%"\out msbuild "%MIMALLOC_PATH%"\ide\vs2017\mimalloc-override.vcxproj /p:Configuration=Release /m -- cmd: IF %NAME%==android IF NOT EXIST C:\ndk\android-ndk-r19c\toolchains\llvm\prebuilt\windows-x86_64 appveyor DownloadFile https://dl.google.com/android/repository/android-ndk-r19c-windows-x86_64.zip -- cmd: IF %NAME%==android IF NOT EXIST C:\ndk\android-ndk-r19c\toolchains\llvm\prebuilt\windows-x86_64 7z x android-ndk-r19c-windows-x86_64.zip -oC:\ndk -- cmd: IF %NAME%==android set PATH=C:\ndk\android-ndk-r19c\toolchains\llvm\prebuilt\windows-x86_64\bin;%PATH% +- cmd: set PATH=C:\Python310;C:\Python310\scripts;%PATH% +#- cmd: pip3 install --upgrade meson==0.55.3 +- cmd: set MIMALLOC_PATH=C:\cache\mimalloc-1.8.7 +- cmd: IF %ANDROID%==false IF NOT EXIST "%MIMALLOC_PATH%" appveyor DownloadFile https://github.com/microsoft/mimalloc/archive/refs/tags/v1.8.7.zip +- cmd: IF %ANDROID%==false IF NOT EXIST "%MIMALLOC_PATH%" 7z x v1.8.7.zip -oC:\cache\ +- cmd: IF %ANDROID%==false IF NOT EXIST "%MIMALLOC_PATH%"\out msbuild "%MIMALLOC_PATH%"\ide\vs2019\mimalloc-override.vcxproj /p:Configuration=Release /m +- cmd: IF %NAME%==android IF NOT EXIST C:\ndk\android-ndk-r27c\toolchains\llvm\prebuilt\windows-x86_64 appveyor DownloadFile https://dl.google.com/android/repository/android-ndk-r27c-windows.zip +- cmd: IF %NAME%==android IF NOT EXIST C:\ndk\android-ndk-r27c\toolchains\llvm\prebuilt\windows-x86_64 7z x android-ndk-r27c-windows.zip -oC:\ndk +- cmd: IF %NAME%==android set PATH=C:\ndk\android-ndk-r27c\toolchains\llvm\prebuilt\windows-x86_64\bin;%PATH% - cmd: IF %NAME%==android sed "s/clang+*/&.cmd/" cross-files/aarch64-linux-android >crossfile-aarch64 - cmd: IF %NAME%==android IF NOT EXIST C:\cache\OpenBLAS\android-aarch64 appveyor DownloadFile https://github.com/borg323/OpenBLAS/releases/download/android-0.3.27/openblas-android-aarch64.zip - cmd: IF %NAME%==android IF NOT EXIST C:\cache\OpenBLAS\android-aarch64 7z x openblas-android-aarch64.zip -oC:\cache\OpenBLAS @@ -103,10 +103,10 @@ install: - cmd: cd C:\projects\lc0 cache: - C:\cache - - 'C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.0' + - 'C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.1' - 'C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.1' - C:\projects\lc0\subprojects\packagecache - - C:\ndk\android-ndk-r19c\toolchains\llvm\prebuilt\windows-x86_64 + - C:\ndk\android-ndk-r27c\toolchains\llvm\prebuilt\windows-x86_64 before_build: - cmd: git submodule update --init --recursive - cmd: IF %BLAS%==true (echo.#define DEFAULT_MAX_PREFETCH 0 & echo.#define DEFAULT_TASK_WORKERS 0) > params_override.h @@ -124,7 +124,7 @@ before_build: - cmd: SET EXTRA= - cmd: IF %ANDROID%==false SET EXTRA=-Db_vscrt=md - cmd: IF %ONNX_DML%==true SET EXTRA=-Db_vscrt=md -Donnx_libdir=C:\cache\%ONNX_NAME%\lib -Donnx_include=C:\cache\%ONNX_NAME%\include -- cmd: IF %ANDROID%==false meson build --backend vs2017 --buildtype release -Dgtest=%GTEST% -Dopencl=%OPENCL% -Dblas=%BUILD_BLAS% -Ddnnl=true -Ddx=%DX% -Dcudnn=%CUDNN% -Donednn=%ONEDNN% -Dispc_native_only=false -Dnative_cuda=false -Dpopcnt=%POPCNT% -Df16c=%F16C% -Dcudnn_include="%CUDA_PATH%\include","%CUDA_PATH%\cuda\include" -Dcudnn_libdirs="%CUDA_PATH%\lib\x64","%CUDA_PATH%\cuda\lib\x64" -Dopenblas_include="%PKG_FOLDER%\OpenBLAS\dist64\include" -Dopenblas_libdirs="%PKG_FOLDER%\OpenBLAS\dist64\lib" -Ddnnl_dir="%PKG_FOLDER%\%DNNL_NAME%" -Dopencl_include="%PKG_FOLDER%\opencl-nug.0.777.77\build\native\include" -Dopencl_libdirs="%PKG_FOLDER%\opencl-nug.0.777.77\build\native\lib\x64" -Ddefault_library=static -Dmalloc=mimalloc -Dmimalloc_libdir="%MIMALLOC_PATH%"\out\msvc-x64\Release %EXTRA% +- cmd: IF %ANDROID%==false meson build --backend vs2019 --buildtype release -Dgtest=%GTEST% -Dopencl=%OPENCL% -Dblas=%BUILD_BLAS% -Ddnnl=true -Ddx=%DX% -Dcudnn=%CUDNN% -Donednn=%ONEDNN% -Dispc_native_only=false -Dnative_cuda=false -Dpopcnt=%POPCNT% -Df16c=%F16C% -Dcudnn_include="%CUDA_PATH%\include","%CUDA_PATH%\cuda\include" -Dcudnn_libdirs="%CUDA_PATH%\lib\x64","%CUDA_PATH%\cuda\lib\x64" -Dopenblas_include="%PKG_FOLDER%\OpenBLAS\dist64\include" -Dopenblas_libdirs="%PKG_FOLDER%\OpenBLAS\dist64\lib" -Ddnnl_dir="%PKG_FOLDER%\%DNNL_NAME%" -Dopencl_include="%PKG_FOLDER%\opencl-nug.0.777.77\build\native\include" -Dopencl_libdirs="%PKG_FOLDER%\opencl-nug.0.777.77\build\native\lib\x64" -Ddefault_library=static -Dmalloc=mimalloc -Dmimalloc_libdir="%MIMALLOC_PATH%"\out\msvc-x64\Release %EXTRA% - cmd: IF %ANDROID%==true meson arm64-v8a --buildtype release -Dgtest=false -Dopenblas_include="%PKG_FOLDER%\OpenBLAS\android-aarch64\include" -Dopenblas_libdirs="%PKG_FOLDER%\OpenBLAS\android-aarch64\lib" -Dembed=%EMBED% -Ddefault_library=static --cross-file crossfile-aarch64 - cmd: IF %ANDROID%==true meson armeabi-v7a --buildtype release -Dgtest=false -Dopenblas_include="%PKG_FOLDER%\OpenBLAS\android-armv7a\include" -Dopenblas_libdirs="%PKG_FOLDER%\OpenBLAS\android-armv7a\lib" -Dembed=%EMBED% -Ddefault_library=static --cross-file crossfile-armv7a -Dispc=false -Dneon=false build_script: diff --git a/cross-files/aarch64-linux-android b/cross-files/aarch64-linux-android index 4a55d838de..75e9e63de9 100644 --- a/cross-files/aarch64-linux-android +++ b/cross-files/aarch64-linux-android @@ -1,5 +1,5 @@ -# Tested with Android NDK r19c, default toolchain +# Tested with Android NDK r27c, default toolchain # Targeting API level 21 # Set the toolchain path on your environment @@ -17,8 +17,8 @@ cpp_link_args = ['-llog', '-static-libstdc++'] [binaries] c = 'aarch64-linux-android21-clang' cpp = 'aarch64-linux-android21-clang++' -ar = 'aarch64-linux-android-ar' -strip = 'aarch64-linux-android-strip' -ld = 'aarch64-linux-android-ld' -ranlib = 'aarch64-linux-android-ranlib' -as = 'aarch64-linux-android-as' +ar = 'llvm-ar' +strip = 'llvm-strip' +ld = 'ld' +ranlib = 'llvm-ranlib' +as = 'aarch64-linux-android21-clang' diff --git a/cross-files/armv7a-linux-android b/cross-files/armv7a-linux-android index 16b3e93f90..3fed7aee8b 100644 --- a/cross-files/armv7a-linux-android +++ b/cross-files/armv7a-linux-android @@ -1,5 +1,5 @@ -# Tested with Android NDK r19c, default toolchain +# Tested with Android NDK r27c, default toolchain # Targeting API level 21 # When targeting API levels < 24 the build fails unless _FILE_OFFSET_BITS is unset. @@ -24,8 +24,8 @@ cpp_link_args = ['-llog', '-static-libstdc++'] [binaries] c = 'armv7a-linux-androideabi21-clang' cpp = 'armv7a-linux-androideabi21-clang++' -ar = 'arm-linux-androideabi-ar' -strip = 'arm-linux-androideabi-strip' -ld = 'arm-linux-androideabi-ld' -ranlib = 'arm-linux-androideabi-ranlib' -as = 'arm-linux-androideabi-as' +ar = 'llvm-ar' +strip = 'llvm-strip' +ld = 'ld' +ranlib = 'llvm-ranlib' +as = 'armv7a-linux-androideabi21-clang' diff --git a/meson.build b/meson.build index 27d6c6cb63..380a8d6857 100644 --- a/meson.build +++ b/meson.build @@ -15,7 +15,7 @@ # along with Leela Chess. If not, see . project('lc0', 'cpp', - default_options : ['cpp_std=c++17', 'b_ndebug=if-release', 'warning_level=3', 'b_lto=true', 'b_vscrt=mt'], + default_options : ['cpp_std=c++20', 'b_ndebug=if-release', 'warning_level=3', 'b_lto=true', 'b_vscrt=mt'], meson_version: '>=0.55') cc = meson.get_compiler('cpp') diff --git a/scripts/appveyor_android_build.cmd b/scripts/appveyor_android_build.cmd index 9f2f79665a..a9f3f01860 100644 --- a/scripts/appveyor_android_build.cmd +++ b/scripts/appveyor_android_build.cmd @@ -1,7 +1,7 @@ cd arm64-v8a ninja -aarch64-linux-android-strip lc0 +llvm-strip lc0 cd C:\projects\lc0 cd armeabi-v7a ninja -arm-linux-androideabi-strip lc0 +llvm-strip lc0 diff --git a/scripts/appveyor_win_package.cmd b/scripts/appveyor_win_package.cmd index 36f98d8eef..3a4abdfa28 100644 --- a/scripts/appveyor_win_package.cmd +++ b/scripts/appveyor_win_package.cmd @@ -15,7 +15,7 @@ IF %NAME%==cpu-openblas 7z a lc0-%APPVEYOR_REPO_TAG_NAME%-windows-%NAME%.zip C:\ IF %NAME%==cpu-dnnl 7z a lc0-%APPVEYOR_REPO_TAG_NAME%-windows-%NAME%.zip C:\cache\%DNNL_NAME%\bin\dnnl.dll IF %NAME%==onednn 7z a lc0-%APPVEYOR_REPO_TAG_NAME%-windows-%NAME%.zip C:\cache\%DNNL_NAME%\bin\dnnl.dll IF %OPENCL%==true 7z a lc0-%APPVEYOR_REPO_TAG_NAME%-windows-%NAME%.zip C:\cache\opencl-nug.0.777.77\build\native\bin\OpenCL.dll -IF %CUDNN%==true 7z a lc0-%APPVEYOR_REPO_TAG_NAME%-windows-%NAME%.zip "%CUDA_PATH%\bin\cudart64_100.dll" "%CUDA_PATH%\bin\cublas64_100.dll" +IF %CUDNN%==true 7z a lc0-%APPVEYOR_REPO_TAG_NAME%-windows-%NAME%.zip "%CUDA_PATH%\bin\cudart64_101.dll" "%CUDA_PATH%\bin\cublas64_10.dll" "%CUDA_PATH%\bin\cublasLt64_10.dll" IF %CUDNN%==true 7z a lc0-%APPVEYOR_REPO_TAG_NAME%-windows-%NAME%.zip "%CUDA_PATH%\cuda\bin\cudnn64_7.dll" IF %CUDA%==true 7z a lc0-%APPVEYOR_REPO_TAG_NAME%-windows-%NAME%.zip "%CUDA_PATH%\bin\cudart64_110.dll" "%CUDA_PATH%\bin\cublas64_11.dll" "%CUDA_PATH%\bin\cublasLt64_11.dll" IF %NAME%==cpu-dnnl copy "%PKG_FOLDER%\%DNNL_NAME%\LICENSE" dist\DNNL-LICENSE diff --git a/src/neural/xla/onnx2hlo.cc b/src/neural/xla/onnx2hlo.cc index effe987447..017618e155 100644 --- a/src/neural/xla/onnx2hlo.cc +++ b/src/neural/xla/onnx2hlo.cc @@ -273,7 +273,7 @@ pblczero::XlaLiteralProto ConstOpMax(const pblczero::XlaLiteralProto& lhs, typename std::remove_reference::type::value_type; std::transform(lhs.begin(), lhs.end(), rhs.begin(), std::back_inserter(*dst), - [](T a, T b) { return std::max(a, b); }); + [](const T &a, const T &b) { return std::max(a, b); }); }); return result; } From 3c2db95a834a2e864449c82b5f95ae95a278cef4 Mon Sep 17 00:00:00 2001 From: borg323 <39573933+borg323@users.noreply.github.com> Date: Mon, 16 Dec 2024 14:50:05 +0200 Subject: [PATCH 006/212] code reorganization (#2041) The src directory is re-organized as follows: 1. The benchmark and lc0ctl directories are merged into tools. 2. All backends are moved into neural/backends. 3. The neural/onnx and neural/xla directories remain but only contain the conversion functions and not any backend code. 4. The neural/tables directory contains some generic information that used to be in neural/shared (activation functions, policy maps etc.) that are used by both backends and the onnx converter. 5. The rest of neural/shared is moved to neural/backends/shared/. 6. The rescorer is moved into the trainingdata directory. --- meson.build | 106 +++++++++--------- src/main.cc | 10 +- src/neural/{ => backends}/blas/README.md | 0 src/neural/{ => backends}/blas/blas.h | 0 .../{ => backends}/blas/convolution1.cc | 4 +- src/neural/{ => backends}/blas/convolution1.h | 0 src/neural/{ => backends}/blas/encoder.h | 2 - .../blas/fully_connected_layer.cc | 5 +- .../blas/fully_connected_layer.h | 2 +- .../{ => backends}/blas/layer_norm.ispc | 0 .../{ => backends}/blas/network_blas.cc | 20 ++-- src/neural/{ => backends}/blas/se_unit.cc | 4 +- src/neural/{ => backends}/blas/se_unit.h | 2 +- .../blas/winograd_convolution3.cc | 4 +- .../blas/winograd_convolution3.h | 0 .../blas/winograd_transform.ispc | 0 .../{ => backends}/cuda/common_kernels.cu | 4 +- src/neural/{ => backends}/cuda/cuda_common.h | 0 .../{ => backends}/cuda/fp16_kernels.cu | 2 +- .../{ => backends}/cuda/inputs_outputs.h | 0 src/neural/{ => backends}/cuda/kernels.h | 2 +- src/neural/{ => backends}/cuda/layers.cc | 3 +- src/neural/{ => backends}/cuda/layers.h | 2 +- .../{ => backends}/cuda/network_cuda.cc | 5 +- .../{ => backends}/cuda/network_cudnn.cc | 5 +- src/neural/{ => backends}/cuda/readme.txt | 0 .../{ => backends}/cuda/winograd_helper.inc | 0 src/neural/{ => backends}/dx/MetaCommand.h | 0 src/neural/{ => backends}/dx/dx_common.h | 0 src/neural/{ => backends}/dx/layers_dx.cc | 0 src/neural/{ => backends}/dx/layers_dx.h | 0 src/neural/{ => backends}/dx/network_dx.cc | 2 +- src/neural/{ => backends}/dx/network_dx.h | 0 .../{ => backends}/dx/shader_wrapper.cc | 0 src/neural/{ => backends}/dx/shader_wrapper.h | 0 .../{ => backends}/dx/shaders/AddVectors.hlsl | 0 .../{ => backends}/dx/shaders/Conv1x1.hlsl | 0 .../dx/shaders/ExpandPlanes.hlsl | 0 .../{ => backends}/dx/shaders/Gemm.hlsl | 0 .../{ => backends}/dx/shaders/PolicyMap.hlsl | 0 src/neural/{ => backends}/dx/shaders/SE.hlsl | 0 .../dx/shaders/WinogradCommon.h | 0 .../dx/shaders/WinogradTransform.hlsl | 0 .../dx/shaders/WinogradTransformSE.hlsl | 0 .../{ => backends}/dx/shaders/dxc_helper.py | 0 .../{ => backends}/dx/shaders/meson.build | 0 .../{ => backends}/dx/shaders/shader_shared.h | 0 .../{ => backends}/dx/shaders/shaders.h | 0 .../{ => backends}/metal/metal_common.h | 0 .../metal/mps/MetalNetworkBuilder.h | 0 .../metal/mps/MetalNetworkBuilder.mm | 2 +- .../{ => backends}/metal/mps/NetworkGraph.h | 0 .../{ => backends}/metal/mps/NetworkGraph.mm | 0 .../{ => backends}/metal/network_metal.cc | 4 +- .../{ => backends}/metal/network_metal.h | 0 src/neural/{ => backends}/network_check.cc | 0 src/neural/{ => backends}/network_demux.cc | 0 src/neural/{ => backends}/network_mux.cc | 0 src/neural/{onnx => backends}/network_onnx.cc | 0 src/neural/{ => backends}/network_random.cc | 0 src/neural/{ => backends}/network_record.cc | 0 src/neural/{ => backends}/network_rr.cc | 0 src/neural/{ => backends}/network_tf_cc.cc | 2 +- src/neural/{ => backends}/network_trivial.cc | 0 src/neural/{ => backends}/onednn/layers.cc | 0 src/neural/{ => backends}/onednn/layers.h | 2 +- .../{ => backends}/onednn/network_onednn.cc | 4 +- src/neural/{ => backends}/opencl/OpenCL.cc | 6 +- src/neural/{ => backends}/opencl/OpenCL.h | 4 +- .../{ => backends}/opencl/OpenCLBuffers.cc | 2 +- .../{ => backends}/opencl/OpenCLBuffers.h | 6 +- .../{ => backends}/opencl/OpenCLParams.h | 0 .../{ => backends}/opencl/OpenCLTuner.cc | 6 +- .../{ => backends}/opencl/OpenCLTuner.h | 4 +- src/neural/{ => backends}/opencl/README.md | 0 .../opencl/clblast_level3/common.opencl | 0 .../clblast_level3/xgemm_batched.opencl | 0 .../opencl/clblast_level3/xgemm_part1.opencl | 0 .../opencl/clblast_level3/xgemm_part2.opencl | 0 .../opencl/clblast_level3/xgemm_part3.opencl | 0 .../opencl/clblast_level3/xgemv.opencl | 0 .../opencl/clsource/config.opencl | 0 .../opencl/clsource/convolve1.opencl | 0 .../opencl/clsource/convolve3.opencl | 0 .../opencl/clsource/policymap.opencl | 0 .../{ => backends}/opencl/clsource/se.opencl | 0 .../{ => backends}/opencl/network_opencl.cc | 10 +- .../{ => backends}/shared/activation.cc | 2 +- src/neural/{ => backends}/shared/activation.h | 22 +--- .../{ => backends}/shared/activation.ispc | 0 .../{ => backends}/shared/winograd_filter.cc | 2 +- .../{ => backends}/shared/winograd_filter.h | 0 src/neural/{ => backends}/xla/network_xla.cc | 2 +- src/neural/{ => backends}/xla/pjrt.cc | 0 src/neural/{ => backends}/xla/pjrt.h | 0 src/neural/{ => backends}/xla/xla_runner.cc | 2 +- src/neural/{ => backends}/xla/xla_runner.h | 4 +- src/neural/onnx/converter.cc | 6 +- src/neural/tables/activation_function.h | 43 +++++++ .../{shared => tables}/attention_policy_map.h | 0 src/neural/{shared => tables}/policy_map.h | 0 src/neural/xla/onnx2hlo.h | 3 +- src/rescorer_main.cc | 2 +- src/{benchmark => tools}/backendbench.cc | 2 +- src/{benchmark => tools}/backendbench.h | 0 src/{benchmark => tools}/benchmark.cc | 2 +- src/{benchmark => tools}/benchmark.h | 0 src/{lc0ctl => tools}/describenet.cc | 2 +- src/{lc0ctl => tools}/describenet.h | 0 src/{lc0ctl => tools}/leela2onnx.cc | 2 +- src/{lc0ctl => tools}/leela2onnx.h | 0 src/{lc0ctl => tools}/onnx2leela.cc | 2 +- src/{lc0ctl => tools}/onnx2leela.h | 0 src/{rescorer => trainingdata}/rescoreloop.cc | 2 +- src/{rescorer => trainingdata}/rescoreloop.h | 0 115 files changed, 178 insertions(+), 158 deletions(-) rename src/neural/{ => backends}/blas/README.md (100%) rename src/neural/{ => backends}/blas/blas.h (100%) rename src/neural/{ => backends}/blas/convolution1.cc (97%) rename src/neural/{ => backends}/blas/convolution1.h (100%) rename src/neural/{ => backends}/blas/encoder.h (98%) rename src/neural/{ => backends}/blas/fully_connected_layer.cc (97%) rename src/neural/{ => backends}/blas/fully_connected_layer.h (96%) rename src/neural/{ => backends}/blas/layer_norm.ispc (100%) rename src/neural/{ => backends}/blas/network_blas.cc (98%) rename src/neural/{ => backends}/blas/se_unit.cc (97%) rename src/neural/{ => backends}/blas/se_unit.h (96%) rename src/neural/{ => backends}/blas/winograd_convolution3.cc (99%) rename src/neural/{ => backends}/blas/winograd_convolution3.h (100%) rename src/neural/{ => backends}/blas/winograd_transform.ispc (100%) rename src/neural/{ => backends}/cuda/common_kernels.cu (99%) rename src/neural/{ => backends}/cuda/cuda_common.h (100%) rename src/neural/{ => backends}/cuda/fp16_kernels.cu (99%) rename src/neural/{ => backends}/cuda/inputs_outputs.h (100%) rename src/neural/{ => backends}/cuda/kernels.h (99%) rename src/neural/{ => backends}/cuda/layers.cc (99%) rename src/neural/{ => backends}/cuda/layers.h (99%) rename src/neural/{ => backends}/cuda/network_cuda.cc (99%) rename src/neural/{ => backends}/cuda/network_cudnn.cc (99%) rename src/neural/{ => backends}/cuda/readme.txt (100%) rename src/neural/{ => backends}/cuda/winograd_helper.inc (100%) rename src/neural/{ => backends}/dx/MetaCommand.h (100%) rename src/neural/{ => backends}/dx/dx_common.h (100%) rename src/neural/{ => backends}/dx/layers_dx.cc (100%) rename src/neural/{ => backends}/dx/layers_dx.h (100%) rename src/neural/{ => backends}/dx/network_dx.cc (99%) rename src/neural/{ => backends}/dx/network_dx.h (100%) rename src/neural/{ => backends}/dx/shader_wrapper.cc (100%) rename src/neural/{ => backends}/dx/shader_wrapper.h (100%) rename src/neural/{ => backends}/dx/shaders/AddVectors.hlsl (100%) rename src/neural/{ => backends}/dx/shaders/Conv1x1.hlsl (100%) rename src/neural/{ => backends}/dx/shaders/ExpandPlanes.hlsl (100%) rename src/neural/{ => backends}/dx/shaders/Gemm.hlsl (100%) rename src/neural/{ => backends}/dx/shaders/PolicyMap.hlsl (100%) rename src/neural/{ => backends}/dx/shaders/SE.hlsl (100%) rename src/neural/{ => backends}/dx/shaders/WinogradCommon.h (100%) rename src/neural/{ => backends}/dx/shaders/WinogradTransform.hlsl (100%) rename src/neural/{ => backends}/dx/shaders/WinogradTransformSE.hlsl (100%) rename src/neural/{ => backends}/dx/shaders/dxc_helper.py (100%) rename src/neural/{ => backends}/dx/shaders/meson.build (100%) rename src/neural/{ => backends}/dx/shaders/shader_shared.h (100%) rename src/neural/{ => backends}/dx/shaders/shaders.h (100%) rename src/neural/{ => backends}/metal/metal_common.h (100%) rename src/neural/{ => backends}/metal/mps/MetalNetworkBuilder.h (100%) rename src/neural/{ => backends}/metal/mps/MetalNetworkBuilder.mm (99%) rename src/neural/{ => backends}/metal/mps/NetworkGraph.h (100%) rename src/neural/{ => backends}/metal/mps/NetworkGraph.mm (100%) rename src/neural/{ => backends}/metal/network_metal.cc (99%) rename src/neural/{ => backends}/metal/network_metal.h (100%) rename src/neural/{ => backends}/network_check.cc (100%) rename src/neural/{ => backends}/network_demux.cc (100%) rename src/neural/{ => backends}/network_mux.cc (100%) rename src/neural/{onnx => backends}/network_onnx.cc (100%) rename src/neural/{ => backends}/network_random.cc (100%) rename src/neural/{ => backends}/network_record.cc (100%) rename src/neural/{ => backends}/network_rr.cc (100%) rename src/neural/{ => backends}/network_tf_cc.cc (99%) rename src/neural/{ => backends}/network_trivial.cc (100%) rename src/neural/{ => backends}/onednn/layers.cc (100%) rename src/neural/{ => backends}/onednn/layers.h (99%) rename src/neural/{ => backends}/onednn/network_onednn.cc (99%) rename src/neural/{ => backends}/opencl/OpenCL.cc (98%) rename src/neural/{ => backends}/opencl/OpenCL.h (98%) rename src/neural/{ => backends}/opencl/OpenCLBuffers.cc (99%) rename src/neural/{ => backends}/opencl/OpenCLBuffers.h (96%) rename src/neural/{ => backends}/opencl/OpenCLParams.h (100%) rename src/neural/{ => backends}/opencl/OpenCLTuner.cc (99%) rename src/neural/{ => backends}/opencl/OpenCLTuner.h (96%) rename src/neural/{ => backends}/opencl/README.md (100%) rename src/neural/{ => backends}/opencl/clblast_level3/common.opencl (100%) rename src/neural/{ => backends}/opencl/clblast_level3/xgemm_batched.opencl (100%) rename src/neural/{ => backends}/opencl/clblast_level3/xgemm_part1.opencl (100%) rename src/neural/{ => backends}/opencl/clblast_level3/xgemm_part2.opencl (100%) rename src/neural/{ => backends}/opencl/clblast_level3/xgemm_part3.opencl (100%) rename src/neural/{ => backends}/opencl/clblast_level3/xgemv.opencl (100%) rename src/neural/{ => backends}/opencl/clsource/config.opencl (100%) rename src/neural/{ => backends}/opencl/clsource/convolve1.opencl (100%) rename src/neural/{ => backends}/opencl/clsource/convolve3.opencl (100%) rename src/neural/{ => backends}/opencl/clsource/policymap.opencl (100%) rename src/neural/{ => backends}/opencl/clsource/se.opencl (100%) rename src/neural/{ => backends}/opencl/network_opencl.cc (98%) rename src/neural/{ => backends}/shared/activation.cc (99%) rename src/neural/{ => backends}/shared/activation.h (72%) rename src/neural/{ => backends}/shared/activation.ispc (100%) rename src/neural/{ => backends}/shared/winograd_filter.cc (98%) rename src/neural/{ => backends}/shared/winograd_filter.h (100%) rename src/neural/{ => backends}/xla/network_xla.cc (99%) rename src/neural/{ => backends}/xla/pjrt.cc (100%) rename src/neural/{ => backends}/xla/pjrt.h (100%) rename src/neural/{ => backends}/xla/xla_runner.cc (99%) rename src/neural/{ => backends}/xla/xla_runner.h (98%) create mode 100644 src/neural/tables/activation_function.h rename src/neural/{shared => tables}/attention_policy_map.h (100%) rename src/neural/{shared => tables}/policy_map.h (100%) rename src/{benchmark => tools}/backendbench.cc (99%) rename src/{benchmark => tools}/backendbench.h (100%) rename src/{benchmark => tools}/benchmark.cc (99%) rename src/{benchmark => tools}/benchmark.h (100%) rename src/{lc0ctl => tools}/describenet.cc (99%) rename src/{lc0ctl => tools}/describenet.h (100%) rename src/{lc0ctl => tools}/leela2onnx.cc (99%) rename src/{lc0ctl => tools}/leela2onnx.h (100%) rename src/{lc0ctl => tools}/onnx2leela.cc (99%) rename src/{lc0ctl => tools}/onnx2leela.h (100%) rename src/{rescorer => trainingdata}/rescoreloop.cc (99%) rename src/{rescorer => trainingdata}/rescoreloop.h (100%) diff --git a/meson.build b/meson.build index 380a8d6857..587ea74c92 100644 --- a/meson.build +++ b/meson.build @@ -181,12 +181,7 @@ common_files += [ ] files += [ - 'src/benchmark/backendbench.cc', - 'src/benchmark/benchmark.cc', 'src/engine.cc', - 'src/lc0ctl/describenet.cc', - 'src/lc0ctl/leela2onnx.cc', - 'src/lc0ctl/onnx2leela.cc', 'src/mcts/params.cc', 'src/mcts/search.cc', 'src/mcts/stoppers/alphazero.cc', @@ -197,27 +192,33 @@ files += [ 'src/mcts/stoppers/smooth.cc', 'src/mcts/stoppers/stoppers.cc', 'src/mcts/stoppers/timemgr.cc', + 'src/neural/backends/network_check.cc', + 'src/neural/backends/network_demux.cc', + 'src/neural/backends/network_mux.cc', + 'src/neural/backends/network_random.cc', + 'src/neural/backends/network_record.cc', + 'src/neural/backends/network_rr.cc', + 'src/neural/backends/network_trivial.cc', 'src/neural/cache.cc', 'src/neural/factory.cc', 'src/neural/loader.cc', - 'src/neural/network_check.cc', - 'src/neural/network_demux.cc', 'src/neural/network_legacy.cc', - 'src/neural/network_mux.cc', - 'src/neural/network_random.cc', - 'src/neural/network_record.cc', - 'src/neural/network_rr.cc', - 'src/neural/network_trivial.cc', 'src/neural/onnx/adapters.cc', 'src/neural/onnx/builder.cc', 'src/neural/onnx/converter.cc', 'src/neural/xla/hlo_builder.cc', 'src/neural/xla/onnx2hlo.cc', 'src/neural/xla/print_hlo.cc', + 'src/neural/xla/xla_tensor.cc', 'src/selfplay/game.cc', 'src/selfplay/loop.cc', 'src/selfplay/multigame.cc', 'src/selfplay/tournament.cc', + 'src/tools/backendbench.cc', + 'src/tools/benchmark.cc', + 'src/tools/describenet.cc', + 'src/tools/leela2onnx.cc', + 'src/tools/onnx2leela.cc', 'src/utils/histogram.cc', 'src/utils/numa.cc', 'src/utils/weights_adapter.cc', @@ -248,7 +249,7 @@ if get_option('build_backends') tf_tensorflow_cc_lib = dependency('tensorflow_cc', required: false) if get_option('tensorflow') and tf_dl_lib.found() and tf_tensorflow_cc_lib.found() deps += [tf_dl_lib, tf_tensorflow_cc_lib] - files += 'src/neural/network_tf_cc.cc' + files += 'src/neural/backends/network_tf_cc.cc' has_backends = true endif @@ -373,25 +374,25 @@ if get_option('build_backends') endif blas_files = [ - 'src/neural/blas/convolution1.cc', - 'src/neural/blas/fully_connected_layer.cc', - 'src/neural/blas/se_unit.cc', - 'src/neural/blas/network_blas.cc', - 'src/neural/blas/winograd_convolution3.cc' + 'src/neural/backends/blas/convolution1.cc', + 'src/neural/backends/blas/fully_connected_layer.cc', + 'src/neural/backends/blas/se_unit.cc', + 'src/neural/backends/blas/network_blas.cc', + 'src/neural/backends/blas/winograd_convolution3.cc' ] shared_files = [ - 'src/neural/shared/activation.cc', - 'src/neural/shared/winograd_filter.cc', + 'src/neural/backends/shared/activation.cc', + 'src/neural/backends/shared/winograd_filter.cc', ] files += blas_files has_backends = true if get_option('ispc') and ispc.found() - files += iscp_gen.process('src/neural/blas/winograd_transform.ispc') - files += iscp_gen.process('src/neural/blas/layer_norm.ispc') - files += iscp_gen.process('src/neural/shared/activation.ispc') + files += iscp_gen.process('src/neural/backends/blas/winograd_transform.ispc') + files += iscp_gen.process('src/neural/backends/blas/layer_norm.ispc') + files += iscp_gen.process('src/neural/backends/shared/activation.ispc') add_project_arguments('-DUSE_ISPC', language : 'cpp') endif @@ -421,15 +422,15 @@ if get_option('build_backends') if get_option('opencl') and has_opencl opencl_files = [ - 'src/neural/opencl/network_opencl.cc', - 'src/neural/opencl/OpenCL.cc', - 'src/neural/opencl/OpenCLTuner.cc', - 'src/neural/opencl/OpenCLBuffers.cc', + 'src/neural/backends/opencl/network_opencl.cc', + 'src/neural/backends/opencl/OpenCL.cc', + 'src/neural/backends/opencl/OpenCLTuner.cc', + 'src/neural/backends/opencl/OpenCLBuffers.cc', ] shared_files = [ - 'src/neural/shared/activation.cc', - 'src/neural/shared/winograd_filter.cc', + 'src/neural/backends/shared/activation.cc', + 'src/neural/backends/shared/winograd_filter.cc', ] if not opencl_framework.found() @@ -455,21 +456,21 @@ if get_option('build_backends') if (get_option('cudnn') or get_option('plain_cuda')) and cu_blas.found() and cu_dart.found() and nvcc.found() deps += [cu_blas, cu_dart] - cuda_files = ['src/neural/cuda/layers.cc'] + cuda_files = ['src/neural/backends/cuda/layers.cc'] if get_option('cudnn') and cu_dnn.found() deps += cu_dnn - cuda_files += 'src/neural/cuda/network_cudnn.cc' - cuda_files += 'src/neural/cuda/network_cuda.cc' # To support newer nets. + cuda_files += 'src/neural/backends/cuda/network_cudnn.cc' + cuda_files += 'src/neural/backends/cuda/network_cuda.cc' # To support newer nets. add_project_arguments('-DUSE_CUDNN', language : 'cpp') elif get_option('plain_cuda') - cuda_files += 'src/neural/cuda/network_cuda.cc' + cuda_files += 'src/neural/backends/cuda/network_cuda.cc' endif foreach d : get_option('cudnn_include') if run_command('scripts/checkdir.py', d, check : false).returncode() == 0 includes += include_directories(d, is_system: true) endif endforeach - includes += include_directories('src/neural/cuda/') + includes += include_directories('src/neural/backends/cuda/') cuda_arguments = ['-c', '@INPUT@', '-o', '@OUTPUT@', '-I', meson.current_source_dir() + '/src'] @@ -523,16 +524,16 @@ if get_option('build_backends') endif files += cuda_files files += custom_target('cuda fp32 code', - input : 'src/neural/cuda/common_kernels.cu', + input : 'src/neural/backends/cuda/common_kernels.cu', output : outputname, - depend_files: 'src/neural/cuda/winograd_helper.inc', + depend_files: 'src/neural/backends/cuda/winograd_helper.inc', command : [nvcc, nvcc_extra_args, cuda_arguments] ) files += custom_target('cuda fp16 code', - input : 'src/neural/cuda/fp16_kernels.cu', + input : 'src/neural/backends/cuda/fp16_kernels.cu', output : outputname, - depend_files: 'src/neural/cuda/winograd_helper.inc', + depend_files: 'src/neural/backends/cuda/winograd_helper.inc', command : [nvcc, nvcc_extra_args, cuda_arguments] ) has_backends = true @@ -548,14 +549,14 @@ if get_option('build_backends') dx_dxgi = cc.find_library('dxgi') dx_files = [ - 'src/neural/dx/network_dx.cc', - 'src/neural/dx/shader_wrapper.cc', - 'src/neural/dx/layers_dx.cc', + 'src/neural/backends/dx/network_dx.cc', + 'src/neural/backends/dx/shader_wrapper.cc', + 'src/neural/backends/dx/layers_dx.cc', ] files += dx_files deps += [dx_d3d12, dx_dxgi] - subdir('src/neural/dx/shaders') + subdir('src/neural/backends/dx/shaders') has_backends = true endif @@ -564,8 +565,8 @@ if get_option('build_backends') includes += include_directories(get_option('dnnl_dir') + '/include') deps += [ dnnl_lib, dependency('openmp', required:true) ] files += [ - 'src/neural/onednn/network_onednn.cc', - 'src/neural/onednn/layers.cc', + 'src/neural/backends/onednn/network_onednn.cc', + 'src/neural/backends/onednn/layers.cc', ] has_backends = true endif @@ -586,7 +587,7 @@ if get_option('build_backends') includes += include_directories(get_option('onnx_include') + '/../providers/cpu', is_system: true) endif - files += 'src/neural/onnx/network_onnx.cc' + files += 'src/neural/backends/network_onnx.cc' if cc.find_library('onnxruntime_providers_rocm', dirs: get_option('onnx_libdir'), required: false).found() add_project_arguments('-DUSE_ROCM', language : 'cpp') @@ -607,9 +608,9 @@ if get_option('build_backends') deps += metal_frameworks files += [ - 'src/neural/metal/network_metal.cc', - 'src/neural/metal/mps/NetworkGraph.mm', - 'src/neural/metal/mps/MetalNetworkBuilder.mm', + 'src/neural/backends/metal/network_metal.cc', + 'src/neural/backends/metal/mps/NetworkGraph.mm', + 'src/neural/backends/metal/mps/MetalNetworkBuilder.mm', ] has_backends = true @@ -623,10 +624,9 @@ if get_option('build_backends') ## ~~~~~~~~ if get_option('xla') files += [ - 'src/neural/xla/network_xla.cc', - 'src/neural/xla/pjrt.cc', - 'src/neural/xla/xla_runner.cc', - 'src/neural/xla/xla_tensor.cc', + 'src/neural/backends/xla/network_xla.cc', + 'src/neural/backends/xla/pjrt.cc', + 'src/neural/backends/xla/xla_runner.cc', ] deps += cc.find_library('dl', required: false) has_backends = true @@ -702,7 +702,7 @@ endif if get_option('rescorer') deps += subproject('gaviotatb').get_variable('gaviotatb_dep') executable('rescorer', 'src/rescorer_main.cc', - [common_files, 'src/rescorer/rescoreloop.cc'], + [common_files, 'src/trainingdata/rescoreloop.cc'], include_directories: includes, dependencies: deps, install: true) endif diff --git a/src/main.cc b/src/main.cc index 4c8880d4e6..f573e4974f 100644 --- a/src/main.cc +++ b/src/main.cc @@ -25,14 +25,14 @@ Program grant you additional permission to convey the resulting work. */ -#include "benchmark/backendbench.h" -#include "benchmark/benchmark.h" #include "chess/board.h" #include "engine.h" -#include "lc0ctl/describenet.h" -#include "lc0ctl/leela2onnx.h" -#include "lc0ctl/onnx2leela.h" #include "selfplay/loop.h" +#include "tools/backendbench.h" +#include "tools/benchmark.h" +#include "tools/describenet.h" +#include "tools/leela2onnx.h" +#include "tools/onnx2leela.h" #include "utils/commandline.h" #include "utils/esc_codes.h" #include "utils/logging.h" diff --git a/src/neural/blas/README.md b/src/neural/backends/blas/README.md similarity index 100% rename from src/neural/blas/README.md rename to src/neural/backends/blas/README.md diff --git a/src/neural/blas/blas.h b/src/neural/backends/blas/blas.h similarity index 100% rename from src/neural/blas/blas.h rename to src/neural/backends/blas/blas.h diff --git a/src/neural/blas/convolution1.cc b/src/neural/backends/blas/convolution1.cc similarity index 97% rename from src/neural/blas/convolution1.cc rename to src/neural/backends/blas/convolution1.cc index c78b3976fb..8674b06dcf 100644 --- a/src/neural/blas/convolution1.cc +++ b/src/neural/backends/blas/convolution1.cc @@ -16,8 +16,8 @@ along with Leela Chess. If not, see . */ -#include "neural/blas/convolution1.h" -#include "neural/blas/blas.h" +#include "neural/backends/blas/convolution1.h" +#include "neural/backends/blas/blas.h" #include diff --git a/src/neural/blas/convolution1.h b/src/neural/backends/blas/convolution1.h similarity index 100% rename from src/neural/blas/convolution1.h rename to src/neural/backends/blas/convolution1.h diff --git a/src/neural/blas/encoder.h b/src/neural/backends/blas/encoder.h similarity index 98% rename from src/neural/blas/encoder.h rename to src/neural/backends/blas/encoder.h index 28cf3b16b1..b4544b16ff 100644 --- a/src/neural/blas/encoder.h +++ b/src/neural/backends/blas/encoder.h @@ -20,8 +20,6 @@ #include -#include "neural/shared/activation.h" - #ifdef USE_ISPC #include "layer_norm_ispc.h" #endif diff --git a/src/neural/blas/fully_connected_layer.cc b/src/neural/backends/blas/fully_connected_layer.cc similarity index 97% rename from src/neural/blas/fully_connected_layer.cc rename to src/neural/backends/blas/fully_connected_layer.cc index d228d2523f..84699a3ec2 100644 --- a/src/neural/blas/fully_connected_layer.cc +++ b/src/neural/backends/blas/fully_connected_layer.cc @@ -16,9 +16,8 @@ along with Leela Chess. If not, see . */ -#include "neural/blas/fully_connected_layer.h" -#include "neural/blas/blas.h" -#include "neural/shared/activation.h" +#include "neural/backends/blas/fully_connected_layer.h" +#include "neural/backends/blas/blas.h" #include #include diff --git a/src/neural/blas/fully_connected_layer.h b/src/neural/backends/blas/fully_connected_layer.h similarity index 96% rename from src/neural/blas/fully_connected_layer.h rename to src/neural/backends/blas/fully_connected_layer.h index 1917c41378..821947cef4 100644 --- a/src/neural/blas/fully_connected_layer.h +++ b/src/neural/backends/blas/fully_connected_layer.h @@ -18,7 +18,7 @@ #pragma once -#include "neural/shared/activation.h" +#include "neural/backends/shared/activation.h" #include #include diff --git a/src/neural/blas/layer_norm.ispc b/src/neural/backends/blas/layer_norm.ispc similarity index 100% rename from src/neural/blas/layer_norm.ispc rename to src/neural/backends/blas/layer_norm.ispc diff --git a/src/neural/blas/network_blas.cc b/src/neural/backends/blas/network_blas.cc similarity index 98% rename from src/neural/blas/network_blas.cc rename to src/neural/backends/blas/network_blas.cc index 607700df7d..71c561ca12 100644 --- a/src/neural/blas/network_blas.cc +++ b/src/neural/backends/blas/network_blas.cc @@ -22,19 +22,19 @@ #include #include -#include "neural/blas/blas.h" -#include "neural/blas/convolution1.h" -#include "neural/blas/encoder.h" -#include "neural/blas/fully_connected_layer.h" -#include "neural/blas/se_unit.h" -#include "neural/blas/winograd_convolution3.h" +#include "neural/backends/blas/blas.h" +#include "neural/backends/blas/convolution1.h" +#include "neural/backends/blas/encoder.h" +#include "neural/backends/blas/fully_connected_layer.h" +#include "neural/backends/blas/se_unit.h" +#include "neural/backends/blas/winograd_convolution3.h" +#include "neural/backends/shared/activation.h" +#include "neural/backends/shared/winograd_filter.h" #include "neural/factory.h" #include "neural/network.h" #include "neural/network_legacy.h" -#include "neural/shared/activation.h" -#include "neural/shared/attention_policy_map.h" -#include "neural/shared/policy_map.h" -#include "neural/shared/winograd_filter.h" +#include "neural/tables/attention_policy_map.h" +#include "neural/tables/policy_map.h" #include "utils/numa.h" #ifdef USE_DNNL diff --git a/src/neural/blas/se_unit.cc b/src/neural/backends/blas/se_unit.cc similarity index 97% rename from src/neural/blas/se_unit.cc rename to src/neural/backends/blas/se_unit.cc index a4f24f0e0b..68761f75f5 100644 --- a/src/neural/blas/se_unit.cc +++ b/src/neural/backends/blas/se_unit.cc @@ -16,8 +16,8 @@ along with Leela Chess. If not, see . */ -#include "neural/blas/se_unit.h" -#include "neural/blas/fully_connected_layer.h" +#include "neural/backends/blas/se_unit.h" +#include "neural/backends/blas/fully_connected_layer.h" #include diff --git a/src/neural/blas/se_unit.h b/src/neural/backends/blas/se_unit.h similarity index 96% rename from src/neural/blas/se_unit.h rename to src/neural/backends/blas/se_unit.h index afc7f2dc15..a93bce1750 100644 --- a/src/neural/blas/se_unit.h +++ b/src/neural/backends/blas/se_unit.h @@ -18,7 +18,7 @@ #pragma once -#include "neural/shared/activation.h" +#include "neural/backends/shared/activation.h" #include diff --git a/src/neural/blas/winograd_convolution3.cc b/src/neural/backends/blas/winograd_convolution3.cc similarity index 99% rename from src/neural/blas/winograd_convolution3.cc rename to src/neural/backends/blas/winograd_convolution3.cc index cd77eb1a21..31f00b50df 100644 --- a/src/neural/blas/winograd_convolution3.cc +++ b/src/neural/backends/blas/winograd_convolution3.cc @@ -16,8 +16,8 @@ along with Leela Chess. If not, see . */ -#include "neural/blas/winograd_convolution3.h" -#include "neural/blas/blas.h" +#include "neural/backends/blas/winograd_convolution3.h" +#include "neural/backends/blas/blas.h" #include #include diff --git a/src/neural/blas/winograd_convolution3.h b/src/neural/backends/blas/winograd_convolution3.h similarity index 100% rename from src/neural/blas/winograd_convolution3.h rename to src/neural/backends/blas/winograd_convolution3.h diff --git a/src/neural/blas/winograd_transform.ispc b/src/neural/backends/blas/winograd_transform.ispc similarity index 100% rename from src/neural/blas/winograd_transform.ispc rename to src/neural/backends/blas/winograd_transform.ispc diff --git a/src/neural/cuda/common_kernels.cu b/src/neural/backends/cuda/common_kernels.cu similarity index 99% rename from src/neural/cuda/common_kernels.cu rename to src/neural/backends/cuda/common_kernels.cu index 395bab8d84..ea8801ec2f 100644 --- a/src/neural/cuda/common_kernels.cu +++ b/src/neural/backends/cuda/common_kernels.cu @@ -29,8 +29,8 @@ #include #include "cuda_common.h" -#include "neural/shared/activation.h" -#include "neural/shared/attention_policy_map.h" +#include "neural/tables/activation_function.h" +#include "neural/tables/attention_policy_map.h" #include "winograd_helper.inc" namespace lczero { diff --git a/src/neural/cuda/cuda_common.h b/src/neural/backends/cuda/cuda_common.h similarity index 100% rename from src/neural/cuda/cuda_common.h rename to src/neural/backends/cuda/cuda_common.h diff --git a/src/neural/cuda/fp16_kernels.cu b/src/neural/backends/cuda/fp16_kernels.cu similarity index 99% rename from src/neural/cuda/fp16_kernels.cu rename to src/neural/backends/cuda/fp16_kernels.cu index f30b14f50d..0d93ca6459 100644 --- a/src/neural/cuda/fp16_kernels.cu +++ b/src/neural/backends/cuda/fp16_kernels.cu @@ -26,7 +26,7 @@ */ #include "cuda_common.h" -#include "neural/shared/activation.h" +#include "neural/tables/activation_function.h" // Allow building on an old architecture. #if __CUDA_ARCH__ < 530 diff --git a/src/neural/cuda/inputs_outputs.h b/src/neural/backends/cuda/inputs_outputs.h similarity index 100% rename from src/neural/cuda/inputs_outputs.h rename to src/neural/backends/cuda/inputs_outputs.h diff --git a/src/neural/cuda/kernels.h b/src/neural/backends/cuda/kernels.h similarity index 99% rename from src/neural/cuda/kernels.h rename to src/neural/backends/cuda/kernels.h index a1a2145737..06ad15c657 100644 --- a/src/neural/cuda/kernels.h +++ b/src/neural/backends/cuda/kernels.h @@ -28,7 +28,7 @@ #pragma once #include "cuda_common.h" -#include "neural/shared/activation.h" +#include "neural/tables/activation_function.h" namespace lczero { namespace cudnn_backend { diff --git a/src/neural/cuda/layers.cc b/src/neural/backends/cuda/layers.cc similarity index 99% rename from src/neural/cuda/layers.cc rename to src/neural/backends/cuda/layers.cc index 8543443897..81a0b01b8b 100644 --- a/src/neural/cuda/layers.cc +++ b/src/neural/backends/cuda/layers.cc @@ -33,8 +33,7 @@ #include "cuda_common.h" #include "kernels.h" #include "neural/network.h" -#include "neural/shared/activation.h" -#include "neural/shared/attention_policy_map.h" +#include "neural/tables/attention_policy_map.h" #include "utils/fp16_utils.h" namespace lczero { diff --git a/src/neural/cuda/layers.h b/src/neural/backends/cuda/layers.h similarity index 99% rename from src/neural/cuda/layers.h rename to src/neural/backends/cuda/layers.h index de563f9346..9ba5bd286e 100644 --- a/src/neural/cuda/layers.h +++ b/src/neural/backends/cuda/layers.h @@ -32,7 +32,7 @@ #include "cuda_common.h" #include "neural/network_legacy.h" -#include "neural/shared/activation.h" +#include "neural/tables/activation_function.h" #ifdef USE_CUDNN #include diff --git a/src/neural/cuda/network_cuda.cc b/src/neural/backends/cuda/network_cuda.cc similarity index 99% rename from src/neural/cuda/network_cuda.cc rename to src/neural/backends/cuda/network_cuda.cc index cf67d1336c..2382b04c63 100644 --- a/src/neural/cuda/network_cuda.cc +++ b/src/neural/backends/cuda/network_cuda.cc @@ -37,9 +37,8 @@ #include "layers.h" #include "neural/factory.h" #include "neural/network_legacy.h" -#include "neural/shared/activation.h" -#include "neural/shared/attention_policy_map.h" -#include "neural/shared/policy_map.h" +#include "neural/tables/attention_policy_map.h" +#include "neural/tables/policy_map.h" #include "utils/bititer.h" #include "utils/exception.h" diff --git a/src/neural/cuda/network_cudnn.cc b/src/neural/backends/cuda/network_cudnn.cc similarity index 99% rename from src/neural/cuda/network_cudnn.cc rename to src/neural/backends/cuda/network_cudnn.cc index d5b54decdc..ea9e341e07 100644 --- a/src/neural/cuda/network_cudnn.cc +++ b/src/neural/backends/cuda/network_cudnn.cc @@ -37,9 +37,8 @@ #include "layers.h" #include "neural/factory.h" #include "neural/network_legacy.h" -#include "neural/shared/activation.h" -#include "neural/shared/attention_policy_map.h" -#include "neural/shared/policy_map.h" +#include "neural/tables/attention_policy_map.h" +#include "neural/tables/policy_map.h" #include "utils/bititer.h" #include "utils/exception.h" diff --git a/src/neural/cuda/readme.txt b/src/neural/backends/cuda/readme.txt similarity index 100% rename from src/neural/cuda/readme.txt rename to src/neural/backends/cuda/readme.txt diff --git a/src/neural/cuda/winograd_helper.inc b/src/neural/backends/cuda/winograd_helper.inc similarity index 100% rename from src/neural/cuda/winograd_helper.inc rename to src/neural/backends/cuda/winograd_helper.inc diff --git a/src/neural/dx/MetaCommand.h b/src/neural/backends/dx/MetaCommand.h similarity index 100% rename from src/neural/dx/MetaCommand.h rename to src/neural/backends/dx/MetaCommand.h diff --git a/src/neural/dx/dx_common.h b/src/neural/backends/dx/dx_common.h similarity index 100% rename from src/neural/dx/dx_common.h rename to src/neural/backends/dx/dx_common.h diff --git a/src/neural/dx/layers_dx.cc b/src/neural/backends/dx/layers_dx.cc similarity index 100% rename from src/neural/dx/layers_dx.cc rename to src/neural/backends/dx/layers_dx.cc diff --git a/src/neural/dx/layers_dx.h b/src/neural/backends/dx/layers_dx.h similarity index 100% rename from src/neural/dx/layers_dx.h rename to src/neural/backends/dx/layers_dx.h diff --git a/src/neural/dx/network_dx.cc b/src/neural/backends/dx/network_dx.cc similarity index 99% rename from src/neural/dx/network_dx.cc rename to src/neural/backends/dx/network_dx.cc index 1c34a6fb2d..1000b88422 100644 --- a/src/neural/dx/network_dx.cc +++ b/src/neural/backends/dx/network_dx.cc @@ -35,7 +35,7 @@ #include #include "layers_dx.h" -#include "neural/shared/policy_map.h" +#include "neural/tables/policy_map.h" #include "shader_wrapper.h" #include "utils/bititer.h" #include "utils/exception.h" diff --git a/src/neural/dx/network_dx.h b/src/neural/backends/dx/network_dx.h similarity index 100% rename from src/neural/dx/network_dx.h rename to src/neural/backends/dx/network_dx.h diff --git a/src/neural/dx/shader_wrapper.cc b/src/neural/backends/dx/shader_wrapper.cc similarity index 100% rename from src/neural/dx/shader_wrapper.cc rename to src/neural/backends/dx/shader_wrapper.cc diff --git a/src/neural/dx/shader_wrapper.h b/src/neural/backends/dx/shader_wrapper.h similarity index 100% rename from src/neural/dx/shader_wrapper.h rename to src/neural/backends/dx/shader_wrapper.h diff --git a/src/neural/dx/shaders/AddVectors.hlsl b/src/neural/backends/dx/shaders/AddVectors.hlsl similarity index 100% rename from src/neural/dx/shaders/AddVectors.hlsl rename to src/neural/backends/dx/shaders/AddVectors.hlsl diff --git a/src/neural/dx/shaders/Conv1x1.hlsl b/src/neural/backends/dx/shaders/Conv1x1.hlsl similarity index 100% rename from src/neural/dx/shaders/Conv1x1.hlsl rename to src/neural/backends/dx/shaders/Conv1x1.hlsl diff --git a/src/neural/dx/shaders/ExpandPlanes.hlsl b/src/neural/backends/dx/shaders/ExpandPlanes.hlsl similarity index 100% rename from src/neural/dx/shaders/ExpandPlanes.hlsl rename to src/neural/backends/dx/shaders/ExpandPlanes.hlsl diff --git a/src/neural/dx/shaders/Gemm.hlsl b/src/neural/backends/dx/shaders/Gemm.hlsl similarity index 100% rename from src/neural/dx/shaders/Gemm.hlsl rename to src/neural/backends/dx/shaders/Gemm.hlsl diff --git a/src/neural/dx/shaders/PolicyMap.hlsl b/src/neural/backends/dx/shaders/PolicyMap.hlsl similarity index 100% rename from src/neural/dx/shaders/PolicyMap.hlsl rename to src/neural/backends/dx/shaders/PolicyMap.hlsl diff --git a/src/neural/dx/shaders/SE.hlsl b/src/neural/backends/dx/shaders/SE.hlsl similarity index 100% rename from src/neural/dx/shaders/SE.hlsl rename to src/neural/backends/dx/shaders/SE.hlsl diff --git a/src/neural/dx/shaders/WinogradCommon.h b/src/neural/backends/dx/shaders/WinogradCommon.h similarity index 100% rename from src/neural/dx/shaders/WinogradCommon.h rename to src/neural/backends/dx/shaders/WinogradCommon.h diff --git a/src/neural/dx/shaders/WinogradTransform.hlsl b/src/neural/backends/dx/shaders/WinogradTransform.hlsl similarity index 100% rename from src/neural/dx/shaders/WinogradTransform.hlsl rename to src/neural/backends/dx/shaders/WinogradTransform.hlsl diff --git a/src/neural/dx/shaders/WinogradTransformSE.hlsl b/src/neural/backends/dx/shaders/WinogradTransformSE.hlsl similarity index 100% rename from src/neural/dx/shaders/WinogradTransformSE.hlsl rename to src/neural/backends/dx/shaders/WinogradTransformSE.hlsl diff --git a/src/neural/dx/shaders/dxc_helper.py b/src/neural/backends/dx/shaders/dxc_helper.py similarity index 100% rename from src/neural/dx/shaders/dxc_helper.py rename to src/neural/backends/dx/shaders/dxc_helper.py diff --git a/src/neural/dx/shaders/meson.build b/src/neural/backends/dx/shaders/meson.build similarity index 100% rename from src/neural/dx/shaders/meson.build rename to src/neural/backends/dx/shaders/meson.build diff --git a/src/neural/dx/shaders/shader_shared.h b/src/neural/backends/dx/shaders/shader_shared.h similarity index 100% rename from src/neural/dx/shaders/shader_shared.h rename to src/neural/backends/dx/shaders/shader_shared.h diff --git a/src/neural/dx/shaders/shaders.h b/src/neural/backends/dx/shaders/shaders.h similarity index 100% rename from src/neural/dx/shaders/shaders.h rename to src/neural/backends/dx/shaders/shaders.h diff --git a/src/neural/metal/metal_common.h b/src/neural/backends/metal/metal_common.h similarity index 100% rename from src/neural/metal/metal_common.h rename to src/neural/backends/metal/metal_common.h diff --git a/src/neural/metal/mps/MetalNetworkBuilder.h b/src/neural/backends/metal/mps/MetalNetworkBuilder.h similarity index 100% rename from src/neural/metal/mps/MetalNetworkBuilder.h rename to src/neural/backends/metal/mps/MetalNetworkBuilder.h diff --git a/src/neural/metal/mps/MetalNetworkBuilder.mm b/src/neural/backends/metal/mps/MetalNetworkBuilder.mm similarity index 99% rename from src/neural/metal/mps/MetalNetworkBuilder.mm rename to src/neural/backends/metal/mps/MetalNetworkBuilder.mm index 4c3d5c9ccc..2be155975a 100644 --- a/src/neural/metal/mps/MetalNetworkBuilder.mm +++ b/src/neural/backends/metal/mps/MetalNetworkBuilder.mm @@ -26,7 +26,7 @@ Toolkit and the NVIDIA CUDA Deep Neural Network library (or a */ #import "neural/network_legacy.h" -#import "neural/shared/attention_policy_map.h" +#import "neural/tables/attention_policy_map.h" #import "MetalNetworkBuilder.h" #import "NetworkGraph.h" diff --git a/src/neural/metal/mps/NetworkGraph.h b/src/neural/backends/metal/mps/NetworkGraph.h similarity index 100% rename from src/neural/metal/mps/NetworkGraph.h rename to src/neural/backends/metal/mps/NetworkGraph.h diff --git a/src/neural/metal/mps/NetworkGraph.mm b/src/neural/backends/metal/mps/NetworkGraph.mm similarity index 100% rename from src/neural/metal/mps/NetworkGraph.mm rename to src/neural/backends/metal/mps/NetworkGraph.mm diff --git a/src/neural/metal/network_metal.cc b/src/neural/backends/metal/network_metal.cc similarity index 99% rename from src/neural/metal/network_metal.cc rename to src/neural/backends/metal/network_metal.cc index f3d8d7eda2..0a45eb74da 100644 --- a/src/neural/metal/network_metal.cc +++ b/src/neural/backends/metal/network_metal.cc @@ -37,8 +37,8 @@ #include "mps/MetalNetworkBuilder.h" #include "neural/factory.h" #include "neural/network_legacy.h" -#include "neural/shared/attention_policy_map.h" -#include "neural/shared/policy_map.h" +#include "neural/tables/attention_policy_map.h" +#include "neural/tables/policy_map.h" #include "utils/bititer.h" #include "utils/exception.h" diff --git a/src/neural/metal/network_metal.h b/src/neural/backends/metal/network_metal.h similarity index 100% rename from src/neural/metal/network_metal.h rename to src/neural/backends/metal/network_metal.h diff --git a/src/neural/network_check.cc b/src/neural/backends/network_check.cc similarity index 100% rename from src/neural/network_check.cc rename to src/neural/backends/network_check.cc diff --git a/src/neural/network_demux.cc b/src/neural/backends/network_demux.cc similarity index 100% rename from src/neural/network_demux.cc rename to src/neural/backends/network_demux.cc diff --git a/src/neural/network_mux.cc b/src/neural/backends/network_mux.cc similarity index 100% rename from src/neural/network_mux.cc rename to src/neural/backends/network_mux.cc diff --git a/src/neural/onnx/network_onnx.cc b/src/neural/backends/network_onnx.cc similarity index 100% rename from src/neural/onnx/network_onnx.cc rename to src/neural/backends/network_onnx.cc diff --git a/src/neural/network_random.cc b/src/neural/backends/network_random.cc similarity index 100% rename from src/neural/network_random.cc rename to src/neural/backends/network_random.cc diff --git a/src/neural/network_record.cc b/src/neural/backends/network_record.cc similarity index 100% rename from src/neural/network_record.cc rename to src/neural/backends/network_record.cc diff --git a/src/neural/network_rr.cc b/src/neural/backends/network_rr.cc similarity index 100% rename from src/neural/network_rr.cc rename to src/neural/backends/network_rr.cc diff --git a/src/neural/network_tf_cc.cc b/src/neural/backends/network_tf_cc.cc similarity index 99% rename from src/neural/network_tf_cc.cc rename to src/neural/backends/network_tf_cc.cc index f7b5cad65f..68d1c0fb9d 100644 --- a/src/neural/network_tf_cc.cc +++ b/src/neural/backends/network_tf_cc.cc @@ -38,7 +38,7 @@ #include "neural/factory.h" #include "neural/network_legacy.h" -#include "neural/shared/policy_map.h" +#include "neural/tables/policy_map.h" #include "utils/bititer.h" #include "utils/optionsdict.h" #include "utils/transpose.h" diff --git a/src/neural/network_trivial.cc b/src/neural/backends/network_trivial.cc similarity index 100% rename from src/neural/network_trivial.cc rename to src/neural/backends/network_trivial.cc diff --git a/src/neural/onednn/layers.cc b/src/neural/backends/onednn/layers.cc similarity index 100% rename from src/neural/onednn/layers.cc rename to src/neural/backends/onednn/layers.cc diff --git a/src/neural/onednn/layers.h b/src/neural/backends/onednn/layers.h similarity index 99% rename from src/neural/onednn/layers.h rename to src/neural/backends/onednn/layers.h index 64b0096fc1..0192096a06 100644 --- a/src/neural/onednn/layers.h +++ b/src/neural/backends/onednn/layers.h @@ -26,7 +26,7 @@ */ #pragma once -#include "neural/shared/activation.h" +#include "neural/tables/activation_function.h" #include "utils/exception.h" #include "dnnl.hpp" diff --git a/src/neural/onednn/network_onednn.cc b/src/neural/backends/onednn/network_onednn.cc similarity index 99% rename from src/neural/onednn/network_onednn.cc rename to src/neural/backends/onednn/network_onednn.cc index 3f03cbd054..5fb85b77a5 100644 --- a/src/neural/onednn/network_onednn.cc +++ b/src/neural/backends/onednn/network_onednn.cc @@ -35,8 +35,8 @@ #include "layers.h" #include "neural/factory.h" #include "neural/network_legacy.h" -#include "neural/shared/attention_policy_map.h" -#include "neural/shared/policy_map.h" +#include "neural/tables/attention_policy_map.h" +#include "neural/tables/policy_map.h" #include "utils/bititer.h" #include "utils/exception.h" diff --git a/src/neural/opencl/OpenCL.cc b/src/neural/backends/opencl/OpenCL.cc similarity index 98% rename from src/neural/opencl/OpenCL.cc rename to src/neural/backends/opencl/OpenCL.cc index 746fcff441..563cef317e 100644 --- a/src/neural/opencl/OpenCL.cc +++ b/src/neural/backends/opencl/OpenCL.cc @@ -32,9 +32,9 @@ #include #include -#include "neural/opencl/OpenCL.h" -#include "neural/opencl/OpenCLParams.h" -#include "neural/opencl/OpenCLTuner.h" +#include "neural/backends/opencl/OpenCL.h" +#include "neural/backends/opencl/OpenCLParams.h" +#include "neural/backends/opencl/OpenCLTuner.h" #include "utils/logging.h" static std::string cl_args = diff --git a/src/neural/opencl/OpenCL.h b/src/neural/backends/opencl/OpenCL.h similarity index 98% rename from src/neural/opencl/OpenCL.h rename to src/neural/backends/opencl/OpenCL.h index 559f1ef382..24bb147c98 100644 --- a/src/neural/opencl/OpenCL.h +++ b/src/neural/backends/opencl/OpenCL.h @@ -37,8 +37,8 @@ using net_t = float; #include #include "cl2.hpp" -#include "neural/opencl/OpenCLBuffers.h" -#include "neural/opencl/OpenCLParams.h" +#include "neural/backends/opencl/OpenCLBuffers.h" +#include "neural/backends/opencl/OpenCLParams.h" inline size_t ceilMultiple(size_t a, size_t b) { if (a % b == 0) return a; diff --git a/src/neural/opencl/OpenCLBuffers.cc b/src/neural/backends/opencl/OpenCLBuffers.cc similarity index 99% rename from src/neural/opencl/OpenCLBuffers.cc rename to src/neural/backends/opencl/OpenCLBuffers.cc index a12f4a4d6a..a6276aac8c 100644 --- a/src/neural/opencl/OpenCLBuffers.cc +++ b/src/neural/backends/opencl/OpenCLBuffers.cc @@ -19,7 +19,7 @@ along with Leela Chess. If not, see . */ -#include "neural/opencl/OpenCLBuffers.h" +#include "neural/backends/opencl/OpenCLBuffers.h" OpenCLBuffers::OpenCLBuffers(const OpenCL_Network& opencl_net) : m_opencl_net(opencl_net), m_opencl(opencl_net.getOpenCL()) { diff --git a/src/neural/opencl/OpenCLBuffers.h b/src/neural/backends/opencl/OpenCLBuffers.h similarity index 96% rename from src/neural/opencl/OpenCLBuffers.h rename to src/neural/backends/opencl/OpenCLBuffers.h index 56d53c4703..3742734b83 100644 --- a/src/neural/opencl/OpenCLBuffers.h +++ b/src/neural/backends/opencl/OpenCLBuffers.h @@ -34,9 +34,9 @@ #include #include -#include "neural/opencl/OpenCL.h" -#include "neural/opencl/OpenCLParams.h" -#include "neural/opencl/OpenCLTuner.h" +#include "neural/backends/opencl/OpenCL.h" +#include "neural/backends/opencl/OpenCLParams.h" +#include "neural/backends/opencl/OpenCLTuner.h" #include "utils/logging.h" class OpenCL_Network; diff --git a/src/neural/opencl/OpenCLParams.h b/src/neural/backends/opencl/OpenCLParams.h similarity index 100% rename from src/neural/opencl/OpenCLParams.h rename to src/neural/backends/opencl/OpenCLParams.h diff --git a/src/neural/opencl/OpenCLTuner.cc b/src/neural/backends/opencl/OpenCLTuner.cc similarity index 99% rename from src/neural/opencl/OpenCLTuner.cc rename to src/neural/backends/opencl/OpenCLTuner.cc index 1e8a0c334b..d25dc48f8c 100644 --- a/src/neural/opencl/OpenCLTuner.cc +++ b/src/neural/backends/opencl/OpenCLTuner.cc @@ -19,7 +19,7 @@ along with Leela Chess. If not, see . */ -#include "neural/opencl/OpenCLTuner.h" +#include "neural/backends/opencl/OpenCLTuner.h" #include #include @@ -31,8 +31,8 @@ #include #include -#include "neural/opencl/OpenCL.h" -#include "neural/opencl/OpenCLParams.h" +#include "neural/backends/opencl/OpenCL.h" +#include "neural/backends/opencl/OpenCLParams.h" #include "utils/logging.h" constexpr auto MAX_ERROR = 1e-4f; diff --git a/src/neural/opencl/OpenCLTuner.h b/src/neural/backends/opencl/OpenCLTuner.h similarity index 96% rename from src/neural/opencl/OpenCLTuner.h rename to src/neural/backends/opencl/OpenCLTuner.h index 0c1ed449ed..fec9105030 100644 --- a/src/neural/opencl/OpenCLTuner.h +++ b/src/neural/backends/opencl/OpenCLTuner.h @@ -26,8 +26,8 @@ #include #include "OpenCLParams.h" -#include "neural/opencl/OpenCL.h" -#include "neural/opencl/OpenCLParams.h" +#include "neural/backends/opencl/OpenCL.h" +#include "neural/backends/opencl/OpenCLParams.h" using Configurations = std::pair>; using TuneParameters = std::map; diff --git a/src/neural/opencl/README.md b/src/neural/backends/opencl/README.md similarity index 100% rename from src/neural/opencl/README.md rename to src/neural/backends/opencl/README.md diff --git a/src/neural/opencl/clblast_level3/common.opencl b/src/neural/backends/opencl/clblast_level3/common.opencl similarity index 100% rename from src/neural/opencl/clblast_level3/common.opencl rename to src/neural/backends/opencl/clblast_level3/common.opencl diff --git a/src/neural/opencl/clblast_level3/xgemm_batched.opencl b/src/neural/backends/opencl/clblast_level3/xgemm_batched.opencl similarity index 100% rename from src/neural/opencl/clblast_level3/xgemm_batched.opencl rename to src/neural/backends/opencl/clblast_level3/xgemm_batched.opencl diff --git a/src/neural/opencl/clblast_level3/xgemm_part1.opencl b/src/neural/backends/opencl/clblast_level3/xgemm_part1.opencl similarity index 100% rename from src/neural/opencl/clblast_level3/xgemm_part1.opencl rename to src/neural/backends/opencl/clblast_level3/xgemm_part1.opencl diff --git a/src/neural/opencl/clblast_level3/xgemm_part2.opencl b/src/neural/backends/opencl/clblast_level3/xgemm_part2.opencl similarity index 100% rename from src/neural/opencl/clblast_level3/xgemm_part2.opencl rename to src/neural/backends/opencl/clblast_level3/xgemm_part2.opencl diff --git a/src/neural/opencl/clblast_level3/xgemm_part3.opencl b/src/neural/backends/opencl/clblast_level3/xgemm_part3.opencl similarity index 100% rename from src/neural/opencl/clblast_level3/xgemm_part3.opencl rename to src/neural/backends/opencl/clblast_level3/xgemm_part3.opencl diff --git a/src/neural/opencl/clblast_level3/xgemv.opencl b/src/neural/backends/opencl/clblast_level3/xgemv.opencl similarity index 100% rename from src/neural/opencl/clblast_level3/xgemv.opencl rename to src/neural/backends/opencl/clblast_level3/xgemv.opencl diff --git a/src/neural/opencl/clsource/config.opencl b/src/neural/backends/opencl/clsource/config.opencl similarity index 100% rename from src/neural/opencl/clsource/config.opencl rename to src/neural/backends/opencl/clsource/config.opencl diff --git a/src/neural/opencl/clsource/convolve1.opencl b/src/neural/backends/opencl/clsource/convolve1.opencl similarity index 100% rename from src/neural/opencl/clsource/convolve1.opencl rename to src/neural/backends/opencl/clsource/convolve1.opencl diff --git a/src/neural/opencl/clsource/convolve3.opencl b/src/neural/backends/opencl/clsource/convolve3.opencl similarity index 100% rename from src/neural/opencl/clsource/convolve3.opencl rename to src/neural/backends/opencl/clsource/convolve3.opencl diff --git a/src/neural/opencl/clsource/policymap.opencl b/src/neural/backends/opencl/clsource/policymap.opencl similarity index 100% rename from src/neural/opencl/clsource/policymap.opencl rename to src/neural/backends/opencl/clsource/policymap.opencl diff --git a/src/neural/opencl/clsource/se.opencl b/src/neural/backends/opencl/clsource/se.opencl similarity index 100% rename from src/neural/opencl/clsource/se.opencl rename to src/neural/backends/opencl/clsource/se.opencl diff --git a/src/neural/opencl/network_opencl.cc b/src/neural/backends/opencl/network_opencl.cc similarity index 98% rename from src/neural/opencl/network_opencl.cc rename to src/neural/backends/opencl/network_opencl.cc index 5d71d06291..428b06315f 100644 --- a/src/neural/opencl/network_opencl.cc +++ b/src/neural/backends/opencl/network_opencl.cc @@ -22,14 +22,14 @@ #include #include +#include "neural/backends/opencl/OpenCL.h" +#include "neural/backends/opencl/OpenCLParams.h" +#include "neural/backends/shared/activation.h" +#include "neural/backends/shared/winograd_filter.h" #include "neural/factory.h" #include "neural/network.h" #include "neural/network_legacy.h" -#include "neural/opencl/OpenCL.h" -#include "neural/opencl/OpenCLParams.h" -#include "neural/shared/activation.h" -#include "neural/shared/policy_map.h" -#include "neural/shared/winograd_filter.h" +#include "neural/tables/policy_map.h" #include "utils/bititer.h" #include "utils/exception.h" #include "utils/filesystem.h" diff --git a/src/neural/shared/activation.cc b/src/neural/backends/shared/activation.cc similarity index 99% rename from src/neural/shared/activation.cc rename to src/neural/backends/shared/activation.cc index 1710d9e802..6f2551a7e6 100644 --- a/src/neural/shared/activation.cc +++ b/src/neural/backends/shared/activation.cc @@ -16,7 +16,7 @@ along with Leela Chess. If not, see . */ -#include "neural/shared/activation.h" +#include "neural/backends/shared/activation.h" #include #include diff --git a/src/neural/shared/activation.h b/src/neural/backends/shared/activation.h similarity index 72% rename from src/neural/shared/activation.h rename to src/neural/backends/shared/activation.h index 6f110886db..b786d3435d 100644 --- a/src/neural/shared/activation.h +++ b/src/neural/backends/shared/activation.h @@ -21,27 +21,9 @@ #include #include -namespace lczero { -// The following list matches the one in net.proto. Ideally this would be done -// by including proto/net.pb.h, but this is incompatible with nvcc. -enum ActivationFunction { - ACTIVATION_DEFAULT = 0, - ACTIVATION_MISH = 1, - ACTIVATION_RELU = 2, - ACTIVATION_NONE = 3, - ACTIVATION_TANH = 4, - ACTIVATION_SIGMOID = 5, - ACTIVATION_SELU = 6, - ACTIVATION_SWISH = 7, - ACTIVATION_RELU_2 = 8, - ACTIVATION_SOFTMAX = 9, -}; +#include "neural/tables/activation_function.h" -struct Activations { - ActivationFunction default_activation = ACTIVATION_RELU; - ActivationFunction smolgen_activation = ACTIVATION_SWISH; - ActivationFunction ffn_activation = ACTIVATION_RELU_2; -}; +namespace lczero { // Softmax activation void SoftmaxActivation(const size_t size, const float* input, float* output); diff --git a/src/neural/shared/activation.ispc b/src/neural/backends/shared/activation.ispc similarity index 100% rename from src/neural/shared/activation.ispc rename to src/neural/backends/shared/activation.ispc diff --git a/src/neural/shared/winograd_filter.cc b/src/neural/backends/shared/winograd_filter.cc similarity index 98% rename from src/neural/shared/winograd_filter.cc rename to src/neural/backends/shared/winograd_filter.cc index 3bedd29596..e985565663 100644 --- a/src/neural/shared/winograd_filter.cc +++ b/src/neural/backends/shared/winograd_filter.cc @@ -16,7 +16,7 @@ along with Leela Chess. If not, see . */ -#include "neural/shared/winograd_filter.h" +#include "neural/backends/shared/winograd_filter.h" #include diff --git a/src/neural/shared/winograd_filter.h b/src/neural/backends/shared/winograd_filter.h similarity index 100% rename from src/neural/shared/winograd_filter.h rename to src/neural/backends/shared/winograd_filter.h diff --git a/src/neural/xla/network_xla.cc b/src/neural/backends/xla/network_xla.cc similarity index 99% rename from src/neural/xla/network_xla.cc rename to src/neural/backends/xla/network_xla.cc index 447a45c7b0..1d0cad0a71 100644 --- a/src/neural/xla/network_xla.cc +++ b/src/neural/backends/xla/network_xla.cc @@ -27,11 +27,11 @@ #include +#include "neural/backends/xla/xla_runner.h" #include "neural/factory.h" #include "neural/network.h" #include "neural/onnx/converter.h" #include "neural/xla/onnx2hlo.h" -#include "neural/xla/xla_runner.h" #include "utils/bititer.h" namespace lczero { diff --git a/src/neural/xla/pjrt.cc b/src/neural/backends/xla/pjrt.cc similarity index 100% rename from src/neural/xla/pjrt.cc rename to src/neural/backends/xla/pjrt.cc diff --git a/src/neural/xla/pjrt.h b/src/neural/backends/xla/pjrt.h similarity index 100% rename from src/neural/xla/pjrt.h rename to src/neural/backends/xla/pjrt.h diff --git a/src/neural/xla/xla_runner.cc b/src/neural/backends/xla/xla_runner.cc similarity index 99% rename from src/neural/xla/xla_runner.cc rename to src/neural/backends/xla/xla_runner.cc index 766c617fc8..4ce2de4a54 100644 --- a/src/neural/xla/xla_runner.cc +++ b/src/neural/backends/xla/xla_runner.cc @@ -25,7 +25,7 @@ Program grant you additional permission to convey the resulting work. */ -#include "neural/xla/xla_runner.h" +#include "neural/backends/xla/xla_runner.h" #include #include diff --git a/src/neural/xla/xla_runner.h b/src/neural/backends/xla/xla_runner.h similarity index 98% rename from src/neural/xla/xla_runner.h rename to src/neural/backends/xla/xla_runner.h index 62c4a27f14..931571362e 100644 --- a/src/neural/xla/xla_runner.h +++ b/src/neural/backends/xla/xla_runner.h @@ -33,8 +33,8 @@ #include #include +#include "neural/backends/xla/pjrt.h" #include "neural/xla/hlo.pb.h" -#include "neural/xla/pjrt.h" #include "neural/xla/xla_tensor.h" namespace lczero { @@ -76,4 +76,4 @@ class XlaRunner { int device_; }; -} // namespace lczero \ No newline at end of file +} // namespace lczero diff --git a/src/neural/onnx/converter.cc b/src/neural/onnx/converter.cc index 19bb48c7ac..07986d4ef6 100644 --- a/src/neural/onnx/converter.cc +++ b/src/neural/onnx/converter.cc @@ -38,9 +38,9 @@ #include "neural/network_legacy.h" #include "neural/onnx/adapters.h" #include "neural/onnx/builder.h" -#include "neural/shared/activation.h" -#include "neural/shared/attention_policy_map.h" -#include "neural/shared/policy_map.h" +#include "neural/tables/activation_function.h" +#include "neural/tables/attention_policy_map.h" +#include "neural/tables/policy_map.h" #include "proto/net.pb.h" #include "utils/bf16_utils.h" #include "utils/exception.h" diff --git a/src/neural/tables/activation_function.h b/src/neural/tables/activation_function.h new file mode 100644 index 0000000000..56a35f5608 --- /dev/null +++ b/src/neural/tables/activation_function.h @@ -0,0 +1,43 @@ +/* + This file is part of Leela Chess Zero. + Copyright (C) 2018-2022 The LCZero Authors + + Leela Chess is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Leela Chess is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Leela Chess. If not, see . + */ + +#pragma once + +namespace lczero { +// The following list matches the one in net.proto. Ideally this would be done +// by including proto/net.pb.h, but this is incompatible with nvcc. +enum ActivationFunction { + ACTIVATION_DEFAULT = 0, + ACTIVATION_MISH = 1, + ACTIVATION_RELU = 2, + ACTIVATION_NONE = 3, + ACTIVATION_TANH = 4, + ACTIVATION_SIGMOID = 5, + ACTIVATION_SELU = 6, + ACTIVATION_SWISH = 7, + ACTIVATION_RELU_2 = 8, + ACTIVATION_SOFTMAX = 9, +}; + +struct Activations { + ActivationFunction default_activation = ACTIVATION_RELU; + ActivationFunction smolgen_activation = ACTIVATION_SWISH; + ActivationFunction ffn_activation = ACTIVATION_RELU_2; +}; + +} // namespace lczero diff --git a/src/neural/shared/attention_policy_map.h b/src/neural/tables/attention_policy_map.h similarity index 100% rename from src/neural/shared/attention_policy_map.h rename to src/neural/tables/attention_policy_map.h diff --git a/src/neural/shared/policy_map.h b/src/neural/tables/policy_map.h similarity index 100% rename from src/neural/shared/policy_map.h rename to src/neural/tables/policy_map.h diff --git a/src/neural/xla/onnx2hlo.h b/src/neural/xla/onnx2hlo.h index fe2f1876d4..e06436915d 100644 --- a/src/neural/xla/onnx2hlo.h +++ b/src/neural/xla/onnx2hlo.h @@ -27,12 +27,13 @@ #pragma once +#include #include #include #include "neural/onnx/onnx.pb.h" #include "neural/xla/hlo.pb.h" -#include "neural/xla/xla_runner.h" +#include "neural/xla/xla_tensor.h" namespace lczero { diff --git a/src/rescorer_main.cc b/src/rescorer_main.cc index f7acee7853..c693ad36d1 100644 --- a/src/rescorer_main.cc +++ b/src/rescorer_main.cc @@ -28,7 +28,7 @@ #include #include "chess/board.h" -#include "rescorer/rescoreloop.h" +#include "trainingdata/rescoreloop.h" #include "utils/commandline.h" #include "utils/esc_codes.h" #include "utils/exception.h" diff --git a/src/benchmark/backendbench.cc b/src/tools/backendbench.cc similarity index 99% rename from src/benchmark/backendbench.cc rename to src/tools/backendbench.cc index 6792f9b778..d8edf3ce97 100644 --- a/src/benchmark/backendbench.cc +++ b/src/tools/backendbench.cc @@ -25,7 +25,7 @@ Program grant you additional permission to convey the resulting work. */ -#include "benchmark/backendbench.h" +#include "tools/backendbench.h" #include "chess/board.h" #include "mcts/node.h" diff --git a/src/benchmark/backendbench.h b/src/tools/backendbench.h similarity index 100% rename from src/benchmark/backendbench.h rename to src/tools/backendbench.h diff --git a/src/benchmark/benchmark.cc b/src/tools/benchmark.cc similarity index 99% rename from src/benchmark/benchmark.cc rename to src/tools/benchmark.cc index d24638a002..c9991cdf3c 100644 --- a/src/benchmark/benchmark.cc +++ b/src/tools/benchmark.cc @@ -25,7 +25,7 @@ Program grant you additional permission to convey the resulting work. */ -#include "benchmark/benchmark.h" +#include "tools/benchmark.h" #include diff --git a/src/benchmark/benchmark.h b/src/tools/benchmark.h similarity index 100% rename from src/benchmark/benchmark.h rename to src/tools/benchmark.h diff --git a/src/lc0ctl/describenet.cc b/src/tools/describenet.cc similarity index 99% rename from src/lc0ctl/describenet.cc rename to src/tools/describenet.cc index 634589f66b..80b5f1ad82 100644 --- a/src/lc0ctl/describenet.cc +++ b/src/tools/describenet.cc @@ -25,7 +25,7 @@ Program grant you additional permission to convey the resulting work. */ -#include "lc0ctl/describenet.h" +#include "tools/describenet.h" #include "neural/loader.h" #include "neural/onnx/onnx.pb.h" diff --git a/src/lc0ctl/describenet.h b/src/tools/describenet.h similarity index 100% rename from src/lc0ctl/describenet.h rename to src/tools/describenet.h diff --git a/src/lc0ctl/leela2onnx.cc b/src/tools/leela2onnx.cc similarity index 99% rename from src/lc0ctl/leela2onnx.cc rename to src/tools/leela2onnx.cc index 8281c6967e..d2aa42796b 100644 --- a/src/lc0ctl/leela2onnx.cc +++ b/src/tools/leela2onnx.cc @@ -28,11 +28,11 @@ #include #include -#include "lc0ctl/describenet.h" #include "neural/loader.h" #include "neural/onnx/converter.h" #include "neural/xla/onnx2hlo.h" #include "neural/xla/print_hlo.h" +#include "tools/describenet.h" #include "utils/files.h" #include "utils/optionsparser.h" diff --git a/src/lc0ctl/leela2onnx.h b/src/tools/leela2onnx.h similarity index 100% rename from src/lc0ctl/leela2onnx.h rename to src/tools/leela2onnx.h diff --git a/src/lc0ctl/onnx2leela.cc b/src/tools/onnx2leela.cc similarity index 99% rename from src/lc0ctl/onnx2leela.cc rename to src/tools/onnx2leela.cc index d036138251..562367f14d 100644 --- a/src/lc0ctl/onnx2leela.cc +++ b/src/tools/onnx2leela.cc @@ -31,9 +31,9 @@ #include #include -#include "lc0ctl/describenet.h" #include "neural/onnx/onnx.pb.h" #include "proto/net.pb.h" +#include "tools/describenet.h" #include "utils/files.h" #include "utils/fp16_utils.h" #include "utils/optionsparser.h" diff --git a/src/lc0ctl/onnx2leela.h b/src/tools/onnx2leela.h similarity index 100% rename from src/lc0ctl/onnx2leela.h rename to src/tools/onnx2leela.h diff --git a/src/rescorer/rescoreloop.cc b/src/trainingdata/rescoreloop.cc similarity index 99% rename from src/rescorer/rescoreloop.cc rename to src/trainingdata/rescoreloop.cc index 2da34c3c22..51e22d4903 100644 --- a/src/rescorer/rescoreloop.cc +++ b/src/trainingdata/rescoreloop.cc @@ -25,7 +25,7 @@ Program grant you additional permission to convey the resulting work. */ -#include "rescorer/rescoreloop.h" +#include "trainingdata/rescoreloop.h" #include #include diff --git a/src/rescorer/rescoreloop.h b/src/trainingdata/rescoreloop.h similarity index 100% rename from src/rescorer/rescoreloop.h rename to src/trainingdata/rescoreloop.h From 242ddf577831ebedf60f34503f48ae376346f7f8 Mon Sep 17 00:00:00 2001 From: Alexander Lyashuk Date: Sat, 21 Dec 2024 13:43:57 +0100 Subject: [PATCH 007/212] Spinlock warning fix (#2095) --- src/utils/mutex.h | 6 +++++- src/utils/spinhelper.h | 13 +++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/utils/mutex.h b/src/utils/mutex.h index 4151af3fb8..4177e35d14 100644 --- a/src/utils/mutex.h +++ b/src/utils/mutex.h @@ -125,8 +125,12 @@ class CAPABILITY("mutex") SharedMutex { }; static inline void SpinloopPause() { -#if defined(__x86_64__) +#if defined(__x86_64__) || defined(_M_X64) _mm_pause(); +#elif defined(_MSC_VER) + __asm {} +#else + asm volatile(""); #endif } diff --git a/src/utils/spinhelper.h b/src/utils/spinhelper.h index c5e8f53633..7c2d7a8757 100644 --- a/src/utils/spinhelper.h +++ b/src/utils/spinhelper.h @@ -44,20 +44,17 @@ class SpinHelper { class ExponentialBackoffSpinHelper : public SpinHelper { public: ExponentialBackoffSpinHelper() - : backoff_iters_(kMinBackoffIters), - spin_to_sleep_iters_(0) { - } + : backoff_iters_(kMinBackoffIters), spin_to_sleep_iters_(0) {} virtual void Backoff() { thread_local std::uniform_int_distribution distribution; thread_local std::minstd_rand generator(std::random_device{}()); - const size_t spin_count = distribution(generator, decltype(distribution)::param_type{0, backoff_iters_}); + const size_t spin_count = distribution( + generator, decltype(distribution)::param_type{0, backoff_iters_}); - for (volatile size_t i=0; i Date: Mon, 23 Dec 2024 07:47:20 +0200 Subject: [PATCH 008/212] speed up position and history (#1761) --- src/chess/position.cc | 12 +++++------- src/chess/position.h | 10 +--------- src/neural/encoder.cc | 4 ++-- src/python/weights.h | 7 +++---- 4 files changed, 11 insertions(+), 22 deletions(-) diff --git a/src/chess/position.cc b/src/chess/position.cc index ec085f1e37..fcc69cf278 100644 --- a/src/chess/position.cc +++ b/src/chess/position.cc @@ -63,9 +63,8 @@ namespace lczero { Position::Position(const Position& parent, Move m) : rule50_ply_(parent.rule50_ply_ + 1), ply_count_(parent.ply_count_ + 1) { - them_board_ = parent.us_board_; - const bool is_zeroing = them_board_.ApplyMove(m); - us_board_ = them_board_; + us_board_ = parent.us_board_; + const bool is_zeroing = us_board_.ApplyMove(m); us_board_.Mirror(); if (is_zeroing) rule50_ply_ = 0; } @@ -73,8 +72,6 @@ Position::Position(const Position& parent, Move m) Position::Position(const ChessBoard& board, int rule50_ply, int game_ply) : rule50_ply_(rule50_ply), repetitions_(0), ply_count_(game_ply) { us_board_ = board; - them_board_ = board; - them_board_.Mirror(); } uint64_t Position::Hash() const { @@ -130,7 +127,7 @@ int PositionHistory::ComputeLastMoveRepetitions(int* cycle_length) const { // TODO(crem) implement hash/cache based solution. if (last.GetRule50Ply() < 4) return 0; - for (int idx = positions_.size() - 3; idx >= 0; idx -= 2) { + for (int idx = positions_.size() - 5; idx >= 0; idx -= 2) { const auto& pos = positions_[idx]; if (pos.GetBoard() == last.GetBoard()) { *cycle_length = positions_.size() - 1 - idx; @@ -162,7 +159,8 @@ uint64_t PositionHistory::HashLast(int positions) const { std::string GetFen(const Position& pos) { std::string result; - const ChessBoard& board = pos.GetWhiteBoard(); + ChessBoard board = pos.GetBoard(); + if (board.flipped()) board.Mirror(); for (int row = 7; row >= 0; --row) { int emptycounter = 0; for (int col = 0; col < 8; ++col) { diff --git a/src/chess/position.h b/src/chess/position.h index 69241467c4..dd7513e18c 100644 --- a/src/chess/position.h +++ b/src/chess/position.h @@ -64,20 +64,12 @@ class Position { // Gets board from the point of view of player to move. const ChessBoard& GetBoard() const { return us_board_; } - // Gets board from the point of view of opponent. - const ChessBoard& GetThemBoard() const { return them_board_; } - // Gets board from the point of view of the white player. - const ChessBoard& GetWhiteBoard() const { - return us_board_.flipped() ? them_board_ : us_board_; - }; std::string DebugString() const; private: // The board from the point of view of the player to move. ChessBoard us_board_; - // The board from the point of view of opponent. - ChessBoard them_board_; // How many half-moves without capture or pawn move was there. int rule50_ply_ = 0; @@ -103,7 +95,7 @@ class PositionHistory { PositionHistory(PositionHistory&& other) = default; PositionHistory& operator=(const PositionHistory& other) = default; - PositionHistory& operator=(PositionHistory&& other) = default; + PositionHistory& operator=(PositionHistory&& other) = default; // Returns first position of the game (or fen from which it was initialized). const Position& Starting() const { return positions_.front(); } diff --git a/src/neural/encoder.cc b/src/neural/encoder.cc index b459aec75b..4699c38d46 100644 --- a/src/neural/encoder.cc +++ b/src/neural/encoder.cc @@ -237,8 +237,8 @@ InputPlanes EncodePositionForNN( ++i, --history_idx) { const Position& position = history.GetPositionAt(history_idx < 0 ? 0 : history_idx); - const ChessBoard& board = - flip ? position.GetThemBoard() : position.GetBoard(); + ChessBoard board = position.GetBoard(); + if (flip) board.Mirror(); // Castling changes can't be repeated, so we can stop early. if (stop_early && board.castlings().as_int() != castlings.as_int()) break; // Enpassants can't be repeated, but we do need to always send the current diff --git a/src/python/weights.h b/src/python/weights.h index 18288c5f69..dcc1bacf54 100644 --- a/src/python/weights.h +++ b/src/python/weights.h @@ -281,10 +281,9 @@ class GameState { } std::string as_string() const { - bool is_black = history_.IsBlackToMove(); - return (is_black ? history_.Last().GetThemBoard() - : history_.Last().GetBoard()) - .DebugString(); + auto board = history_.Last().GetBoard(); + if (history_.IsBlackToMove()) board.Mirror(); + return board.DebugString(); } private: From c3a160c9438c6c8aae48c42705dff64161100b1d Mon Sep 17 00:00:00 2001 From: Alexander Lyashuk Date: Tue, 24 Dec 2024 14:10:25 +0100 Subject: [PATCH 009/212] Make EncodePositionForNN accept span (#2097) --- src/chess/position.h | 3 +++ src/neural/encoder.cc | 23 +++++++++++++++-------- src/neural/encoder.h | 7 +++++++ 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/src/chess/position.h b/src/chess/position.h index dd7513e18c..99dc01f64a 100644 --- a/src/chess/position.h +++ b/src/chess/position.h @@ -27,6 +27,7 @@ #pragma once +#include #include #include "chess/board.h" @@ -139,6 +140,8 @@ class PositionHistory { // Checks for any repetitions since the last time 50 move rule was reset. bool DidRepeatSinceLastZeroingMove() const; + std::span GetPositions() const { return positions_; } + private: int ComputeLastMoveRepetitions(int* cycle_length) const; diff --git a/src/neural/encoder.cc b/src/neural/encoder.cc index 4699c38d46..485a6a573c 100644 --- a/src/neural/encoder.cc +++ b/src/neural/encoder.cc @@ -133,7 +133,7 @@ int TransformForPosition(pblczero::NetworkFormat::InputFormat input_format, InputPlanes EncodePositionForNN( pblczero::NetworkFormat::InputFormat input_format, - const PositionHistory& history, int history_planes, + std::span history, int history_planes, FillEmptyHistory fill_empty_history, int* transform_out) { InputPlanes result(kAuxPlaneBase + 8); @@ -146,7 +146,7 @@ InputPlanes EncodePositionForNN( // it for the first board. ChessBoard::Castlings castlings; { - const ChessBoard& board = history.Last().GetBoard(); + const ChessBoard& board = history.back().GetBoard(); const bool we_are_black = board.flipped(); if (IsCanonicalFormat(input_format)) { transform = ChooseTransform(board); @@ -211,9 +211,9 @@ InputPlanes EncodePositionForNN( if (we_are_black) result[kAuxPlaneBase + 4].SetAll(); } if (IsHectopliesFormat(input_format)) { - result[kAuxPlaneBase + 5].Fill(history.Last().GetRule50Ply() / 100.0f); + result[kAuxPlaneBase + 5].Fill(history.back().GetRule50Ply() / 100.0f); } else { - result[kAuxPlaneBase + 5].Fill(history.Last().GetRule50Ply()); + result[kAuxPlaneBase + 5].Fill(history.back().GetRule50Ply()); } // Plane kAuxPlaneBase + 6 used to be movecount plane, now it's all zeros // unless we need it for canonical armageddon side to move. @@ -232,18 +232,17 @@ InputPlanes EncodePositionForNN( input_format == pblczero::NetworkFormat:: INPUT_112_WITH_CANONICALIZATION_V2_ARMAGEDDON; bool flip = false; - int history_idx = history.GetLength() - 1; + int history_idx = history.size() - 1; for (int i = 0; i < std::min(history_planes, kMoveHistory); ++i, --history_idx) { - const Position& position = - history.GetPositionAt(history_idx < 0 ? 0 : history_idx); + const Position& position = history[history_idx < 0 ? 0 : history_idx]; ChessBoard board = position.GetBoard(); if (flip) board.Mirror(); // Castling changes can't be repeated, so we can stop early. if (stop_early && board.castlings().as_int() != castlings.as_int()) break; // Enpassants can't be repeated, but we do need to always send the current // position. - if (stop_early && history_idx != history.GetLength() - 1 && + if (stop_early && history_idx != static_cast(history.size()) - 1 && !board.en_passant().empty()) { break; } @@ -327,4 +326,12 @@ InputPlanes EncodePositionForNN( return result; } +InputPlanes EncodePositionForNN( + pblczero::NetworkFormat::InputFormat input_format, + const PositionHistory& history, int history_planes, + FillEmptyHistory fill_empty_history, int* transform_out) { + return EncodePositionForNN(input_format, history.GetPositions(), + history_planes, fill_empty_history, transform_out); +} + } // namespace lczero diff --git a/src/neural/encoder.h b/src/neural/encoder.h index e027a0743f..41cf4cf0f3 100644 --- a/src/neural/encoder.h +++ b/src/neural/encoder.h @@ -27,6 +27,8 @@ #pragma once +#include + #include "chess/position.h" #include "neural/network.h" #include "proto/net.pb.h" @@ -49,6 +51,11 @@ InputPlanes EncodePositionForNN( const PositionHistory& history, int history_planes, FillEmptyHistory fill_empty_history, int* transform_out); +InputPlanes EncodePositionForNN( + pblczero::NetworkFormat::InputFormat input_format, + std::span positions, int history_planes, + FillEmptyHistory fill_empty_history, int* transform_out); + bool IsCanonicalFormat(pblczero::NetworkFormat::InputFormat input_format); bool IsCanonicalArmageddonFormat( pblczero::NetworkFormat::InputFormat input_format); From 212328463fa35229c6d7209f7631a6ae64c1ffc3 Mon Sep 17 00:00:00 2001 From: Alexander Lyashuk Date: Sat, 28 Dec 2024 22:15:31 +0100 Subject: [PATCH 010/212] Decoupling EngineLoop from EngineController (#2102) --- meson.build | 3 +- src/{engine.cc => engine_classic.cc} | 101 +++++--------------------- src/{engine.h => engine_classic.h} | 47 ++++-------- src/engine_loop.cc | 103 +++++++++++++++++++++++++++ src/engine_loop.h | 84 ++++++++++++++++++++++ src/main.cc | 11 ++- 6 files changed, 227 insertions(+), 122 deletions(-) rename src/{engine.cc => engine_classic.cc} (81%) rename src/{engine.h => engine_classic.h} (76%) create mode 100644 src/engine_loop.cc create mode 100644 src/engine_loop.h diff --git a/meson.build b/meson.build index 587ea74c92..85ab10f031 100644 --- a/meson.build +++ b/meson.build @@ -181,7 +181,8 @@ common_files += [ ] files += [ - 'src/engine.cc', + 'src/engine_classic.cc', + 'src/engine_loop.cc', 'src/mcts/params.cc', 'src/mcts/search.cc', 'src/mcts/stoppers/alphazero.cc', diff --git a/src/engine.cc b/src/engine_classic.cc similarity index 81% rename from src/engine.cc rename to src/engine_classic.cc index e4157657c6..0556467921 100644 --- a/src/engine.cc +++ b/src/engine_classic.cc @@ -25,7 +25,7 @@ Program grant you additional permission to convey the resulting work. */ -#include "engine.h" +#include "engine_classic.h" #include #include @@ -42,10 +42,6 @@ namespace { const OptionId kThreadsOptionId{ "threads", "Threads", "Number of (CPU) worker threads to use, 0 for the backend default.", 't'}; -const OptionId kLogFileId{"logfile", "LogFile", - "Write log to that file. Special value to " - "output the log to the console.", - 'l'}; const OptionId kSyzygyTablebaseId{ "syzygy-paths", "SyzygyPath", "List of Syzygy tablebase directories, list entries separated by system " @@ -64,8 +60,6 @@ const OptionId kStrictUciTiming{"strict-uci-timing", "StrictTiming", "The UCI host compensates for lag, waits for " "the 'readyok' reply before sending 'go' and " "only then starts timing."}; -const OptionId kPreload{"preload", "", - "Initialize backend and load net on engine startup."}; const OptionId kValueOnly{ "value-only", "ValueOnly", "In value only mode all search parameters are ignored and the position is " @@ -92,13 +86,13 @@ MoveList StringsToMovelist(const std::vector& moves, } // namespace -EngineController::EngineController(std::unique_ptr uci_responder, - const OptionsDict& options) +EngineClassic::EngineClassic(std::unique_ptr uci_responder, + const OptionsDict& options) : options_(options), uci_responder_(std::move(uci_responder)), current_position_{ChessBoard::kStartposFen, {}} {} -void EngineController::PopulateOptions(OptionsParser* options) { +void EngineClassic::PopulateOptions(OptionsParser* options) { using namespace std::placeholders; const bool is_simple = CommandLine::BinaryName().find("simple") != std::string::npos; @@ -129,18 +123,17 @@ void EngineController::PopulateOptions(OptionsParser* options) { options->Add(kStrictUciTiming) = false; options->HideOption(kStrictUciTiming); - options->Add(kPreload) = false; options->Add(kValueOnly) = false; options->Add(kClearTree); options->HideOption(kClearTree); } -void EngineController::ResetMoveTimer() { +void EngineClassic::ResetMoveTimer() { move_start_time_ = std::chrono::steady_clock::now(); } // Updates values from Uci options. -void EngineController::UpdateFromUciOptions() { +void EngineClassic::UpdateFromUciOptions() { SharedLock lock(busy_mutex_); // Syzygy tablebases. @@ -173,14 +166,14 @@ void EngineController::UpdateFromUciOptions() { strict_uci_timing_ = options_.Get(kStrictUciTiming); } -void EngineController::EnsureReady() { +void EngineClassic::EnsureReady() { std::unique_lock lock(busy_mutex_); // If a UCI host is waiting for our ready response, we can consider the move // not started until we're done ensuring ready. ResetMoveTimer(); } -void EngineController::NewGame() { +void EngineClassic::NewGame() { // In case anything relies upon defaulting to default position and just calls // newgame and goes straight into go. ResetMoveTimer(); @@ -193,8 +186,8 @@ void EngineController::NewGame() { UpdateFromUciOptions(); } -void EngineController::SetPosition(const std::string& fen, - const std::vector& moves_str) { +void EngineClassic::SetPosition(const std::string& fen, + const std::vector& moves_str) { // Some UCI hosts just call position then immediately call go, while starting // the clock on calling 'position'. ResetMoveTimer(); @@ -203,7 +196,7 @@ void EngineController::SetPosition(const std::string& fen, search_.reset(); } -Position EngineController::ApplyPositionMoves() { +Position EngineClassic::ApplyPositionMoves() { ChessBoard board; int no_capture_ply; int game_move; @@ -218,8 +211,8 @@ Position EngineController::ApplyPositionMoves() { return pos; } -void EngineController::SetupPosition( - const std::string& fen, const std::vector& moves_str) { +void EngineClassic::SetupPosition(const std::string& fen, + const std::vector& moves_str) { SharedLock lock(busy_mutex_); search_.reset(); @@ -233,7 +226,7 @@ void EngineController::SetupPosition( if (!is_same_game) CreateFreshTimeManager(); } -void EngineController::CreateFreshTimeManager() { +void EngineClassic::CreateFreshTimeManager() { time_manager_ = MakeTimeManager(options_); } @@ -341,7 +334,7 @@ void ValueOnlyGo(NodeTree* tree, Network* network, const OptionsDict& options, } // namespace -void EngineController::Go(const GoParams& params) { +void EngineClassic::Go(const GoParams& params) { // TODO: should consecutive calls to go be considered to be a continuation and // hence have the same start time like this behaves, or should we check start // time hasn't changed since last call to go and capture the new start time @@ -401,74 +394,14 @@ void EngineController::Go(const GoParams& params) { search_->StartThreads(options_.Get(kThreadsOptionId)); } -void EngineController::PonderHit() { +void EngineClassic::PonderHit() { ResetMoveTimer(); go_params_.ponder = false; Go(go_params_); } -void EngineController::Stop() { +void EngineClassic::Stop() { if (search_) search_->Stop(); } -EngineLoop::EngineLoop() - : engine_( - std::make_unique( - std::bind(&UciLoop::SendBestMove, this, std::placeholders::_1), - std::bind(&UciLoop::SendInfo, this, std::placeholders::_1)), - options_.GetOptionsDict()) { - engine_.PopulateOptions(&options_); - options_.Add(kLogFileId); -} - -void EngineLoop::RunLoop() { - if (!ConfigFile::Init() || !options_.ProcessAllFlags()) return; - const auto options = options_.GetOptionsDict(); - Logging::Get().SetFilename(options.Get(kLogFileId)); - if (options.Get(kPreload)) engine_.NewGame(); - UciLoop::RunLoop(); -} - -void EngineLoop::CmdUci() { - SendId(); - for (const auto& option : options_.ListOptionsUci()) { - SendResponse(option); - } - SendResponse("uciok"); -} - -void EngineLoop::CmdIsReady() { - engine_.EnsureReady(); - SendResponse("readyok"); -} - -void EngineLoop::CmdSetOption(const std::string& name, const std::string& value, - const std::string& context) { - options_.SetUciOption(name, value, context); - // Set the log filename for the case it was set in UCI option. - Logging::Get().SetFilename( - options_.GetOptionsDict().Get(kLogFileId)); -} - -void EngineLoop::CmdUciNewGame() { engine_.NewGame(); } - -void EngineLoop::CmdPosition(const std::string& position, - const std::vector& moves) { - std::string fen = position; - if (fen.empty()) { - fen = ChessBoard::kStartposFen; - } - engine_.SetPosition(fen, moves); -} - -void EngineLoop::CmdFen() { - std::string fen = GetFen(engine_.ApplyPositionMoves()); - return SendResponse(fen); -} -void EngineLoop::CmdGo(const GoParams& params) { engine_.Go(params); } - -void EngineLoop::CmdPonderHit() { engine_.PonderHit(); } - -void EngineLoop::CmdStop() { engine_.Stop(); } - } // namespace lczero diff --git a/src/engine.h b/src/engine_classic.h similarity index 76% rename from src/engine.h rename to src/engine_classic.h index 9743679a43..104f8ee66b 100644 --- a/src/engine.h +++ b/src/engine_classic.h @@ -29,14 +29,13 @@ #include -#include "chess/uciloop.h" +#include "engine_loop.h" #include "mcts/search.h" #include "neural/cache.h" #include "neural/factory.h" #include "neural/network.h" #include "syzygy/syzygy.h" #include "utils/mutex.h" -#include "utils/optionsparser.h" namespace lczero { @@ -45,34 +44,34 @@ struct CurrentPosition { std::vector moves; }; -class EngineController { +class EngineClassic : public EngineControllerBase { public: - EngineController(std::unique_ptr uci_responder, - const OptionsDict& options); + EngineClassic(std::unique_ptr uci_responder, + const OptionsDict& options); - ~EngineController() { + ~EngineClassic() { // Make sure search is destructed first, and it still may be running in // a separate thread. search_.reset(); } - void PopulateOptions(OptionsParser* options); + static void PopulateOptions(OptionsParser* options); // Blocks. - void EnsureReady(); + void EnsureReady() override; // Must not block. - void NewGame(); + void NewGame() override; // Blocks. void SetPosition(const std::string& fen, - const std::vector& moves); + const std::vector& moves) override; // Must not block. - void Go(const GoParams& params); - void PonderHit(); + void Go(const GoParams& params) override; + void PonderHit() override; // Must not block. - void Stop(); + void Stop() override; Position ApplyPositionMoves(); @@ -116,26 +115,4 @@ class EngineController { bool strict_uci_timing_; }; -class EngineLoop : public UciLoop { - public: - EngineLoop(); - - void RunLoop() override; - void CmdUci() override; - void CmdIsReady() override; - void CmdSetOption(const std::string& name, const std::string& value, - const std::string& context) override; - void CmdUciNewGame() override; - void CmdPosition(const std::string& position, - const std::vector& moves) override; - void CmdFen() override; - void CmdGo(const GoParams& params) override; - void CmdPonderHit() override; - void CmdStop() override; - - private: - OptionsParser options_; - EngineController engine_; -}; - } // namespace lczero diff --git a/src/engine_loop.cc b/src/engine_loop.cc new file mode 100644 index 0000000000..74b851abc3 --- /dev/null +++ b/src/engine_loop.cc @@ -0,0 +1,103 @@ +/* + This file is part of Leela Chess Zero. + Copyright (C) 2018-2024 The LCZero Authors + + Leela Chess is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Leela Chess is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Leela Chess. If not, see . + + Additional permission under GNU GPL version 3 section 7 + + If you modify this Program, or any covered work, by linking or + combining it with NVIDIA Corporation's libraries from the NVIDIA CUDA + Toolkit and the NVIDIA CUDA Deep Neural Network library (or a + modified version of those libraries), containing parts covered by the + terms of the respective license agreement, the licensors of this + Program grant you additional permission to convey the resulting work. +*/ + +#include "engine_loop.h" + +#include "utils/configfile.h" + +namespace lczero { +namespace { +const OptionId kLogFileId{"logfile", "LogFile", + "Write log to that file. Special value to " + "output the log to the console.", + 'l'}; +const OptionId kPreload{"preload", "", + "Initialize backend and load net on engine startup."}; +} // namespace + +EngineLoop::EngineLoop(std::unique_ptr options, + std::function( + std::unique_ptr uci_responder, + const OptionsDict& options)> + engine_factory) + : options_(std::move(options)), + engine_(engine_factory( + std::make_unique( + std::bind(&UciLoop::SendBestMove, this, std::placeholders::_1), + std::bind(&UciLoop::SendInfo, this, std::placeholders::_1)), + options_->GetOptionsDict())) { + options_->Add(kLogFileId); + options_->Add(kPreload) = false; +} + +void EngineLoop::RunLoop() { + if (!ConfigFile::Init() || !options_->ProcessAllFlags()) return; + const auto options = options_->GetOptionsDict(); + Logging::Get().SetFilename(options.Get(kLogFileId)); + if (options.Get(kPreload)) engine_->NewGame(); + UciLoop::RunLoop(); +} + +void EngineLoop::CmdUci() { + SendId(); + for (const auto& option : options_->ListOptionsUci()) { + SendResponse(option); + } + SendResponse("uciok"); +} + +void EngineLoop::CmdIsReady() { + engine_->EnsureReady(); + SendResponse("readyok"); +} + +void EngineLoop::CmdSetOption(const std::string& name, const std::string& value, + const std::string& context) { + options_->SetUciOption(name, value, context); + // Set the log filename for the case it was set in UCI option. + Logging::Get().SetFilename( + options_->GetOptionsDict().Get(kLogFileId)); +} + +void EngineLoop::CmdUciNewGame() { engine_->NewGame(); } + +void EngineLoop::CmdPosition(const std::string& position, + const std::vector& moves) { + std::string fen = position; + if (fen.empty()) { + fen = ChessBoard::kStartposFen; + } + engine_->SetPosition(fen, moves); +} + +void EngineLoop::CmdGo(const GoParams& params) { engine_->Go(params); } + +void EngineLoop::CmdPonderHit() { engine_->PonderHit(); } + +void EngineLoop::CmdStop() { engine_->Stop(); } + +} // namespace lczero diff --git a/src/engine_loop.h b/src/engine_loop.h new file mode 100644 index 0000000000..b9ace9fab2 --- /dev/null +++ b/src/engine_loop.h @@ -0,0 +1,84 @@ +/* + This file is part of Leela Chess Zero. + Copyright (C) 2018-2024 The LCZero Authors + + Leela Chess is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Leela Chess is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Leela Chess. If not, see . + + Additional permission under GNU GPL version 3 section 7 + + If you modify this Program, or any covered work, by linking or + combining it with NVIDIA Corporation's libraries from the NVIDIA CUDA + Toolkit and the NVIDIA CUDA Deep Neural Network library (or a + modified version of those libraries), containing parts covered by the + terms of the respective license agreement, the licensors of this + Program grant you additional permission to convey the resulting work. +*/ + +#pragma once + +#include +#include + +#include "chess/uciloop.h" +#include "utils/optionsparser.h" + +namespace lczero { + +class EngineControllerBase { + public: + virtual ~EngineControllerBase() = default; + + // Blocks. + virtual void EnsureReady() = 0; + + // Must not block. + virtual void NewGame() = 0; + + // Blocks. + virtual void SetPosition(const std::string& fen, + const std::vector& moves) = 0; + + // Must not block. + virtual void Go(const GoParams& params) = 0; + virtual void PonderHit() = 0; + // Must not block. + virtual void Stop() = 0; +}; + +class EngineLoop : public UciLoop { + public: + EngineLoop(std::unique_ptr options, + std::function( + std::unique_ptr uci_responder, + const OptionsDict& options)> + engine_factory); + + void RunLoop() override; + void CmdUci() override; + void CmdIsReady() override; + void CmdSetOption(const std::string& name, const std::string& value, + const std::string& context) override; + void CmdUciNewGame() override; + void CmdPosition(const std::string& position, + const std::vector& moves) override; + void CmdGo(const GoParams& params) override; + void CmdPonderHit() override; + void CmdStop() override; + + private: + std::unique_ptr options_; + std::unique_ptr engine_; +}; + +} // namespace lczero \ No newline at end of file diff --git a/src/main.cc b/src/main.cc index f573e4974f..01c182e4ee 100644 --- a/src/main.cc +++ b/src/main.cc @@ -26,7 +26,7 @@ */ #include "chess/board.h" -#include "engine.h" +#include "engine_classic.h" #include "selfplay/loop.h" #include "tools/backendbench.h" #include "tools/benchmark.h" @@ -84,7 +84,14 @@ int main(int argc, const char** argv) { // Consuming optional "uci" mode. CommandLine::ConsumeCommand("uci"); // Ordinary UCI engine. - EngineLoop loop; + auto options_parser = std::make_unique(); + EngineClassic::PopulateOptions(options_parser.get()); + EngineLoop loop(std::move(options_parser), + [](std::unique_ptr uci_responder, + const OptionsDict& options) { + return std::make_unique( + std::move(uci_responder), options); + }); loop.RunLoop(); } } catch (std::exception& e) { From 82dd466c5468375e86fd7062ba26c29aaa0dfaeb Mon Sep 17 00:00:00 2001 From: Alexander Lyashuk Date: Sat, 28 Dec 2024 23:51:15 +0100 Subject: [PATCH 011/212] Minor changes to proto generation (#2025) --- scripts/compile_proto.py | 73 +++++++++++++++++++++++++++++++++------- 1 file changed, 60 insertions(+), 13 deletions(-) diff --git a/scripts/compile_proto.py b/scripts/compile_proto.py index cb7d0450b2..bbbdfb7342 100755 --- a/scripts/compile_proto.py +++ b/scripts/compile_proto.py @@ -60,24 +60,26 @@ TYPES = {**VARINT_TYPES, **FIXED32_TYPES, **FIXED64_TYPES, **BYTES_TYPES} RESERVED_WORDS = [ - 'syntax', - 'package', + 'enum', 'message', 'optional', - 'required', + 'package', 'repeated', - 'enum', + 'required', + 'reserved', + 'syntax', + 'to', ] + list(TYPES.keys()) GRAMMAR = ([(r'%s\b' % x, x) - for x in RESERVED_WORDS] + [('\\' + x, x) for x in '=;{}.'] + [ + for x in RESERVED_WORDS] + [('\\' + x, x) for x in '=;{}.,'] + [ (r'/\*.*?\*/', None), # /* Comment */ (r'//.*?$', None), # // Comment (r'\s+', None), # Whitespace (r'$', 'EOF'), (r'"((?:[^"\\]|\\.)*)"', 'string'), (r'\d+', 'number'), - (r'\w+', 'identifier'), + (r'(\w+)', 'identifier'), ]) @@ -103,7 +105,7 @@ def Consume(self, expected_token, value=None, group=0): ''' token, match = self.Pick() if expected_token != token: - self.Error('Expected token type [%s]' % expected_token) + self.Error(f'Expected token type [{expected_token}], got [{token}]') if value is not None and value != match.group(group): self.Error('Expected value [%s]' % value) self.cur_offset = match.span()[1] @@ -128,7 +130,8 @@ def NextTokenOrWhitespace(self): m = r.match(self.text, self.cur_offset) if m: return (token, m) - self.Error('Unexpected token') + token_snippet = self.text[self.cur_offset:self.cur_offset + 10] + self.Error(f'Unparseable token [{token_snippet}...]') def Error(self, text): '''Throws an error with context in the file read.''' @@ -318,7 +321,7 @@ def GenerateCaseClause(self, w): w.Write('case %d: %s; break;' % (self.number, self.GetParser())) def GenerateClear(self, w): - name = self.name.group(0) + name = self.name.group(0) if self.category == 'repeated': w.Write('%s_.clear();' % name) else: @@ -392,8 +395,9 @@ def GenerateFunctionDeclarations(self, w): w.Write("bool has_%s() const;" % (name)) if self.type.IsMessage(): w.Write("const %s& %s() const;" % (cpp_type, name)) - w.Write("%s* mutable_%s();" % (cpp_type, name)) - else: + if self.type.IsMessage() or self.type.IsBytesType(): + w.Write("%s* mutable_%s();" % (var_cpp_type, name)) + if not self.type.IsMessage(): w.Write("%s %s() const;" % (cpp_type, name)) w.Write("void set_%s(%s val);" % (name, cpp_type)) @@ -436,14 +440,15 @@ def GenerateFunctionDefinitions(self, w, class_name): if self.type.IsMessage(): w.Write("inline const %s& %s::%s() const { return %s_; }" % (cpp_type, class_name, name, name)) + if self.type.IsMessage() or self.type.IsBytesType(): w.Write("inline %s* %s::mutable_%s() {" % - (cpp_type, class_name, name)) + (var_cpp_type, class_name, name)) w.Indent() w.Write('has_%s_ = true;' % (name)) w.Write('return &%s_;' % name) w.Unindent() w.Write("}") - else: + if not self.type.IsMessage(): w.Write("inline %s %s::%s() const { return %s_; }" % (cpp_type, class_name, name, name)) w.Write("inline void %s::set_%s(%s val) {" % @@ -551,10 +556,36 @@ def GenerateUsingDirectives(self, w): w.Write('}') +def ParseReservedFields(lexer): + res = set() + lexer.Consume('reserved') + while True: + token, match = lexer.Pick() + if token == 'number': + num = int(lexer.Consume('number').group(0)) + if lexer.Pick()[0] == 'to': + lexer.Consume('to') + end = int(lexer.Consume('number').group(0)) + res.add(range(num, end + 1)) + else: + res.add(num) + elif token in ['identifier', 'string']: + res.add(lexer.Consume(token).group(1)) + else: + lexer.Error('Expected number or identifier') + token, _ = lexer.Pick() + if token == ';': + lexer.Consume(';') + break + lexer.Consume(',') + return res + + class ProtoMessageParser: def __init__(self, lexer, type_stack, scope): type_stack[0].append(self) + self.reserved = set() self.types = [] self.fields = [] self.scope = scope[:] @@ -573,9 +604,12 @@ def __init__(self, lexer, type_stack, scope): elif token in ['repeated', 'optional', 'required']: self.fields.append( ProtoFieldParser(lexer, [self.types, *type_stack])) + elif token == 'reserved': + self.reserved.update(ParseReservedFields(lexer)) else: lexer.Error('Expected field or type') lexer.Consume('}') + self.CheckReserved() def GetName(self): return self.name @@ -597,6 +631,19 @@ def GetFieldsGruppedByWireType(self): for x in self.fields: type_to_fields.setdefault(x.type.GetWireType(), []).append(x) return type_to_fields + + def CheckReserved(self): + for r in self.reserved: + if isinstance(r, int): + if any(x.number == r for x in self.fields): + raise ValueError(f'Field number [{r}] is reserved.') + elif isinstance(r, range): + if any(x.number in r for x in self.fields): + raise ValueError(f'Field range [{r.start} to {r.stop-1}] ' + 'is reserved.') + else: + if any(x.name.group(0) == r for x in self.fields): + raise ValueError(f'Field name [{r}] is reserved.') def ResolveForwardDeclarations(self, type_stack): type_stack.append(self.types) From 0ba125d21b2c2e12fb3db9b7861be1b1dfe8117b Mon Sep 17 00:00:00 2001 From: Alexander Lyashuk Date: Sun, 29 Dec 2024 15:09:01 +0100 Subject: [PATCH 012/212] Move src/mcts/ to src/search/classic/, and to classic namespace (#2094) --- meson.build | 22 +++---- src/engine_classic.cc | 30 +++++----- src/engine_classic.h | 8 +-- src/{mcts => search/classic}/node.cc | 4 +- src/{mcts => search/classic}/node.h | 2 + src/{mcts => search/classic}/params.cc | 4 +- src/{mcts => search/classic}/params.h | 2 + src/{mcts => search/classic}/search.cc | 6 +- src/{mcts => search/classic}/search.h | 8 ++- .../classic}/stoppers/alphazero.cc | 4 +- .../classic}/stoppers/alphazero.h | 2 + .../classic}/stoppers/common.cc | 4 +- .../classic}/stoppers/common.h | 4 +- .../classic}/stoppers/factory.cc | 14 +++-- .../classic}/stoppers/factory.h | 6 +- .../classic}/stoppers/legacy.cc | 6 +- .../classic}/stoppers/legacy.h | 4 +- .../classic}/stoppers/simple.cc | 4 +- .../classic}/stoppers/simple.h | 2 + .../classic}/stoppers/smooth.cc | 8 ++- .../classic}/stoppers/smooth.h | 4 +- .../classic}/stoppers/stoppers.cc | 6 +- .../classic}/stoppers/stoppers.h | 6 +- .../classic}/stoppers/timemgr.cc | 6 +- .../classic}/stoppers/timemgr.h | 4 +- src/selfplay/game.cc | 36 +++++------ src/selfplay/game.h | 10 ++-- src/selfplay/multigame.cc | 10 ++-- src/selfplay/multigame.h | 8 +-- src/selfplay/tournament.cc | 42 ++++++------- src/tools/backendbench.cc | 60 +++++++++---------- src/tools/benchmark.cc | 24 ++++---- src/tools/benchmark.h | 2 +- src/trainingdata/trainingdata.cc | 12 ++-- src/trainingdata/trainingdata.h | 11 ++-- 35 files changed, 219 insertions(+), 166 deletions(-) rename src/{mcts => search/classic}/node.cc (99%) rename src/{mcts => search/classic}/node.h (99%) rename src/{mcts => search/classic}/params.cc (99%) rename src/{mcts => search/classic}/params.h (99%) rename src/{mcts => search/classic}/search.cc (99%) rename src/{mcts => search/classic}/search.h (99%) rename src/{mcts => search/classic}/stoppers/alphazero.cc (96%) rename src/{mcts => search/classic}/stoppers/alphazero.h (96%) rename src/{mcts => search/classic}/stoppers/common.cc (98%) rename src/{mcts => search/classic}/stoppers/common.h (95%) rename src/{mcts => search/classic}/stoppers/factory.cc (92%) rename src/{mcts => search/classic}/stoppers/factory.h (92%) rename src/{mcts => search/classic}/stoppers/legacy.cc (98%) rename src/{mcts => search/classic}/stoppers/legacy.h (94%) rename src/{mcts => search/classic}/stoppers/simple.cc (98%) rename src/{mcts => search/classic}/stoppers/simple.h (96%) rename src/{mcts => search/classic}/stoppers/smooth.cc (99%) rename src/{mcts => search/classic}/stoppers/smooth.h (94%) rename src/{mcts => search/classic}/stoppers/stoppers.cc (98%) rename src/{mcts => search/classic}/stoppers/stoppers.h (97%) rename src/{mcts => search/classic}/stoppers/timemgr.cc (94%) rename src/{mcts => search/classic}/stoppers/timemgr.h (98%) diff --git a/meson.build b/meson.build index 85ab10f031..a749d884c9 100644 --- a/meson.build +++ b/meson.build @@ -161,9 +161,9 @@ common_files += [ 'src/chess/board.cc', 'src/chess/position.cc', 'src/chess/uciloop.cc', - 'src/mcts/node.cc', 'src/neural/decoder.cc', 'src/neural/encoder.cc', + 'src/search/classic/node.cc', 'src/syzygy/syzygy.cc', 'src/trainingdata/reader.cc', 'src/trainingdata/trainingdata.cc', @@ -183,16 +183,6 @@ common_files += [ files += [ 'src/engine_classic.cc', 'src/engine_loop.cc', - 'src/mcts/params.cc', - 'src/mcts/search.cc', - 'src/mcts/stoppers/alphazero.cc', - 'src/mcts/stoppers/common.cc', - 'src/mcts/stoppers/factory.cc', - 'src/mcts/stoppers/legacy.cc', - 'src/mcts/stoppers/simple.cc', - 'src/mcts/stoppers/smooth.cc', - 'src/mcts/stoppers/stoppers.cc', - 'src/mcts/stoppers/timemgr.cc', 'src/neural/backends/network_check.cc', 'src/neural/backends/network_demux.cc', 'src/neural/backends/network_mux.cc', @@ -211,6 +201,16 @@ files += [ 'src/neural/xla/onnx2hlo.cc', 'src/neural/xla/print_hlo.cc', 'src/neural/xla/xla_tensor.cc', + 'src/search/classic/params.cc', + 'src/search/classic/search.cc', + 'src/search/classic/stoppers/alphazero.cc', + 'src/search/classic/stoppers/common.cc', + 'src/search/classic/stoppers/factory.cc', + 'src/search/classic/stoppers/legacy.cc', + 'src/search/classic/stoppers/simple.cc', + 'src/search/classic/stoppers/smooth.cc', + 'src/search/classic/stoppers/stoppers.cc', + 'src/search/classic/stoppers/timemgr.cc', 'src/selfplay/game.cc', 'src/selfplay/loop.cc', 'src/selfplay/multigame.cc', diff --git a/src/engine_classic.cc b/src/engine_classic.cc index 0556467921..e6dc0c9038 100644 --- a/src/engine_classic.cc +++ b/src/engine_classic.cc @@ -31,8 +31,8 @@ #include #include -#include "mcts/search.h" -#include "mcts/stoppers/factory.h" +#include "search/classic/search.h" +#include "search/classic/stoppers/factory.h" #include "utils/commandline.h" #include "utils/configfile.h" #include "utils/logging.h" @@ -98,16 +98,16 @@ void EngineClassic::PopulateOptions(OptionsParser* options) { CommandLine::BinaryName().find("simple") != std::string::npos; NetworkFactory::PopulateOptions(options); options->Add(kThreadsOptionId, 0, 128) = 0; - options->Add(kNNCacheSizeId, 0, 999999999) = 2000000; - SearchParams::Populate(options); + options->Add(classic::kNNCacheSizeId, 0, 999999999) = 2000000; + classic::SearchParams::Populate(options); ConfigFile::PopulateOptions(options); if (is_simple) { options->HideAllOptions(); options->UnhideOption(kThreadsOptionId); options->UnhideOption(NetworkFactory::kWeightsId); - options->UnhideOption(SearchParams::kContemptId); - options->UnhideOption(SearchParams::kMultiPvId); + options->UnhideOption(classic::SearchParams::kContemptId); + options->UnhideOption(classic::SearchParams::kMultiPvId); } options->Add(kSyzygyTablebaseId); // Add "Ponder" option to signal to GUIs that we support pondering. @@ -117,8 +117,9 @@ void EngineClassic::PopulateOptions(OptionsParser* options) { options->Add(kShowWDL) = false; options->Add(kShowMovesleft) = false; - PopulateTimeManagementOptions(is_simple ? RunType::kSimpleUci : RunType::kUci, - options); + PopulateTimeManagementOptions( + is_simple ? classic::RunType::kSimpleUci : classic::RunType::kUci, + options); options->Add(kStrictUciTiming) = false; options->HideOption(kStrictUciTiming); @@ -160,7 +161,7 @@ void EngineClassic::UpdateFromUciOptions() { } // Cache size. - cache_.SetCapacity(options_.Get(kNNCacheSizeId)); + cache_.SetCapacity(options_.Get(classic::kNNCacheSizeId)); // Check whether we can update the move timer in "Go". strict_uci_timing_ = options_.Get(kStrictUciTiming); @@ -218,7 +219,7 @@ void EngineClassic::SetupPosition(const std::string& fen, UpdateFromUciOptions(); - if (!tree_) tree_ = std::make_unique(); + if (!tree_) tree_ = std::make_unique(); std::vector moves; for (const auto& move : moves_str) moves.emplace_back(move); @@ -227,7 +228,7 @@ void EngineClassic::SetupPosition(const std::string& fen, } void EngineClassic::CreateFreshTimeManager() { - time_manager_ = MakeTimeManager(options_); + time_manager_ = classic::MakeTimeManager(options_); } namespace { @@ -265,7 +266,8 @@ class PonderResponseTransformer : public TransformingUciResponder { std::string ponder_move_; }; -void ValueOnlyGo(NodeTree* tree, Network* network, const OptionsDict& options, +void ValueOnlyGo(classic::NodeTree* tree, Network* network, + const OptionsDict& options, std::unique_ptr responder) { auto input_format = network->GetCapabilities().input_format; @@ -284,7 +286,7 @@ void ValueOnlyGo(NodeTree* tree, Network* network, const OptionsDict& options, } std::vector comp_q; - int batch_size = options.Get(SearchParams::kMiniBatchSizeId); + int batch_size = options.Get(classic::SearchParams::kMiniBatchSizeId); if (batch_size == 0) batch_size = network->GetMiniBatchSize(); for (size_t i = 0; i < planes.size(); i += batch_size) { @@ -383,7 +385,7 @@ void EngineClassic::Go(const GoParams& params) { } auto stopper = time_manager_->GetStopper(params, *tree_.get()); - search_ = std::make_unique( + search_ = std::make_unique( *tree_, network_.get(), std::move(responder), StringsToMovelist(params.searchmoves, tree_->HeadPosition().GetBoard()), *move_start_time_, std::move(stopper), params.infinite, params.ponder, diff --git a/src/engine_classic.h b/src/engine_classic.h index 104f8ee66b..e74b6172c8 100644 --- a/src/engine_classic.h +++ b/src/engine_classic.h @@ -30,10 +30,10 @@ #include #include "engine_loop.h" -#include "mcts/search.h" #include "neural/cache.h" #include "neural/factory.h" #include "neural/network.h" +#include "search/classic/search.h" #include "syzygy/syzygy.h" #include "utils/mutex.h" @@ -91,9 +91,9 @@ class EngineClassic : public EngineControllerBase { RpSharedMutex busy_mutex_; using SharedLock = std::shared_lock; - std::unique_ptr time_manager_; - std::unique_ptr search_; - std::unique_ptr tree_; + std::unique_ptr time_manager_; + std::unique_ptr search_; + std::unique_ptr tree_; std::unique_ptr syzygy_tb_; std::unique_ptr network_; NNCache cache_; diff --git a/src/mcts/node.cc b/src/search/classic/node.cc similarity index 99% rename from src/mcts/node.cc rename to src/search/classic/node.cc index c3ec4b010e..f7fa034432 100644 --- a/src/mcts/node.cc +++ b/src/search/classic/node.cc @@ -25,7 +25,7 @@ Program grant you additional permission to convey the resulting work. */ -#include "mcts/node.h" +#include "search/classic/node.h" #include #include @@ -41,6 +41,7 @@ #include "utils/hashcat.h" namespace lczero { +namespace classic { ///////////////////////////////////////////////////////////////////////// // Node garbage collector @@ -539,4 +540,5 @@ void NodeTree::DeallocateTree() { current_head_ = nullptr; } +} // namespace classic } // namespace lczero diff --git a/src/mcts/node.h b/src/search/classic/node.h similarity index 99% rename from src/mcts/node.h rename to src/search/classic/node.h index 2982de24da..3bd6cc9b1a 100644 --- a/src/mcts/node.h +++ b/src/search/classic/node.h @@ -42,6 +42,7 @@ #include "utils/mutex.h" namespace lczero { +namespace classic { // Children of a node are stored the following way: // * Edges and Nodes edges point to are stored separately. @@ -659,4 +660,5 @@ class NodeTree { PositionHistory history_; }; +} // namespace classic } // namespace lczero diff --git a/src/mcts/params.cc b/src/search/classic/params.cc similarity index 99% rename from src/mcts/params.cc rename to src/search/classic/params.cc index 22310477e1..27c01d8ebb 100644 --- a/src/mcts/params.cc +++ b/src/search/classic/params.cc @@ -25,7 +25,7 @@ Program grant you additional permission to convey the resulting work. */ -#include "mcts/params.h" +#include "search/classic/params.h" #include #include @@ -46,6 +46,7 @@ #endif namespace lczero { +namespace classic { namespace { FillEmptyHistory EncodeHistoryFill(std::string history_fill) { @@ -696,4 +697,5 @@ SearchParams::SearchParams(const OptionsDict& options) options.Get(kMaxCollisionVisitsScalingPowerId)), kSearchSpinBackoff(options_.Get(kSearchSpinBackoffId)) {} +} // namespace classic } // namespace lczero diff --git a/src/mcts/params.h b/src/search/classic/params.h similarity index 99% rename from src/mcts/params.h rename to src/search/classic/params.h index df02f124fb..cc5a0322d3 100644 --- a/src/mcts/params.h +++ b/src/search/classic/params.h @@ -32,6 +32,7 @@ #include "utils/optionsparser.h" namespace lczero { +namespace classic { enum class ContemptMode { PLAY, WHITE, BLACK, NONE }; @@ -295,4 +296,5 @@ class SearchParams { const bool kSearchSpinBackoff; }; +} // namespace classic } // namespace lczero diff --git a/src/mcts/search.cc b/src/search/classic/search.cc similarity index 99% rename from src/mcts/search.cc rename to src/search/classic/search.cc index b3326a7661..b06f13f20d 100644 --- a/src/mcts/search.cc +++ b/src/search/classic/search.cc @@ -25,7 +25,7 @@ Program grant you additional permission to convey the resulting work. */ -#include "mcts/search.h" +#include "search/classic/search.h" #include #include @@ -37,7 +37,7 @@ #include #include -#include "mcts/node.h" +#include "search/classic/node.h" #include "neural/cache.h" #include "neural/encoder.h" #include "utils/fastmath.h" @@ -45,6 +45,7 @@ #include "utils/spinhelper.h" namespace lczero { +namespace classic { namespace { // Maximum delay between outputting "uci info" when nothing interesting happens. @@ -2466,4 +2467,5 @@ void SearchWorker::UpdateCounters() { } } +} // namespace classic } // namespace lczero diff --git a/src/mcts/search.h b/src/search/classic/search.h similarity index 99% rename from src/mcts/search.h rename to src/search/classic/search.h index c2ff2aa116..4699516a39 100644 --- a/src/mcts/search.h +++ b/src/search/classic/search.h @@ -36,9 +36,9 @@ #include "chess/callbacks.h" #include "chess/uciloop.h" -#include "mcts/node.h" -#include "mcts/params.h" -#include "mcts/stoppers/timemgr.h" +#include "search/classic/node.h" +#include "search/classic/params.h" +#include "search/classic/stoppers/timemgr.h" #include "neural/cache.h" #include "neural/network.h" #include "syzygy/syzygy.h" @@ -46,6 +46,7 @@ #include "utils/mutex.h" namespace lczero { +namespace classic { class Search { public: @@ -497,4 +498,5 @@ class SearchWorker { bool exiting_ = false; }; +} // namespace classic } // namespace lczero diff --git a/src/mcts/stoppers/alphazero.cc b/src/search/classic/stoppers/alphazero.cc similarity index 96% rename from src/mcts/stoppers/alphazero.cc rename to src/search/classic/stoppers/alphazero.cc index 84e04c0e2a..779e8688c0 100644 --- a/src/mcts/stoppers/alphazero.cc +++ b/src/search/classic/stoppers/alphazero.cc @@ -25,9 +25,10 @@ Program grant you additional permission to convey the resulting work. */ -#include "mcts/stoppers/stoppers.h" +#include "search/classic/stoppers/stoppers.h" namespace lczero { +namespace classic { namespace { @@ -73,4 +74,5 @@ std::unique_ptr MakeAlphazeroTimeManager( int64_t move_overhead, const OptionsDict& params) { return std::make_unique(move_overhead, params); } +} // namespace classic } // namespace lczero diff --git a/src/mcts/stoppers/alphazero.h b/src/search/classic/stoppers/alphazero.h similarity index 96% rename from src/mcts/stoppers/alphazero.h rename to src/search/classic/stoppers/alphazero.h index f342cbe0d8..77404a0673 100644 --- a/src/mcts/stoppers/alphazero.h +++ b/src/search/classic/stoppers/alphazero.h @@ -30,8 +30,10 @@ #include "utils/optionsdict.h" namespace lczero { +namespace classic { std::unique_ptr MakeAlphazeroTimeManager( int64_t move_overhead, const OptionsDict& params); +} // namespace classic } // namespace lczero \ No newline at end of file diff --git a/src/mcts/stoppers/common.cc b/src/search/classic/stoppers/common.cc similarity index 98% rename from src/mcts/stoppers/common.cc rename to src/search/classic/stoppers/common.cc index 2fd95f578e..ac8efae588 100644 --- a/src/mcts/stoppers/common.cc +++ b/src/search/classic/stoppers/common.cc @@ -25,9 +25,10 @@ Program grant you additional permission to convey the resulting work. */ -#include "src/mcts/stoppers/common.h" +#include "search/classic/stoppers/common.h" namespace lczero { +namespace classic { const OptionId kNNCacheSizeId{ "nncache", "NNCacheSize", @@ -190,4 +191,5 @@ std::unique_ptr MakeCommonTimeManager( move_overhead); } +} // namespace classic } // namespace lczero diff --git a/src/mcts/stoppers/common.h b/src/search/classic/stoppers/common.h similarity index 95% rename from src/mcts/stoppers/common.h rename to src/search/classic/stoppers/common.h index fe35115ef5..1be3571811 100644 --- a/src/mcts/stoppers/common.h +++ b/src/search/classic/stoppers/common.h @@ -27,11 +27,12 @@ #pragma once -#include "mcts/stoppers/stoppers.h" +#include "search/classic/stoppers/stoppers.h" #include "utils/optionsdict.h" #include "utils/optionsparser.h" namespace lczero { +namespace classic { enum class RunType { kUci, kSimpleUci, kSelfplay }; void PopulateCommonStopperOptions(RunType for_what, OptionsParser* options); @@ -48,4 +49,5 @@ std::unique_ptr MakeCommonTimeManager( std::unique_ptr child_manager, const OptionsDict& options, int64_t move_overhead); +} // namespace classic } // namespace lczero diff --git a/src/mcts/stoppers/factory.cc b/src/search/classic/stoppers/factory.cc similarity index 92% rename from src/mcts/stoppers/factory.cc rename to src/search/classic/stoppers/factory.cc index 3da29d1aa1..b6db77ea18 100644 --- a/src/mcts/stoppers/factory.cc +++ b/src/search/classic/stoppers/factory.cc @@ -25,19 +25,20 @@ Program grant you additional permission to convey the resulting work. */ -#include "mcts/stoppers/factory.h" +#include "search/classic/stoppers/factory.h" #include #include "factory.h" -#include "mcts/stoppers/alphazero.h" -#include "mcts/stoppers/legacy.h" -#include "mcts/stoppers/simple.h" -#include "mcts/stoppers/smooth.h" -#include "mcts/stoppers/stoppers.h" +#include "search/classic/stoppers/alphazero.h" +#include "search/classic/stoppers/legacy.h" +#include "search/classic/stoppers/simple.h" +#include "search/classic/stoppers/smooth.h" +#include "search/classic/stoppers/stoppers.h" #include "utils/exception.h" namespace lczero { +namespace classic { namespace { const OptionId kMoveOverheadId{ @@ -109,4 +110,5 @@ std::unique_ptr MakeTimeManager(const OptionsDict& options) { return MakeCommonTimeManager(std::move(time_manager), options, move_overhead); } +} // namespace classic } // namespace lczero diff --git a/src/mcts/stoppers/factory.h b/src/search/classic/stoppers/factory.h similarity index 92% rename from src/mcts/stoppers/factory.h rename to src/search/classic/stoppers/factory.h index a8b0c15c7e..6c5eba1c24 100644 --- a/src/mcts/stoppers/factory.h +++ b/src/search/classic/stoppers/factory.h @@ -27,12 +27,13 @@ #pragma once -#include "mcts/stoppers/common.h" -#include "mcts/stoppers/timemgr.h" +#include "search/classic/stoppers/common.h" +#include "search/classic/stoppers/timemgr.h" #include "utils/optionsdict.h" #include "utils/optionsparser.h" namespace lczero { +namespace classic { // Populates UCI/command line flags with time management options. void PopulateTimeManagementOptions(RunType for_what, OptionsParser* options); @@ -40,4 +41,5 @@ void PopulateTimeManagementOptions(RunType for_what, OptionsParser* options); // Creates a new time manager for a new search. std::unique_ptr MakeTimeManager(const OptionsDict& dict); +} // namespace classic } // namespace lczero diff --git a/src/mcts/stoppers/legacy.cc b/src/search/classic/stoppers/legacy.cc similarity index 98% rename from src/mcts/stoppers/legacy.cc rename to src/search/classic/stoppers/legacy.cc index 77bc712381..d23573adb1 100644 --- a/src/mcts/stoppers/legacy.cc +++ b/src/search/classic/stoppers/legacy.cc @@ -25,11 +25,12 @@ Program grant you additional permission to convey the resulting work. */ -#include "mcts/stoppers/legacy.h" +#include "search/classic/stoppers/legacy.h" -#include "mcts/stoppers/stoppers.h" +#include "search/classic/stoppers/stoppers.h" namespace lczero { +namespace classic { float ComputeEstimatedMovesToGo(int ply, float midpoint, float steepness) { // An analysis of chess games shows that the distribution of game lengths @@ -169,4 +170,5 @@ std::unique_ptr MakeLegacyTimeManager(int64_t move_overhead, const OptionsDict& params) { return std::make_unique(move_overhead, params); } +} // namespace classic } // namespace lczero diff --git a/src/mcts/stoppers/legacy.h b/src/search/classic/stoppers/legacy.h similarity index 94% rename from src/mcts/stoppers/legacy.h rename to src/search/classic/stoppers/legacy.h index 82cbf3f85b..865ecd42ba 100644 --- a/src/mcts/stoppers/legacy.h +++ b/src/search/classic/stoppers/legacy.h @@ -27,14 +27,16 @@ #pragma once -#include "mcts/stoppers/timemgr.h" +#include "search/classic/stoppers/timemgr.h" #include "utils/optionsdict.h" namespace lczero { +namespace classic { float ComputeEstimatedMovesToGo(int ply, float midpoint, float steepness); std::unique_ptr MakeLegacyTimeManager(int64_t move_overhead, const OptionsDict& params); +} // namespace classic } // namespace lczero diff --git a/src/mcts/stoppers/simple.cc b/src/search/classic/stoppers/simple.cc similarity index 98% rename from src/mcts/stoppers/simple.cc rename to src/search/classic/stoppers/simple.cc index f976142f7c..51ac6f350a 100644 --- a/src/mcts/stoppers/simple.cc +++ b/src/search/classic/stoppers/simple.cc @@ -25,9 +25,10 @@ Program grant you additional permission to convey the resulting work. */ -#include "mcts/stoppers/stoppers.h" +#include "search/classic/stoppers/stoppers.h" namespace lczero { +namespace classic { namespace { @@ -126,4 +127,5 @@ std::unique_ptr MakeSimpleTimeManager(int64_t move_overhead, const OptionsDict& params) { return std::make_unique(move_overhead, params); } +} // namespace classic } // namespace lczero diff --git a/src/mcts/stoppers/simple.h b/src/search/classic/stoppers/simple.h similarity index 96% rename from src/mcts/stoppers/simple.h rename to src/search/classic/stoppers/simple.h index b7b6f3a349..9429b45f70 100644 --- a/src/mcts/stoppers/simple.h +++ b/src/search/classic/stoppers/simple.h @@ -30,8 +30,10 @@ #include "utils/optionsdict.h" namespace lczero { +namespace classic { std::unique_ptr MakeSimpleTimeManager( int64_t move_overhead, const OptionsDict& params); +} // namespace classic } // namespace lczero diff --git a/src/mcts/stoppers/smooth.cc b/src/search/classic/stoppers/smooth.cc similarity index 99% rename from src/mcts/stoppers/smooth.cc rename to src/search/classic/stoppers/smooth.cc index 2a1a196247..d82802cf1b 100644 --- a/src/mcts/stoppers/smooth.cc +++ b/src/search/classic/stoppers/smooth.cc @@ -25,17 +25,18 @@ Program grant you additional permission to convey the resulting work. */ -#include "mcts/stoppers/smooth.h" +#include "search/classic/stoppers/smooth.h" #include #include #include -#include "mcts/stoppers/legacy.h" -#include "mcts/stoppers/stoppers.h" +#include "search/classic/stoppers/legacy.h" +#include "search/classic/stoppers/stoppers.h" #include "utils/mutex.h" namespace lczero { +namespace classic { namespace { class Params { @@ -636,4 +637,5 @@ std::unique_ptr MakeSmoothTimeManager(int64_t move_overhead, return std::make_unique(move_overhead, params); } +} // namespace classic } // namespace lczero diff --git a/src/mcts/stoppers/smooth.h b/src/search/classic/stoppers/smooth.h similarity index 94% rename from src/mcts/stoppers/smooth.h rename to src/search/classic/stoppers/smooth.h index 2e68e83667..da81a9a8b0 100644 --- a/src/mcts/stoppers/smooth.h +++ b/src/search/classic/stoppers/smooth.h @@ -27,12 +27,14 @@ #pragma once -#include "mcts/stoppers/timemgr.h" +#include "search/classic/stoppers/timemgr.h" #include "utils/optionsdict.h" namespace lczero { +namespace classic { std::unique_ptr MakeSmoothTimeManager(int64_t move_overhead, const OptionsDict& params); +} // namespace classic } // namespace lczero \ No newline at end of file diff --git a/src/mcts/stoppers/stoppers.cc b/src/search/classic/stoppers/stoppers.cc similarity index 98% rename from src/mcts/stoppers/stoppers.cc rename to src/search/classic/stoppers/stoppers.cc index 201faa23b8..56b3cafb8e 100644 --- a/src/mcts/stoppers/stoppers.cc +++ b/src/search/classic/stoppers/stoppers.cc @@ -25,12 +25,13 @@ Program grant you additional permission to convey the resulting work. */ -#include "mcts/stoppers/stoppers.h" +#include "search/classic/stoppers/stoppers.h" -#include "mcts/node.h" +#include "search/classic/node.h" #include "neural/cache.h" namespace lczero { +namespace classic { /////////////////////////// // ChainedSearchStopper @@ -267,4 +268,5 @@ bool SmartPruningStopper::ShouldStop(const IterationStats& stats, return false; } +} // namespace classic } // namespace lczero diff --git a/src/mcts/stoppers/stoppers.h b/src/search/classic/stoppers/stoppers.h similarity index 97% rename from src/mcts/stoppers/stoppers.h rename to src/search/classic/stoppers/stoppers.h index f813c4daf1..7c3ccf4eec 100644 --- a/src/mcts/stoppers/stoppers.h +++ b/src/search/classic/stoppers/stoppers.h @@ -30,10 +30,11 @@ #include #include -#include "mcts/node.h" -#include "mcts/stoppers/timemgr.h" +#include "search/classic/node.h" +#include "search/classic/stoppers/timemgr.h" namespace lczero { +namespace classic { // Combines multiple stoppers into one. class ChainedSearchStopper : public SearchStopper { @@ -151,4 +152,5 @@ class SmartPruningStopper : public SearchStopper { std::optional first_eval_time_ GUARDED_BY(mutex_); }; +} // namespace classic } // namespace lczero diff --git a/src/mcts/stoppers/timemgr.cc b/src/search/classic/stoppers/timemgr.cc similarity index 94% rename from src/mcts/stoppers/timemgr.cc rename to src/search/classic/stoppers/timemgr.cc index cd75658c72..41cd096dd5 100644 --- a/src/mcts/stoppers/timemgr.cc +++ b/src/search/classic/stoppers/timemgr.cc @@ -25,11 +25,12 @@ Program grant you additional permission to convey the resulting work. */ -#include "mcts/stoppers/timemgr.h" +#include "search/classic/stoppers/timemgr.h" -#include "mcts/stoppers/stoppers.h" +#include "search/classic/stoppers/stoppers.h" namespace lczero { +namespace classic { StoppersHints::StoppersHints() { Reset(); } @@ -64,4 +65,5 @@ void StoppersHints::Reset() { estimated_nps_.reset(); } +} // namespace classic } // namespace lczero \ No newline at end of file diff --git a/src/mcts/stoppers/timemgr.h b/src/search/classic/stoppers/timemgr.h similarity index 98% rename from src/mcts/stoppers/timemgr.h rename to src/search/classic/stoppers/timemgr.h index 60a1097863..a390c1df2a 100644 --- a/src/mcts/stoppers/timemgr.h +++ b/src/search/classic/stoppers/timemgr.h @@ -33,10 +33,11 @@ #include #include "chess/uciloop.h" -#include "mcts/node.h" +#include "search/classic/node.h" #include "utils/optionsdict.h" namespace lczero { +namespace classic { // Various statistics that search sends to stoppers for their stopping decision. // It is expected that this structure will grow. @@ -108,4 +109,5 @@ class TimeManager { const NodeTree& tree) = 0; }; +} // namespace classic } // namespace lczero diff --git a/src/selfplay/game.cc b/src/selfplay/game.cc index 68554c2fc3..eefb274f0b 100644 --- a/src/selfplay/game.cc +++ b/src/selfplay/game.cc @@ -29,8 +29,8 @@ #include -#include "mcts/stoppers/common.h" -#include "mcts/stoppers/factory.h" +#include "search/classic/stoppers/common.h" +#include "search/classic/stoppers/factory.h" #include "utils/random.h" namespace lczero { @@ -74,7 +74,7 @@ void SelfPlayGame::PopulateUciParams(OptionsParser* options) { options->Add(kResignEarliestMoveId, 0, 1000) = 0; options->Add(kMinimumAllowedVistsId, 0, 1000000) = 0; options->Add(kUciChess960) = false; - PopulateTimeManagementOptions(RunType::kSelfplay, options); + PopulateTimeManagementOptions(classic::RunType::kSelfplay, options); options->Add(kSyzygyTablebaseId); options->Add(kOpeningStopProbId, 0.0f, 1.0f) = 0.0f; } @@ -84,17 +84,17 @@ SelfPlayGame::SelfPlayGame(PlayerOptions white, PlayerOptions black, : options_{white, black}, chess960_{white.uci_options->Get(kUciChess960) || black.uci_options->Get(kUciChess960)}, - training_data_(SearchParams(*white.uci_options).GetHistoryFill(), - SearchParams(*black.uci_options).GetHistoryFill(), + training_data_(classic::SearchParams(*white.uci_options).GetHistoryFill(), + classic::SearchParams(*black.uci_options).GetHistoryFill(), white.network->GetCapabilities().input_format) { orig_fen_ = opening.start_fen; - tree_[0] = std::make_shared(); + tree_[0] = std::make_shared(); tree_[0]->ResetToPosition(orig_fen_, {}); if (shared_tree) { tree_[1] = tree_[0]; } else { - tree_[1] = std::make_shared(); + tree_[1] = std::make_shared(); tree_[1]->ResetToPosition(orig_fen_, {}); } int ply = 0; @@ -166,7 +166,8 @@ void SelfPlayGame::Play(int white_threads, int black_threads, bool training, std::lock_guard lock(mutex_); if (abort_) break; auto stoppers = options_[idx].search_limits.MakeSearchStopper(); - PopulateIntrinsicStoppers(stoppers.get(), *options_[idx].uci_options); + classic::PopulateIntrinsicStoppers(stoppers.get(), + *options_[idx].uci_options); std::unique_ptr responder = std::make_unique( @@ -178,7 +179,7 @@ void SelfPlayGame::Play(int white_threads, int black_threads, bool training, std::move(responder), tree_[idx]->HeadPosition().GetBoard()); } - search_ = std::make_unique( + search_ = std::make_unique( *tree_[idx], options_[idx].network, std::move(responder), /* searchmoves */ MoveList(), std::chrono::steady_clock::now(), std::move(stoppers), /* infinite */ false, /* ponder */ false, @@ -238,7 +239,7 @@ void SelfPlayGame::Play(int white_threads, int black_threads, bool training, } auto node = tree_[idx]->GetCurrentHead(); - Eval played_eval = best_eval; + classic::Eval played_eval = best_eval; Move move; while (true) { move = search_->GetBestMove().first; @@ -310,7 +311,7 @@ void SelfPlayGame::Play(int white_threads, int black_threads, bool training, std::vector SelfPlayGame::GetMoves() const { std::vector moves; - for (Node* node = tree_[0]->GetCurrentHead(); + for (classic::Node* node = tree_[0]->GetCurrentHead(); node != tree_[0]->GetGameBeginNode(); node = node->GetParent()) { moves.push_back(node->GetParent()->GetEdgeToNode(node)->GetMove()); } @@ -355,18 +356,19 @@ void SelfPlayGame::WriteTrainingData(TrainingDataWriter* writer) const { training_data_.Write(writer, game_result_, adjudicated_); } -std::unique_ptr SelfPlayLimits::MakeSearchStopper() - const { - auto result = std::make_unique(); +std::unique_ptr +SelfPlayLimits::MakeSearchStopper() const { + auto result = std::make_unique(); // always set VisitsStopper to avoid exceeding the limit 4000000000, the // default value when visits = 0 - result->AddStopper(std::make_unique(visits, false)); + result->AddStopper(std::make_unique(visits, false)); if (playouts >= 0) { - result->AddStopper(std::make_unique(playouts, false)); + result->AddStopper( + std::make_unique(playouts, false)); } if (movetime >= 0) { - result->AddStopper(std::make_unique(movetime)); + result->AddStopper(std::make_unique(movetime)); } return result; } diff --git a/src/selfplay/game.h b/src/selfplay/game.h index 918c328ce1..c65be8fabe 100644 --- a/src/selfplay/game.h +++ b/src/selfplay/game.h @@ -30,10 +30,10 @@ #include "chess/pgn.h" #include "chess/position.h" #include "chess/uciloop.h" -#include "mcts/search.h" -#include "mcts/stoppers/stoppers.h" #include "neural/cache.h" #include "neural/network.h" +#include "search/classic/search.h" +#include "search/classic/stoppers/stoppers.h" #include "trainingdata/trainingdata.h" #include "utils/optionsparser.h" @@ -44,7 +44,7 @@ struct SelfPlayLimits { std::int64_t playouts = -1; std::int64_t movetime = -1; - std::unique_ptr MakeSearchStopper() const; + std::unique_ptr MakeSearchStopper() const; }; struct PlayerOptions { @@ -104,13 +104,13 @@ class SelfPlayGame { PlayerOptions options_[2]; // Node tree for player1 and player2. If the tree is shared between players, // tree_[0] == tree_[1]. - std::shared_ptr tree_[2]; + std::shared_ptr tree_[2]; std::string orig_fen_; int start_ply_; // Search that is currently in progress. Stored in members so that Abort() // can stop it. - std::unique_ptr search_; + std::unique_ptr search_; bool abort_ = false; GameResult game_result_ = GameResult::UNDECIDED; bool adjudicated_ = false; diff --git a/src/selfplay/multigame.cc b/src/selfplay/multigame.cc index 1214cc9039..31965f1191 100644 --- a/src/selfplay/multigame.cc +++ b/src/selfplay/multigame.cc @@ -37,7 +37,7 @@ class PolicyEvaluator : public Evaluator { transforms.clear(); comp_idx = 0; } - void Gather(NodeTree* tree) override { + void Gather(classic::NodeTree* tree) override { int transform; auto planes = EncodePositionForNN(input_format, tree->GetPositionHistory(), 8, @@ -46,7 +46,7 @@ class PolicyEvaluator : public Evaluator { comp->AddInput(std::move(planes)); } void Run() override { comp->ComputeBlocking(); } - void MakeBestMove(NodeTree* tree) override { + void MakeBestMove(classic::NodeTree* tree) override { Move best; float max_p = std::numeric_limits::lowest(); for (auto edge : tree->GetCurrentHead()->Edges()) { @@ -74,7 +74,7 @@ class ValueEvaluator : public Evaluator { input_format = player.network->GetCapabilities().input_format; comp_idx = 0; } - void Gather(NodeTree* tree) override { + void Gather(classic::NodeTree* tree) override { PositionHistory history = tree->GetPositionHistory(); for (auto edge : tree->GetCurrentHead()->Edges()) { history.Append(edge.GetMove()); @@ -88,7 +88,7 @@ class ValueEvaluator : public Evaluator { } } void Run() override { comp->ComputeBlocking(); } - void MakeBestMove(NodeTree* tree) override { + void MakeBestMove(classic::NodeTree* tree) override { Move best; float max_q = std::numeric_limits::lowest(); PositionHistory history = tree->GetPositionHistory(); @@ -134,7 +134,7 @@ MultiSelfPlayGames::MultiSelfPlayGames(PlayerOptions player1, : std::unique_ptr(std::make_unique()); trees_.reserve(openings.size()); for (auto opening : openings) { - trees_.push_back(std::make_shared()); + trees_.push_back(std::make_shared()); trees_.back()->ResetToPosition(opening.start_fen, {}); results_.push_back(GameResult::UNDECIDED); diff --git a/src/selfplay/multigame.h b/src/selfplay/multigame.h index 122eb71bf5..ace4b2dcb4 100644 --- a/src/selfplay/multigame.h +++ b/src/selfplay/multigame.h @@ -37,11 +37,11 @@ class Evaluator { // Run before each batch before any Gather. virtual void Reset(const PlayerOptions& player) = 0; // Run for each tree. - virtual void Gather(NodeTree* tree) = 0; + virtual void Gather(classic::NodeTree* tree) = 0; // Run once between Gather and Move. virtual void Run() = 0; // Run for each tree in the same order as Gather. - virtual void MakeBestMove(NodeTree* tree) = 0; + virtual void MakeBestMove(classic::NodeTree* tree) = 0; }; // Plays a bunch of games vs itself. @@ -63,7 +63,7 @@ class MultiSelfPlayGames { std::vector GetMoves(int index) const { std::vector moves; bool flip = !trees_[index]->IsBlackToMove(); - for (Node* node = trees_[index]->GetCurrentHead(); + for (classic::Node* node = trees_[index]->GetCurrentHead(); node != trees_[index]->GetGameBeginNode(); node = node->GetParent()) { moves.push_back(node->GetParent()->GetEdgeToNode(node)->GetMove(flip)); flip = !flip; @@ -77,7 +77,7 @@ class MultiSelfPlayGames { PlayerOptions options_[2]; // Node tree for player1 and player2. If the tree is shared between players, // tree_[0] == tree_[1]. - std::vector> trees_; + std::vector> trees_; std::vector results_; bool abort_ = false; std::mutex mutex_; diff --git a/src/selfplay/tournament.cc b/src/selfplay/tournament.cc index 993e449a23..409d4d3681 100644 --- a/src/selfplay/tournament.cc +++ b/src/selfplay/tournament.cc @@ -30,9 +30,9 @@ #include #include "chess/pgn.h" -#include "mcts/search.h" -#include "mcts/stoppers/factory.h" #include "neural/factory.h" +#include "search/classic/search.h" +#include "search/classic/stoppers/factory.h" #include "selfplay/game.h" #include "selfplay/multigame.h" #include "utils/optionsparser.h" @@ -112,8 +112,8 @@ void SelfPlayTournament::PopulateOptions(OptionsParser* options) { NetworkFactory::PopulateOptions(options); options->Add(kThreadsId, 1, 8) = 1; - options->Add(kNNCacheSizeId, 0, 999999999) = 2000000; - SearchParams::Populate(options); + options->Add(classic::kNNCacheSizeId, 0, 999999999) = 2000000; + classic::SearchParams::Populate(options); options->Add(kShareTreesId) = true; options->Add(kTotalGamesId, -2, 999999) = -1; @@ -139,22 +139,22 @@ void SelfPlayTournament::PopulateOptions(OptionsParser* options) { SelfPlayGame::PopulateUciParams(options); auto defaults = options->GetMutableDefaultsOptions(); - defaults->Set(SearchParams::kMiniBatchSizeId, 32); - defaults->Set(SearchParams::kCpuctId, 1.2f); - defaults->Set(SearchParams::kCpuctFactorId, 0.0f); - defaults->Set(SearchParams::kPolicySoftmaxTempId, 1.0f); - defaults->Set(SearchParams::kMaxCollisionVisitsId, 1); - defaults->Set(SearchParams::kMaxCollisionEventsId, 1); - defaults->Set(SearchParams::kCacheHistoryLengthId, 7); - defaults->Set(SearchParams::kOutOfOrderEvalId, false); - defaults->Set(SearchParams::kTemperatureId, 1.0f); - defaults->Set(SearchParams::kNoiseEpsilonId, 0.25f); - defaults->Set(SearchParams::kFpuValueId, 0.0f); - defaults->Set(SearchParams::kHistoryFillId, "no"); + defaults->Set(classic::SearchParams::kMiniBatchSizeId, 32); + defaults->Set(classic::SearchParams::kCpuctId, 1.2f); + defaults->Set(classic::SearchParams::kCpuctFactorId, 0.0f); + defaults->Set(classic::SearchParams::kPolicySoftmaxTempId, 1.0f); + defaults->Set(classic::SearchParams::kMaxCollisionVisitsId, 1); + defaults->Set(classic::SearchParams::kMaxCollisionEventsId, 1); + defaults->Set(classic::SearchParams::kCacheHistoryLengthId, 7); + defaults->Set(classic::SearchParams::kOutOfOrderEvalId, false); + defaults->Set(classic::SearchParams::kTemperatureId, 1.0f); + defaults->Set(classic::SearchParams::kNoiseEpsilonId, 0.25f); + defaults->Set(classic::SearchParams::kFpuValueId, 0.0f); + defaults->Set(classic::SearchParams::kHistoryFillId, "no"); defaults->Set(NetworkFactory::kBackendId, "multiplexing"); - defaults->Set(SearchParams::kStickyEndgamesId, false); - defaults->Set(SearchParams::kTwoFoldDrawsId, false); - defaults->Set(SearchParams::kTaskWorkersPerSearchWorkerId, 0); + defaults->Set(classic::SearchParams::kStickyEndgamesId, false); + defaults->Set(classic::SearchParams::kTwoFoldDrawsId, false); + defaults->Set(classic::SearchParams::kTaskWorkersPerSearchWorkerId, 0); } SelfPlayTournament::SelfPlayTournament( @@ -225,12 +225,12 @@ SelfPlayTournament::SelfPlayTournament( // Initializing cache. cache_[0] = std::make_shared( - options.GetSubdict("player1").Get(kNNCacheSizeId)); + options.GetSubdict("player1").Get(classic::kNNCacheSizeId)); if (kShareTree) { cache_[1] = cache_[0]; } else { cache_[1] = std::make_shared( - options.GetSubdict("player2").Get(kNNCacheSizeId)); + options.GetSubdict("player2").Get(classic::kNNCacheSizeId)); } // SearchLimits. diff --git a/src/tools/backendbench.cc b/src/tools/backendbench.cc index d8edf3ce97..6568d48200 100644 --- a/src/tools/backendbench.cc +++ b/src/tools/backendbench.cc @@ -28,8 +28,8 @@ #include "tools/backendbench.h" #include "chess/board.h" -#include "mcts/node.h" #include "neural/factory.h" +#include "search/classic/node.h" #include "utils/optionsparser.h" namespace lczero { @@ -50,27 +50,25 @@ const OptionId kFenId{"fen", "", "Benchmark initial position FEN."}; const OptionId kClippyId{"clippy", "", "Enable helpful assistant."}; -void Clippy(std::string title, - std::string msg3, std::string best3, std::string msg2, - std::string best2, std::string msg, std::string best) { +void Clippy(std::string title, std::string msg3, std::string best3, + std::string msg2, std::string best2, std::string msg, + std::string best) { std::cout << " __" << std::endl; std::cout << " / \\" << std::endl; - std::cout << " | | " << std::string(title.length()+2, '_') << std::endl; - std::cout << " + + | " << std::string(title.length()+1, ' ') - << "|" << std::endl; - std::cout << "(@)(@) _| " - << title << " |" + std::cout << " | | " << std::string(title.length() + 2, '_') << std::endl; + std::cout << " + + | " << std::string(title.length() + 1, ' ') << "|" << std::endl; + std::cout << "(@)(@) _| " << title << " |" << std::endl; std::cout << " | | \\ " << std::string(6, ' ') << msg3 << std::string(4 - best3.length(), ' ') << best3 - << std::string(title.length()-33, ' ') << "|" << std::endl; + << std::string(title.length() - 33, ' ') << "|" << std::endl; std::cout << " || |/ | " << std::string(6, ' ') << msg2 << std::string(4 - best2.length(), ' ') << best2 - << std::string(title.length()-33, ' ') << "|" << std::endl; + << std::string(title.length() - 33, ' ') << "|" << std::endl; std::cout << " || || | " << std::string(6, ' ') << msg << std::string(4 - best.length(), ' ') << best - << std::string(title.length()-33, ' ') << "|" << std::endl; - std::cout << " |\\_/| |" << std::string(title.length()+2, '_') << "|" + << std::string(title.length() - 33, ' ') << "|" << std::endl; + std::cout << " |\\_/| |" << std::string(title.length() + 2, '_') << "|" << std::endl; std::cout << " \\___/" << std::endl; } @@ -95,7 +93,7 @@ void BackendBenchmark::Run() { auto network = NetworkFactory::LoadNetwork(option_dict); - NodeTree tree; + classic::NodeTree tree; tree.ResetToPosition(option_dict.Get(kFenId), {}); // Do any backend initialization outside the loop. @@ -107,8 +105,12 @@ void BackendBenchmark::Run() { const int batches = option_dict.Get(kBatchesId); - int best = 1; int best2 = 1; int best3 = 1; - float best_nps = 0.0f; float best_nps2 = 0.0f; float best_nps3 = 0.0f; + int best = 1; + int best2 = 1; + int best3 = 1; + float best_nps = 0.0f; + float best_nps2 = 0.0f; + float best_nps3 = 0.0f; std::optional> pending; for (int i = option_dict.Get(kStartBatchSizeId); @@ -137,12 +139,12 @@ void BackendBenchmark::Run() { << " nps." << std::endl; if (option_dict.Get(kClippyId)) { - float nps_ingame = std::pow((nps + best_nps) / 2, 1.085); + float nps_ingame = std::pow((nps + best_nps) / 2, 1.085); float nps_ingame2 = std::pow((nps + best_nps2) / 2, 1.085); float nps_ingame3 = std::pow((nps + best_nps3) / 2, 1.085); - float threshold = 0.16947 * exp(-4.1695e-6 * nps_ingame * 180) + 0.02; - float threshold2 = 0.16947 * exp(-4.1695e-6 * nps_ingame2 * 15) + 0.02; - float threshold3 = 0.16947 * exp(-4.1695e-6 * nps_ingame3 * 1) + 0.02; + float threshold = 0.16947 * exp(-4.1695e-6 * nps_ingame * 180) + 0.02; + float threshold2 = 0.16947 * exp(-4.1695e-6 * nps_ingame2 * 15) + 0.02; + float threshold3 = 0.16947 * exp(-4.1695e-6 * nps_ingame3 * 1) + 0.02; if (nps > best_nps && threshold * (i - best) * best_nps < (nps - best_nps) * best) { @@ -165,22 +167,20 @@ void BackendBenchmark::Run() { if (pending) { time = std::chrono::steady_clock::now() - *pending; if (time.count() > 10) { - Clippy( - "Recommended minibatch-size for this net (so far):", - "1s/move (Bullet): ", std::to_string(best3), - "15s/move (Rapid): ", std::to_string(best2), - "3min/move (Tournament): ", std::to_string(best)); + Clippy("Recommended minibatch-size for this net (so far):", + "1s/move (Bullet): ", std::to_string(best3), + "15s/move (Rapid): ", std::to_string(best2), + "3min/move (Tournament): ", std::to_string(best)); pending.reset(); } } } } if (option_dict.Get(kClippyId)) { - Clippy( - "Recommended minibatch-size for this net:", - "1s/move (Bullet): ", std::to_string(best3), - "15s/move (Rapid): ", std::to_string(best2), - "3min/move (Tournament): ", std::to_string(best)); + Clippy("Recommended minibatch-size for this net:", + "1s/move (Bullet): ", std::to_string(best3), + "15s/move (Rapid): ", std::to_string(best2), + "3min/move (Tournament): ", std::to_string(best)); } } catch (Exception& ex) { std::cerr << ex.what() << std::endl; diff --git a/src/tools/benchmark.cc b/src/tools/benchmark.cc index c9991cdf3c..8282bd95c1 100644 --- a/src/tools/benchmark.cc +++ b/src/tools/benchmark.cc @@ -29,9 +29,9 @@ #include -#include "mcts/search.h" -#include "mcts/stoppers/factory.h" -#include "mcts/stoppers/stoppers.h" +#include "search/classic/search.h" +#include "search/classic/stoppers/factory.h" +#include "search/classic/stoppers/stoppers.h" namespace lczero { namespace { @@ -51,8 +51,8 @@ void Benchmark::Run() { OptionsParser options; NetworkFactory::PopulateOptions(&options); options.Add(kThreadsOptionId, 1, 128) = kDefaultThreads; - options.Add(kNNCacheSizeId, 0, 999999999) = 200000; - SearchParams::Populate(&options); + options.Add(classic::kNNCacheSizeId, 0, 999999999) = 200000; + classic::SearchParams::Populate(&options); options.Add(kNodesId, -1, 999999999) = -1; options.Add(kMovetimeId, -1, 999999999) = 10000; @@ -86,22 +86,24 @@ void Benchmark::Run() { std::cout << "\nPosition: " << cnt++ << "/" << testing_positions.size() << " " << position << std::endl; - auto stopper = std::make_unique(); + auto stopper = std::make_unique(); if (movetime > -1) { - stopper->AddStopper(std::make_unique(movetime)); + stopper->AddStopper( + std::make_unique(movetime)); } if (visits > -1) { - stopper->AddStopper(std::make_unique(visits, false)); + stopper->AddStopper( + std::make_unique(visits, false)); } NNCache cache; - cache.SetCapacity(option_dict.Get(kNNCacheSizeId)); + cache.SetCapacity(option_dict.Get(classic::kNNCacheSizeId)); - NodeTree tree; + classic::NodeTree tree; tree.ResetToPosition(position, {}); const auto start = std::chrono::steady_clock::now(); - auto search = std::make_unique( + auto search = std::make_unique( tree, network.get(), std::make_unique( std::bind(&Benchmark::OnBestMove, this, std::placeholders::_1), diff --git a/src/tools/benchmark.h b/src/tools/benchmark.h index a081a76883..d14ea6b53d 100644 --- a/src/tools/benchmark.h +++ b/src/tools/benchmark.h @@ -27,7 +27,7 @@ #pragma once -#include "mcts/search.h" +#include "search/classic/search.h" #include "neural/cache.h" #include "neural/factory.h" #include "utils/optionsparser.h" diff --git a/src/trainingdata/trainingdata.cc b/src/trainingdata/trainingdata.cc index 1285dc7b49..e5caddfc84 100644 --- a/src/trainingdata/trainingdata.cc +++ b/src/trainingdata/trainingdata.cc @@ -111,10 +111,12 @@ void V6TrainingDataArray::Write(TrainingDataWriter* writer, GameResult result, } } -void V6TrainingDataArray::Add(const Node* node, const PositionHistory& history, - Eval best_eval, Eval played_eval, - bool best_is_proven, Move best_move, - Move played_move, const NNCacheLock& nneval) { +void V6TrainingDataArray::Add(const classic::Node* node, + const PositionHistory& history, + classic::Eval best_eval, + classic::Eval played_eval, bool best_is_proven, + Move best_move, Move played_move, + const NNCacheLock& nneval) { V6TrainingData result; const auto& position = history.Last(); @@ -234,7 +236,7 @@ void V6TrainingDataArray::Add(const Node* node, const PositionHistory& history, result.result_q = 0; result.result_d = 1; - Eval orig_eval; + classic::Eval orig_eval; if (nneval) { orig_eval.wl = nneval->q; orig_eval.d = nneval->d; diff --git a/src/trainingdata/trainingdata.h b/src/trainingdata/trainingdata.h index 6fc3b3b8a5..83894f355e 100644 --- a/src/trainingdata/trainingdata.h +++ b/src/trainingdata/trainingdata.h @@ -27,7 +27,7 @@ #pragma once -#include "mcts/node.h" +#include "search/classic/node.h" #include "trainingdata/writer.h" namespace lczero { @@ -72,7 +72,7 @@ struct V6TrainingData { float played_d; float played_m; // The folowing may be NaN if not found in cache. - float orig_q; // For value repair. + float orig_q; // For value repair. float orig_d; float orig_m; uint32_t visits; @@ -96,9 +96,10 @@ class V6TrainingDataArray { input_format_(input_format) {} // Add a chunk. - void Add(const Node* node, const PositionHistory& history, Eval best_eval, - Eval played_eval, bool best_is_proven, Move best_move, - Move played_move, const NNCacheLock& nneval); + void Add(const classic::Node* node, const PositionHistory& history, + classic::Eval best_eval, classic::Eval played_eval, + bool best_is_proven, Move best_move, Move played_move, + const NNCacheLock& nneval); // Writes training data to a file. void Write(TrainingDataWriter* writer, GameResult result, From 8ccae03ef75813987d73ab9f024f875a661d3294 Mon Sep 17 00:00:00 2001 From: Alexander Lyashuk Date: Mon, 30 Dec 2024 23:25:04 +0100 Subject: [PATCH 013/212] New backend API and wrapper for old networks. (#2098) --- meson.build | 3 + src/neural/backend.cc | 48 +++++++++++++ src/neural/backend.h | 111 +++++++++++++++++++++++++++++++ src/neural/factory.h | 25 ++++--- src/neural/register.cc | 37 +++++++++++ src/neural/register.h | 61 +++++++++++++++++ src/neural/wrapper.cc | 148 +++++++++++++++++++++++++++++++++++++++++ src/neural/wrapper.h | 57 ++++++++++++++++ 8 files changed, 482 insertions(+), 8 deletions(-) create mode 100644 src/neural/backend.cc create mode 100644 src/neural/backend.h create mode 100644 src/neural/register.cc create mode 100644 src/neural/register.h create mode 100644 src/neural/wrapper.cc create mode 100644 src/neural/wrapper.h diff --git a/meson.build b/meson.build index a749d884c9..c808d46603 100644 --- a/meson.build +++ b/meson.build @@ -161,8 +161,11 @@ common_files += [ 'src/chess/board.cc', 'src/chess/position.cc', 'src/chess/uciloop.cc', + 'src/neural/backend.cc', 'src/neural/decoder.cc', 'src/neural/encoder.cc', + 'src/neural/register.cc', + 'src/neural/wrapper.cc', 'src/search/classic/node.cc', 'src/syzygy/syzygy.cc', 'src/trainingdata/reader.cc', diff --git a/src/neural/backend.cc b/src/neural/backend.cc new file mode 100644 index 0000000000..5ee0f61006 --- /dev/null +++ b/src/neural/backend.cc @@ -0,0 +1,48 @@ +/* + This file is part of Leela Chess Zero. + Copyright (C) 2024 The LCZero Authors + + Leela Chess is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Leela Chess is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Leela Chess. If not, see . + + Additional permission under GNU GPL version 3 section 7 + + If you modify this Program, or any covered work, by linking or + combining it with NVIDIA Corporation's libraries from the NVIDIA CUDA + Toolkit and the NVIDIA CUDA Deep Neural Network library (or a + modified version of those libraries), containing parts covered by the + terms of the respective license agreement, the licensors of this + Program grant you additional permission to convey the resulting work. +*/ + +#include "neural/backend.h" + +namespace lczero { + +std::vector Backend::EvaluateBatch( + std::span positions) { + std::vector results; + results.reserve(positions.size()); + std::unique_ptr computation = CreateComputation(); + for (const EvalPosition& pos : positions) { + results.emplace_back(); + EvalResult& result = results.back(); + computation->AddInput( + pos, EvalResultPtr{&result.q, &result.d, &result.m, + std::span(result.p.data(), result.p.size())}); + } + computation->ComputeBlocking(); + return results; +} + +} // namespace lczero \ No newline at end of file diff --git a/src/neural/backend.h b/src/neural/backend.h new file mode 100644 index 0000000000..7672b812b0 --- /dev/null +++ b/src/neural/backend.h @@ -0,0 +1,111 @@ +/* + This file is part of Leela Chess Zero. + Copyright (C) 2024 The LCZero Authors + + Leela Chess is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Leela Chess is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Leela Chess. If not, see . + + Additional permission under GNU GPL version 3 section 7 + + If you modify this Program, or any covered work, by linking or + combining it with NVIDIA Corporation's libraries from the NVIDIA CUDA + Toolkit and the NVIDIA CUDA Deep Neural Network library (or a + modified version of those libraries), containing parts covered by the + terms of the respective license agreement, the licensors of this + Program grant you additional permission to convey the resulting work. +*/ + +#pragma once + +#include +#include +#include +#include +#include + +#include "chess/position.h" +#include "neural/loader.h" +#include "utils/optionsdict.h" + +namespace lczero { + +// Information about the backend or network that search may need. +struct BackendAttributes { + bool has_mlh; + bool has_wdl; + bool runs_on_cpu; + int suggested_num_search_threads; + int recommended_batch_size; + int maximum_batch_size; +}; + +struct EvalResult { + float q; + float d; + float m; + std::vector p; +}; + +struct EvalResultPtr { + float* q = nullptr; + float* d = nullptr; + float* m = nullptr; + std::span p; +}; + +struct EvalPosition { + std::span pos; + std::span legal_moves; +}; + +class BackendComputation { + public: + virtual ~BackendComputation() = default; + virtual size_t UsedBatchSize() const = 0; + enum AddInputResult { + ENQUEUED_FOR_EVAL = 0, // Will be computed during ComputeBlocking(); + FETCHED_IMMEDIATELY = 1, // Was in cache, the result is already populated. + }; + virtual AddInputResult AddInput( + const EvalPosition& pos, // Input position. + EvalResultPtr result) = 0; // Where to fetch data into. + virtual void ComputeBlocking() = 0; +}; + +class Backend { + public: + virtual ~Backend() = default; + virtual BackendAttributes GetAttributes() const = 0; + virtual std::unique_ptr CreateComputation() = 0; + + // Simple helper with default implementation, to evaluate a batch without + // creating a computation explicitly. + virtual std::vector EvaluateBatch( + std::span positions); + // Returns the evaluation if it's possible to do immediately. + virtual std::optional GetCachedEvaluation(const EvalPosition&) { + return std::nullopt; + } +}; + +class BackendFactory { + public: + virtual ~BackendFactory() = default; + // Higher priority is higher. + virtual int GetPriority() const = 0; + virtual std::string_view GetName() const = 0; + virtual std::unique_ptr Create(const std::optional&, + const OptionsDict&) = 0; +}; + +} // namespace lczero \ No newline at end of file diff --git a/src/neural/factory.h b/src/neural/factory.h index 4448aa3224..e3f87edebe 100644 --- a/src/neural/factory.h +++ b/src/neural/factory.h @@ -33,6 +33,7 @@ #include "neural/loader.h" #include "neural/network.h" +#include "neural/wrapper.h" #include "utils/optionsdict.h" #include "utils/optionsparser.h" @@ -115,15 +116,23 @@ class NetworkFactory { friend class Register; }; -#define REGISTER_NETWORK_WITH_COUNTER2(name, func, priority, counter) \ - namespace { \ - static NetworkFactory::Register regH38fhs##counter( \ - name, \ - [](const std::optional& w, const OptionsDict& o) { \ - return func(w, o); \ - }, \ - priority); \ +#define REGISTER_NETWORK_WITH_COUNTER2(name, func, priority, counter) \ + namespace { \ + static NetworkFactory::Register regH38fhs##counter( \ + name, \ + [](const std::optional& w, const OptionsDict& o) { \ + return func(w, o); \ + }, \ + priority); \ + static BackendManager::Register regK03nv##counter( \ + std::make_unique( \ + name, \ + [](const std::optional& w, const OptionsDict& o) { \ + return func(w, o); \ + }, \ + priority)); \ } + #define REGISTER_NETWORK_WITH_COUNTER(name, func, priority, counter) \ REGISTER_NETWORK_WITH_COUNTER2(name, func, priority, counter) diff --git a/src/neural/register.cc b/src/neural/register.cc new file mode 100644 index 0000000000..56c82227d7 --- /dev/null +++ b/src/neural/register.cc @@ -0,0 +1,37 @@ +/* + This file is part of Leela Chess Zero. + Copyright (C) 2024 The LCZero Authors + + Leela Chess is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Leela Chess is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Leela Chess. If not, see . + + Additional permission under GNU GPL version 3 section 7 + + If you modify this Program, or any covered work, by linking or + combining it with NVIDIA Corporation's libraries from the NVIDIA CUDA + Toolkit and the NVIDIA CUDA Deep Neural Network library (or a + modified version of those libraries), containing parts covered by the + terms of the respective license agreement, the licensors of this + Program grant you additional permission to convey the resulting work. +*/ + +#include "neural/register.h" + +namespace lczero { + +BackendManager* BackendManager::Get() { + static BackendManager instance; + return &instance; +} + +} // namespace lczero \ No newline at end of file diff --git a/src/neural/register.h b/src/neural/register.h new file mode 100644 index 0000000000..ef982de4bd --- /dev/null +++ b/src/neural/register.h @@ -0,0 +1,61 @@ +/* + This file is part of Leela Chess Zero. + Copyright (C) 2024 The LCZero Authors + + Leela Chess is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Leela Chess is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Leela Chess. If not, see . + + Additional permission under GNU GPL version 3 section 7 + + If you modify this Program, or any covered work, by linking or + combining it with NVIDIA Corporation's libraries from the NVIDIA CUDA + Toolkit and the NVIDIA CUDA Deep Neural Network library (or a + modified version of those libraries), containing parts covered by the + terms of the respective license agreement, the licensors of this + Program grant you additional permission to convey the resulting work. +*/ + +#include +#include + +#include "neural/backend.h" + +#pragma once + +namespace lczero { + +class BackendManager { + public: + static BackendManager* Get(); + void AddBackend(std::unique_ptr factory) { + algorithms_.push_back(std::move(factory)); + } + + struct Register { + Register(std::unique_ptr factory) { + BackendManager::Get()->AddBackend(std::move(factory)); + } + }; + + private: + BackendManager() = default; + + std::vector> algorithms_; +}; + +#define REGISTER_BACKEND(factory) \ + namespace { \ + static SearchFactory::Register reg29c93##factory( \ + std::make_unique()); \ + } +} // namespace lczero diff --git a/src/neural/wrapper.cc b/src/neural/wrapper.cc new file mode 100644 index 0000000000..cb6425d6e1 --- /dev/null +++ b/src/neural/wrapper.cc @@ -0,0 +1,148 @@ +/* + This file is part of Leela Chess Zero. + Copyright (C) 2024 The LCZero Authors + + Leela Chess is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Leela Chess is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Leela Chess. If not, see . + + Additional permission under GNU GPL version 3 section 7 + + If you modify this Program, or any covered work, by linking or + combining it with NVIDIA Corporation's libraries from the NVIDIA CUDA + Toolkit and the NVIDIA CUDA Deep Neural Network library (or a + modified version of those libraries), containing parts covered by the + terms of the respective license agreement, the licensors of this + Program grant you additional permission to convey the resulting work. +*/ + +#include "neural/wrapper.h" + +#include +#include + +#include "neural/encoder.h" +#include "utils/fastmath.h" + +namespace lczero { +namespace { + +class NetworkAsBackend : public Backend { + public: + NetworkAsBackend(std::unique_ptr network, + float softmax_policy_temperature) + : network_(std::move(network)), + softmax_policy_temperature_(1.0f / softmax_policy_temperature) { + const NetworkCapabilities& caps = network_->GetCapabilities(); + attrs_.has_mlh = caps.has_mlh(); + attrs_.has_wdl = caps.has_wdl(); + attrs_.runs_on_cpu = network_->IsCpu(); + attrs_.suggested_num_search_threads = network_->GetThreads(); + attrs_.recommended_batch_size = network_->GetMiniBatchSize(); + attrs_.maximum_batch_size = 1024; + input_format_ = caps.input_format; + } + + BackendAttributes GetAttributes() const override { return attrs_; } + virtual std::unique_ptr CreateComputation() override; + + private: + std::unique_ptr network_; + BackendAttributes attrs_; + pblczero::NetworkFormat::InputFormat input_format_; + float softmax_policy_temperature_; + friend class NetworkAsBackendComputation; +}; + +class NetworkAsBackendComputation : public BackendComputation { + public: + NetworkAsBackendComputation(NetworkAsBackend* backend) + : backend_(backend), computation_(backend_->network_->NewComputation()) { + results_.reserve(backend_->attrs_.maximum_batch_size); + moves_.reserve(backend_->attrs_.maximum_batch_size); + transforms_.reserve(backend_->attrs_.maximum_batch_size); + } + + size_t UsedBatchSize() const override { return computation_->GetBatchSize(); } + + AddInputResult AddInput(const EvalPosition& pos, + EvalResultPtr result) override { + int transform; + computation_->AddInput(EncodePositionForNN(backend_->input_format_, pos.pos, + 8, FillEmptyHistory::FEN_ONLY, + &transform)); + results_.push_back(result); + moves_.emplace_back(pos.legal_moves.begin(), pos.legal_moves.end()); + transforms_.push_back(transform); + return ENQUEUED_FOR_EVAL; + } + + void ComputeBlocking() override { + computation_->ComputeBlocking(); + for (size_t i = 0; i < results_.size(); ++i) { + const EvalResultPtr& result = results_[i]; + if (result.q) *result.q = computation_->GetQVal(i); + if (result.d) *result.d = computation_->GetDVal(i); + if (result.m) *result.m = computation_->GetMVal(i); + if (!result.p.empty()) SoftmaxPolicy(result.p, computation_.get(), i); + } + } + + void SoftmaxPolicy(std::span dst, + const NetworkComputation* computation, int idx) { + const std::vector& moves = moves_[idx]; + const int transform = transforms_[idx]; + // Copy the values to the destination array and compute the maximum. + const float max_p = std::accumulate( + moves.begin(), moves.end(), -std::numeric_limits::infinity(), + [&, counter = 0](float max_p, const Move& move) mutable { + return std::max(max_p, dst[counter++] = computation->GetPVal( + idx, move.as_nn_index(transform))); + }); + // Compute the softmax and compute the total. + const float temperature = backend_->softmax_policy_temperature_; + float total = std::accumulate( + dst.begin(), dst.end(), 0.0f, [&](float total, float& val) { + return total + (val = FastExp((val - max_p) * temperature)); + }); + const float scale = total > 0.0f ? 1.0f / total : 1.0f; + // Scale the values to sum to 1.0. + std::for_each(dst.begin(), dst.end(), [&](float& val) { val *= scale; }); + } + + private: + NetworkAsBackend* backend_; + std::unique_ptr computation_; + std::vector> moves_; + std::vector results_; + std::vector transforms_; +}; + +std::unique_ptr NetworkAsBackend::CreateComputation() { + return std::make_unique(this); +} + +} // namespace + +NetworkAsBackendFactory::NetworkAsBackendFactory(const std::string& name, + FactoryFunc factory, + int priority) + : name_(name), factory_(factory), priority_(priority) {} + +std::unique_ptr NetworkAsBackendFactory::Create( + const std::optional& weights, const OptionsDict& options) { + return std::make_unique( + factory_(weights, options), + options.GetOrDefault("policy_temp", 1.359f)); +} + +} // namespace lczero \ No newline at end of file diff --git a/src/neural/wrapper.h b/src/neural/wrapper.h new file mode 100644 index 0000000000..73df876799 --- /dev/null +++ b/src/neural/wrapper.h @@ -0,0 +1,57 @@ +/* + This file is part of Leela Chess Zero. + Copyright (C) 2024 The LCZero Authors + + Leela Chess is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Leela Chess is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Leela Chess. If not, see . + + Additional permission under GNU GPL version 3 section 7 + + If you modify this Program, or any covered work, by linking or + combining it with NVIDIA Corporation's libraries from the NVIDIA CUDA + Toolkit and the NVIDIA CUDA Deep Neural Network library (or a + modified version of those libraries), containing parts covered by the + terms of the respective license agreement, the licensors of this + Program grant you additional permission to convey the resulting work. +*/ + +#pragma once + +#include +#include + +#include "neural/network.h" +#include "neural/register.h" + +namespace lczero { + +class NetworkAsBackendFactory : public BackendFactory { + public: + using FactoryFunc = std::function( + const std::optional&, const OptionsDict&)>; + + NetworkAsBackendFactory(const std::string& name, FactoryFunc factory, + int priority = 0); + + virtual int GetPriority() const { return priority_; } + virtual std::string_view GetName() const { return name_; } + virtual std::unique_ptr Create(const std::optional&, + const OptionsDict&); + + private: + std::string name_; + FactoryFunc factory_; + int priority_; +}; + +} // namespace lczero \ No newline at end of file From fc0abdc96a08d79bd989cec913bdbbc9b3e842bb Mon Sep 17 00:00:00 2001 From: Alexander Lyashuk Date: Wed, 1 Jan 2025 20:34:30 +0100 Subject: [PATCH 014/212] Move backend-specific options out of search params.cc (#2104) --- meson.build | 1 + src/engine_classic.cc | 4 +- src/engine_loop.cc | 2 + src/neural/factory.cc | 47 +++++++--------------- src/neural/factory.h | 8 ---- src/neural/shared_params.cc | 75 ++++++++++++++++++++++++++++++++++++ src/neural/shared_params.h | 50 ++++++++++++++++++++++++ src/neural/wrapper.cc | 27 ++++++++++--- src/search/classic/params.cc | 19 +++------ src/search/classic/params.h | 2 - src/selfplay/tournament.cc | 13 ++++--- src/tools/backendbench.cc | 3 +- src/tools/benchmark.cc | 3 +- 13 files changed, 180 insertions(+), 74 deletions(-) create mode 100644 src/neural/shared_params.cc create mode 100644 src/neural/shared_params.h diff --git a/meson.build b/meson.build index c808d46603..3811ead0bc 100644 --- a/meson.build +++ b/meson.build @@ -165,6 +165,7 @@ common_files += [ 'src/neural/decoder.cc', 'src/neural/encoder.cc', 'src/neural/register.cc', + 'src/neural/shared_params.cc', 'src/neural/wrapper.cc', 'src/search/classic/node.cc', 'src/syzygy/syzygy.cc', diff --git a/src/engine_classic.cc b/src/engine_classic.cc index e6dc0c9038..8391cb11f8 100644 --- a/src/engine_classic.cc +++ b/src/engine_classic.cc @@ -31,6 +31,7 @@ #include #include +#include "neural/shared_params.h" #include "search/classic/search.h" #include "search/classic/stoppers/factory.h" #include "utils/commandline.h" @@ -96,7 +97,6 @@ void EngineClassic::PopulateOptions(OptionsParser* options) { using namespace std::placeholders; const bool is_simple = CommandLine::BinaryName().find("simple") != std::string::npos; - NetworkFactory::PopulateOptions(options); options->Add(kThreadsOptionId, 0, 128) = 0; options->Add(classic::kNNCacheSizeId, 0, 999999999) = 2000000; classic::SearchParams::Populate(options); @@ -105,7 +105,7 @@ void EngineClassic::PopulateOptions(OptionsParser* options) { if (is_simple) { options->HideAllOptions(); options->UnhideOption(kThreadsOptionId); - options->UnhideOption(NetworkFactory::kWeightsId); + options->UnhideOption(SharedBackendParams::kWeightsId); options->UnhideOption(classic::SearchParams::kContemptId); options->UnhideOption(classic::SearchParams::kMultiPvId); } diff --git a/src/engine_loop.cc b/src/engine_loop.cc index 74b851abc3..c59f572b47 100644 --- a/src/engine_loop.cc +++ b/src/engine_loop.cc @@ -27,6 +27,7 @@ #include "engine_loop.h" +#include "neural/shared_params.h" #include "utils/configfile.h" namespace lczero { @@ -52,6 +53,7 @@ EngineLoop::EngineLoop(std::unique_ptr options, options_->GetOptionsDict())) { options_->Add(kLogFileId); options_->Add(kPreload) = false; + SharedBackendParams::Populate(options_.get()); } void EngineLoop::RunLoop() { diff --git a/src/neural/factory.cc b/src/neural/factory.cc index 03c69ef682..1be3a31d15 100644 --- a/src/neural/factory.cc +++ b/src/neural/factory.cc @@ -30,27 +30,12 @@ #include #include "neural/loader.h" +#include "neural/shared_params.h" #include "utils/commandline.h" #include "utils/logging.h" namespace lczero { -const OptionId NetworkFactory::kWeightsId{ - "weights", "WeightsFile", - "Path from which to load network weights.\nSetting it to " - "makes it search in ./ and ./weights/ subdirectories for the latest (by " - "file date) file which looks like weights.", - 'w'}; -const OptionId NetworkFactory::kBackendId{ - "backend", "Backend", "Neural network computational backend to use.", 'b'}; -const OptionId NetworkFactory::kBackendOptionsId{ - "backend-opts", "BackendOptions", - "Parameters of neural network backend. " - "Exact parameters differ per backend.", - 'o'}; -const char* kAutoDiscover = ""; -const char* kEmbed = ""; - NetworkFactory* NetworkFactory::Get() { static NetworkFactory factory; return &factory; @@ -61,18 +46,6 @@ NetworkFactory::Register::Register(const std::string& name, FactoryFunc factory, NetworkFactory::Get()->RegisterNetwork(name, factory, priority); } -void NetworkFactory::PopulateOptions(OptionsParser* options) { -#if defined(EMBED) - options->Add(NetworkFactory::kWeightsId) = kEmbed; -#else - options->Add(NetworkFactory::kWeightsId) = kAutoDiscover; -#endif - const auto backends = NetworkFactory::Get()->GetBackendsList(); - options->Add(NetworkFactory::kBackendId, backends) = - backends.empty() ? "" : backends[0]; - options->Add(NetworkFactory::kBackendOptionsId); -} - void NetworkFactory::RegisterNetwork(const std::string& name, FactoryFunc factory, int priority) { factories_.emplace_back(name, factory, priority); @@ -99,9 +72,10 @@ std::unique_ptr NetworkFactory::Create( NetworkFactory::BackendConfiguration::BackendConfiguration( const OptionsDict& options) - : weights_path(options.Get(kWeightsId)), - backend(options.Get(kBackendId)), - backend_options(options.Get(kBackendOptionsId)) {} + : weights_path(options.Get(SharedBackendParams::kWeightsId)), + backend(options.Get(SharedBackendParams::kBackendId)), + backend_options( + options.Get(SharedBackendParams::kBackendOptionsId)) {} bool NetworkFactory::BackendConfiguration::operator==( const BackendConfiguration& other) const { @@ -111,10 +85,15 @@ bool NetworkFactory::BackendConfiguration::operator==( std::unique_ptr NetworkFactory::LoadNetwork( const OptionsDict& options) { - std::string net_path = options.Get(kWeightsId); - const std::string backend = options.Get(kBackendId); + std::string net_path = + options.Get(SharedBackendParams::kWeightsId); + const std::string backend = + options.Get(SharedBackendParams::kBackendId); const std::string backend_options = - options.Get(kBackendOptionsId); + options.Get(SharedBackendParams::kBackendOptionsId); + + constexpr const char* kAutoDiscover = ""; + constexpr const char* kEmbed = ""; if (net_path == kAutoDiscover) { net_path = DiscoverWeightsFile(); diff --git a/src/neural/factory.h b/src/neural/factory.h index e3f87edebe..1659f89773 100644 --- a/src/neural/factory.h +++ b/src/neural/factory.h @@ -56,9 +56,6 @@ class NetworkFactory { Register(const std::string& name, FactoryFunc factory, int priority = 0); }; - // Add the network/backend parameters to the options dictionary. - static void PopulateOptions(OptionsParser* options); - // Returns list of backend names, sorted by priority (higher priority first). std::vector GetBackendsList() const; @@ -71,11 +68,6 @@ class NetworkFactory { // if no network options changed since the previous call. static std::unique_ptr LoadNetwork(const OptionsDict& options); - // Parameter IDs. - static const OptionId kWeightsId; - static const OptionId kBackendId; - static const OptionId kBackendOptionsId; - struct BackendConfiguration { BackendConfiguration() = default; BackendConfiguration(const OptionsDict& options); diff --git a/src/neural/shared_params.cc b/src/neural/shared_params.cc new file mode 100644 index 0000000000..77414babea --- /dev/null +++ b/src/neural/shared_params.cc @@ -0,0 +1,75 @@ +/* + This file is part of Leela Chess Zero. + Copyright (C) 2024 The LCZero Authors + + Leela Chess is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Leela Chess is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Leela Chess. If not, see . + + Additional permission under GNU GPL version 3 section 7 + + If you modify this Program, or any covered work, by linking or + combining it with NVIDIA Corporation's libraries from the NVIDIA CUDA + Toolkit and the NVIDIA CUDA Deep Neural Network library (or a + modified version of those libraries), containing parts covered by the + terms of the respective license agreement, the licensors of this + Program grant you additional permission to convey the resulting work. +*/ + +#include "neural/shared_params.h" + +#include "neural/factory.h" + +namespace lczero { +const OptionId SharedBackendParams::kPolicySoftmaxTemp{ + "policy-softmax-temp", "PolicyTemperature", + "Policy softmax temperature. Higher values make priors of move candidates " + "closer to each other, widening the search."}; +const OptionId SharedBackendParams::kHistoryFill{ + "history-fill-new", "HistoryFill", + "Neural network uses 7 previous board positions in addition to the current " + "one. During the first moves of the game such historical positions don't " + "exist, but they can be synthesized. This parameter defines when to " + "synthesize them (always, never, or only at non-standard fen position)."}; +const OptionId SharedBackendParams::kWeightsId{ + "weights", "WeightsFile", + "Path from which to load network weights.\nSetting it to " + "makes it search in ./ and ./weights/ subdirectories for the latest (by " + "file date) file which looks like weights.", + 'w'}; +const OptionId SharedBackendParams::kBackendId{ + "backend", "Backend", "Neural network computational backend to use.", 'b'}; +const OptionId SharedBackendParams::kBackendOptionsId{ + "backend-opts", "BackendOptions", + "Parameters of neural network backend. " + "Exact parameters differ per backend.", + 'o'}; + +void SharedBackendParams::Populate(OptionsParser* options) { + options->Add(kPolicySoftmaxTemp, 0.1f, 10.0f) = 1.359f; + std::vector history_fill_opt{"no", "fen_only", "always"}; + options->Add(kHistoryFill, history_fill_opt) = "fen_only"; + +#if defined(EMBED) + constexpr const char* kEmbed = ""; + options->Add(SharedBackendParams::kWeightsId) = kEmbed; +#else + constexpr const char* kAutoDiscover = ""; + options->Add(SharedBackendParams::kWeightsId) = kAutoDiscover; +#endif + const auto backends = NetworkFactory::Get()->GetBackendsList(); + options->Add(SharedBackendParams::kBackendId, backends) = + backends.empty() ? "" : backends[0]; + options->Add(SharedBackendParams::kBackendOptionsId); +} + +} // namespace lczero \ No newline at end of file diff --git a/src/neural/shared_params.h b/src/neural/shared_params.h new file mode 100644 index 0000000000..1640085e25 --- /dev/null +++ b/src/neural/shared_params.h @@ -0,0 +1,50 @@ +/* + This file is part of Leela Chess Zero. + Copyright (C) 2024 The LCZero Authors + + Leela Chess is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Leela Chess is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Leela Chess. If not, see . + + Additional permission under GNU GPL version 3 section 7 + + If you modify this Program, or any covered work, by linking or + combining it with NVIDIA Corporation's libraries from the NVIDIA CUDA + Toolkit and the NVIDIA CUDA Deep Neural Network library (or a + modified version of those libraries), containing parts covered by the + terms of the respective license agreement, the licensors of this + Program grant you additional permission to convey the resulting work. +*/ + +#pragma once + +#include "utils/optionsdict.h" +#include "utils/optionsparser.h" + +namespace lczero { + +// Backend parameters that appear in UCI interface and are in use by most +// backends. +struct SharedBackendParams { + static const OptionId kPolicySoftmaxTemp; + static const OptionId kHistoryFill; + static const OptionId kWeightsId; + static const OptionId kBackendId; + static const OptionId kBackendOptionsId; + + static void Populate(OptionsParser*); + + private: + SharedBackendParams() = delete; +}; + +} // namespace lczero \ No newline at end of file diff --git a/src/neural/wrapper.cc b/src/neural/wrapper.cc index cb6425d6e1..60c9819eaf 100644 --- a/src/neural/wrapper.cc +++ b/src/neural/wrapper.cc @@ -31,17 +31,27 @@ #include #include "neural/encoder.h" +#include "neural/shared_params.h" #include "utils/fastmath.h" namespace lczero { namespace { +FillEmptyHistory EncodeHistoryFill(std::string history_fill) { + if (history_fill == "fen_only") return FillEmptyHistory::FEN_ONLY; + if (history_fill == "always") return FillEmptyHistory::ALWAYS; + assert(history_fill == "no"); + return FillEmptyHistory::NO; +} + class NetworkAsBackend : public Backend { public: - NetworkAsBackend(std::unique_ptr network, - float softmax_policy_temperature) + NetworkAsBackend(std::unique_ptr network, const OptionsDict& options) : network_(std::move(network)), - softmax_policy_temperature_(1.0f / softmax_policy_temperature) { + softmax_policy_temperature_( + 1.0f / options.Get(SharedBackendParams::kPolicySoftmaxTemp)), + fill_empty_history_(EncodeHistoryFill( + options.Get(SharedBackendParams::kHistoryFill))) { const NetworkCapabilities& caps = network_->GetCapabilities(); attrs_.has_mlh = caps.has_mlh(); attrs_.has_wdl = caps.has_wdl(); @@ -60,6 +70,7 @@ class NetworkAsBackend : public Backend { BackendAttributes attrs_; pblczero::NetworkFormat::InputFormat input_format_; float softmax_policy_temperature_; + FillEmptyHistory fill_empty_history_; friend class NetworkAsBackendComputation; }; @@ -140,9 +151,13 @@ NetworkAsBackendFactory::NetworkAsBackendFactory(const std::string& name, std::unique_ptr NetworkAsBackendFactory::Create( const std::optional& weights, const OptionsDict& options) { - return std::make_unique( - factory_(weights, options), - options.GetOrDefault("policy_temp", 1.359f)); + const std::string backend_options = + options.Get(SharedBackendParams::kBackendOptionsId); + OptionsDict network_options; + network_options.AddSubdictFromString(backend_options); + + return std::make_unique(factory_(weights, network_options), + options); } } // namespace lczero \ No newline at end of file diff --git a/src/search/classic/params.cc b/src/search/classic/params.cc index 27c01d8ebb..33829f52b5 100644 --- a/src/search/classic/params.cc +++ b/src/search/classic/params.cc @@ -31,6 +31,7 @@ #include #include +#include "neural/shared_params.h" #include "utils/exception.h" #include "utils/string.h" @@ -296,10 +297,6 @@ const OptionId SearchParams::kCacheHistoryLengthId{ "this value is less than history that NN uses to eval a position, it's " "possble that the search will use eval of the same position with different " "history taken from cache."}; -const OptionId SearchParams::kPolicySoftmaxTempId{ - "policy-softmax-temp", "PolicyTemperature", - "Policy softmax temperature. Higher values make priors of move candidates " - "closer to each other, widening the search."}; const OptionId SearchParams::kMaxCollisionVisitsId{ "max-collision-visits", "MaxCollisionVisits", "Total allowed node collision visits, per batch."}; @@ -338,12 +335,6 @@ const OptionId SearchParams::kScoreTypeId{ "score-type", "ScoreType", "What to display as score. Either centipawns (the UCI default), win " "percentage or Q (the actual internal score) multiplied by 100."}; -const OptionId SearchParams::kHistoryFillId{ - "history-fill", "HistoryFill", - "Neural network uses 7 previous board positions in addition to the current " - "one. During the first moves of the game such historical positions don't " - "exist, but they can be synthesized. This parameter defines when to " - "synthesize them (always, never, or only at non-standard fen position)."}; const OptionId SearchParams::kMovesLeftMaxEffectId{ "moves-left-max-effect", "MovesLeftMaxEffect", "Maximum bonus to add to the score of a node based on how much " @@ -522,7 +513,6 @@ void SearchParams::Populate(OptionsParser* options) { options->Add(kFpuStrategyAtRootId, fpu_strategy) = "same"; options->Add(kFpuValueAtRootId, -100.0f, 100.0f) = 1.0f; options->Add(kCacheHistoryLengthId, 0, 7) = 0; - options->Add(kPolicySoftmaxTempId, 0.1f, 10.0f) = 1.359f; options->Add(kMaxCollisionEventsId, 1, 65536) = 917; options->Add(kMaxCollisionVisitsId, 1, 100000000) = 80000; options->Add(kMaxCollisionVisitsScalingStartId, 1, 100000) = 28; @@ -546,7 +536,6 @@ void SearchParams::Populate(OptionsParser* options) { "WDL_mu"}; options->Add(kScoreTypeId, score_type) = "WDL_mu"; std::vector history_fill_opt{"no", "fen_only", "always"}; - options->Add(kHistoryFillId, history_fill_opt) = "fen_only"; options->Add(kMovesLeftMaxEffectId, 0.0f, 1.0f) = 0.0345f; options->Add(kMovesLeftThresholdId, 0.0f, 1.0f) = 0.8f; options->Add(kMovesLeftSlopeId, 0.0f, 1.0f) = 0.0027f; @@ -637,13 +626,15 @@ SearchParams::SearchParams(const OptionsDict& options) ? kFpuValue : options.Get(kFpuValueAtRootId)), kCacheHistoryLength(options.Get(kCacheHistoryLengthId)), - kPolicySoftmaxTemp(options.Get(kPolicySoftmaxTempId)), + kPolicySoftmaxTemp( + options.Get(SharedBackendParams::kPolicySoftmaxTemp)), kMaxCollisionEvents(options.Get(kMaxCollisionEventsId)), kMaxCollisionVisits(options.Get(kMaxCollisionVisitsId)), kOutOfOrderEval(options.Get(kOutOfOrderEvalId)), kStickyEndgames(options.Get(kStickyEndgamesId)), kSyzygyFastPlay(options.Get(kSyzygyFastPlayId)), - kHistoryFill(EncodeHistoryFill(options.Get(kHistoryFillId))), + kHistoryFill(EncodeHistoryFill( + options.Get(SharedBackendParams::kHistoryFill))), kMiniBatchSize(options.Get(kMiniBatchSizeId)), kMovesLeftMaxEffect(options.Get(kMovesLeftMaxEffectId)), kMovesLeftThreshold(options.Get(kMovesLeftThresholdId)), diff --git a/src/search/classic/params.h b/src/search/classic/params.h index cc5a0322d3..13d75cb587 100644 --- a/src/search/classic/params.h +++ b/src/search/classic/params.h @@ -191,7 +191,6 @@ class SearchParams { static const OptionId kFpuStrategyAtRootId; static const OptionId kFpuValueAtRootId; static const OptionId kCacheHistoryLengthId; - static const OptionId kPolicySoftmaxTempId; static const OptionId kMaxCollisionEventsId; static const OptionId kMaxCollisionVisitsId; static const OptionId kOutOfOrderEvalId; @@ -200,7 +199,6 @@ class SearchParams { static const OptionId kMultiPvId; static const OptionId kPerPvCountersId; static const OptionId kScoreTypeId; - static const OptionId kHistoryFillId; static const OptionId kMovesLeftMaxEffectId; static const OptionId kMovesLeftThresholdId; static const OptionId kMovesLeftConstantFactorId; diff --git a/src/selfplay/tournament.cc b/src/selfplay/tournament.cc index 409d4d3681..7d4be9952a 100644 --- a/src/selfplay/tournament.cc +++ b/src/selfplay/tournament.cc @@ -31,6 +31,7 @@ #include "chess/pgn.h" #include "neural/factory.h" +#include "neural/shared_params.h" #include "search/classic/search.h" #include "search/classic/stoppers/factory.h" #include "selfplay/game.h" @@ -110,7 +111,7 @@ void SelfPlayTournament::PopulateOptions(OptionsParser* options) { dict->AddSubdict("black")->AddAliasDict(&options->GetOptionsDict("black")); } - NetworkFactory::PopulateOptions(options); + SharedBackendParams::Populate(options); options->Add(kThreadsId, 1, 8) = 1; options->Add(classic::kNNCacheSizeId, 0, 999999999) = 2000000; classic::SearchParams::Populate(options); @@ -142,7 +143,7 @@ void SelfPlayTournament::PopulateOptions(OptionsParser* options) { defaults->Set(classic::SearchParams::kMiniBatchSizeId, 32); defaults->Set(classic::SearchParams::kCpuctId, 1.2f); defaults->Set(classic::SearchParams::kCpuctFactorId, 0.0f); - defaults->Set(classic::SearchParams::kPolicySoftmaxTempId, 1.0f); + defaults->Set(SharedBackendParams::kPolicySoftmaxTemp, 1.0f); defaults->Set(classic::SearchParams::kMaxCollisionVisitsId, 1); defaults->Set(classic::SearchParams::kMaxCollisionEventsId, 1); defaults->Set(classic::SearchParams::kCacheHistoryLengthId, 7); @@ -150,8 +151,8 @@ void SelfPlayTournament::PopulateOptions(OptionsParser* options) { defaults->Set(classic::SearchParams::kTemperatureId, 1.0f); defaults->Set(classic::SearchParams::kNoiseEpsilonId, 0.25f); defaults->Set(classic::SearchParams::kFpuValueId, 0.0f); - defaults->Set(classic::SearchParams::kHistoryFillId, "no"); - defaults->Set(NetworkFactory::kBackendId, "multiplexing"); + defaults->Set(SharedBackendParams::kHistoryFill, "no"); + defaults->Set(SharedBackendParams::kBackendId, "multiplexing"); defaults->Set(classic::SearchParams::kStickyEndgamesId, false); defaults->Set(classic::SearchParams::kTwoFoldDrawsId, false); defaults->Set(classic::SearchParams::kTaskWorkersPerSearchWorkerId, 0); @@ -658,9 +659,9 @@ void SelfPlayTournament::SaveResults() { if (kTournamentResultsFile.empty()) return; std::ofstream output(kTournamentResultsFile, std::ios_base::app); auto p1name = - player_options_[0][0].Get(NetworkFactory::kWeightsId); + player_options_[0][0].Get(SharedBackendParams::kWeightsId); auto p2name = - player_options_[1][0].Get(NetworkFactory::kWeightsId); + player_options_[1][0].Get(SharedBackendParams::kWeightsId); output << std::endl; output << "[White \"" << p1name << "\"]" << std::endl; diff --git a/src/tools/backendbench.cc b/src/tools/backendbench.cc index 6568d48200..5ec46934c7 100644 --- a/src/tools/backendbench.cc +++ b/src/tools/backendbench.cc @@ -29,6 +29,7 @@ #include "chess/board.h" #include "neural/factory.h" +#include "neural/shared_params.h" #include "search/classic/node.h" #include "utils/optionsparser.h" @@ -76,7 +77,7 @@ void Clippy(std::string title, std::string msg3, std::string best3, void BackendBenchmark::Run() { OptionsParser options; - NetworkFactory::PopulateOptions(&options); + SharedBackendParams::Populate(&options); options.Add(kThreadsOptionId, 1, 128) = kDefaultThreads; options.Add(kBatchesId, 1, 999999999) = 100; diff --git a/src/tools/benchmark.cc b/src/tools/benchmark.cc index 8282bd95c1..e0debb969e 100644 --- a/src/tools/benchmark.cc +++ b/src/tools/benchmark.cc @@ -29,6 +29,7 @@ #include +#include "neural/shared_params.h" #include "search/classic/search.h" #include "search/classic/stoppers/factory.h" #include "search/classic/stoppers/stoppers.h" @@ -49,7 +50,7 @@ const OptionId kNumPositionsId{"num-positions", "", void Benchmark::Run() { OptionsParser options; - NetworkFactory::PopulateOptions(&options); + SharedBackendParams::Populate(&options); options.Add(kThreadsOptionId, 1, 128) = kDefaultThreads; options.Add(classic::kNNCacheSizeId, 0, 999999999) = 200000; classic::SearchParams::Populate(&options); From d5c663867f2e6cf7c57a9c1137dd0c862f2385b9 Mon Sep 17 00:00:00 2001 From: borg323 <39573933+borg323@users.noreply.github.com> Date: Thu, 2 Jan 2025 19:16:43 +0200 Subject: [PATCH 015/212] fix rescorer build with newer meson (#2089) --- subprojects/packagefiles/gaviotatb/meson.build | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/subprojects/packagefiles/gaviotatb/meson.build b/subprojects/packagefiles/gaviotatb/meson.build index d235a257d7..13986e8dfd 100644 --- a/subprojects/packagefiles/gaviotatb/meson.build +++ b/subprojects/packagefiles/gaviotatb/meson.build @@ -27,8 +27,13 @@ gaviotatb_includes = [ 'compression/lzma' ] +gaviota_lib = static_library('gaviota', + gaviotatb_src, + c_args : '-Dz_uLong=uLong', + include_directories : gaviotatb_includes) + +incdir = include_directories('.') + gaviotatb_dep = declare_dependency( - sources: gaviotatb_src, - include_directories: gaviotatb_includes, - compile_args:'-Dz_uLong=uLong' -) + link_with : gaviota_lib, + include_directories : gaviotatb_includes) From 548267cce53c964dd90c874c31c4583145ee51b0 Mon Sep 17 00:00:00 2001 From: Alexander Lyashuk Date: Thu, 2 Jan 2025 22:17:45 +0100 Subject: [PATCH 016/212] Introduce new search API, add a sample "policy head" algorithm (#2100) --- meson.build | 6 ++ src/chess/gamestate.cc | 50 ++++++++++++ src/chess/gamestate.h | 48 ++++++++++++ src/chess/position.h | 1 + src/search/artifacts.h | 37 +++++++++ src/search/instamove/instamove.cc | 72 ++++++++++++++++++ src/search/instamove/instamove.h | 80 ++++++++++++++++++++ src/search/register.cc | 41 ++++++++++ src/search/register.h | 62 +++++++++++++++ src/search/search.h | 122 ++++++++++++++++++++++++++++++ 10 files changed, 519 insertions(+) create mode 100644 src/chess/gamestate.cc create mode 100644 src/chess/gamestate.h create mode 100644 src/search/artifacts.h create mode 100644 src/search/instamove/instamove.cc create mode 100644 src/search/instamove/instamove.h create mode 100644 src/search/register.cc create mode 100644 src/search/register.h create mode 100644 src/search/search.h diff --git a/meson.build b/meson.build index 3811ead0bc..7d7476135e 100644 --- a/meson.build +++ b/meson.build @@ -159,6 +159,7 @@ files += gen_proto_src.process('src/neural/xla/hlo.proto', common_files += [ 'src/chess/bitboard.cc', 'src/chess/board.cc', + 'src/chess/gamestate.cc', 'src/chess/position.cc', 'src/chess/uciloop.cc', 'src/neural/backend.cc', @@ -215,6 +216,7 @@ files += [ 'src/search/classic/stoppers/smooth.cc', 'src/search/classic/stoppers/stoppers.cc', 'src/search/classic/stoppers/timemgr.cc', + 'src/search/register.cc', 'src/selfplay/game.cc', 'src/selfplay/loop.cc', 'src/selfplay/multigame.cc', @@ -228,6 +230,10 @@ files += [ 'src/utils/numa.cc', 'src/utils/weights_adapter.cc', ] + +files += [ + 'src/search/instamove/instamove.cc', +] includes += include_directories('src') deps += dependency('threads') diff --git a/src/chess/gamestate.cc b/src/chess/gamestate.cc new file mode 100644 index 0000000000..0a8cab2c52 --- /dev/null +++ b/src/chess/gamestate.cc @@ -0,0 +1,50 @@ +/* + This file is part of Leela Chess Zero. + Copyright (C) 2024 The LCZero Authors + + Leela Chess is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Leela Chess is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Leela Chess. If not, see . + + Additional permission under GNU GPL version 3 section 7 + + If you modify this Program, or any covered work, by linking or + combining it with NVIDIA Corporation's libraries from the NVIDIA CUDA + Toolkit and the NVIDIA CUDA Deep Neural Network library (or a + modified version of those libraries), containing parts covered by the + terms of the respective license agreement, the licensors of this + Program grant you additional permission to convey the resulting work. +*/ + +#include "chess/gamestate.h" + +#include +#include + +namespace lczero { + +Position GameState::CurrentPosition() const { + return std::accumulate( + moves.begin(), moves.end(), startpos, + [](const Position& pos, Move m) { return Position(pos, m); }); +} + +std::vector GameState::GetPositions() const { + std::vector positions; + positions.reserve(moves.size() + 1); + positions.push_back(startpos); + std::transform(moves.begin(), moves.end(), std::back_inserter(positions), + [&](const Move& m) { return Position(positions.back(), m); }); + return positions; +} + +} // namespace lczero diff --git a/src/chess/gamestate.h b/src/chess/gamestate.h new file mode 100644 index 0000000000..e473813c2e --- /dev/null +++ b/src/chess/gamestate.h @@ -0,0 +1,48 @@ +/* + This file is part of Leela Chess Zero. + Copyright (C) 2024 The LCZero Authors + + Leela Chess is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Leela Chess is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Leela Chess. If not, see . + + Additional permission under GNU GPL version 3 section 7 + + If you modify this Program, or any covered work, by linking or + combining it with NVIDIA Corporation's libraries from the NVIDIA CUDA + Toolkit and the NVIDIA CUDA Deep Neural Network library (or a + modified version of those libraries), containing parts covered by the + terms of the respective license agreement, the licensors of this + Program grant you additional permission to convey the resulting work. +*/ + +#pragma once + +#include + +#include "chess/position.h" + +namespace lczero { + +// A structure that is passed to Search/SearchEnvironment to provide the game +// state. Somewhat mirrors usi `position moves ...` command. +struct GameState { + Position startpos; + std::span moves; + + // Returns the position of the last move in the list. + Position CurrentPosition() const; + // Returns positions after all moves, including the starting and the last one. + std::vector GetPositions() const; +}; + +} // namespace lczero \ No newline at end of file diff --git a/src/chess/position.h b/src/chess/position.h index 99dc01f64a..f56f819824 100644 --- a/src/chess/position.h +++ b/src/chess/position.h @@ -36,6 +36,7 @@ namespace lczero { class Position { public: + Position() = default; // From parent position and move. Position(const Position& parent, Move m); // From particular position. diff --git a/src/search/artifacts.h b/src/search/artifacts.h new file mode 100644 index 0000000000..2ef68c5cf5 --- /dev/null +++ b/src/search/artifacts.h @@ -0,0 +1,37 @@ +/* + This file is part of Leela Chess Zero. + Copyright (C) 2024 The LCZero Authors + + Leela Chess is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Leela Chess is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Leela Chess. If not, see . + + Additional permission under GNU GPL version 3 section 7 + + If you modify this Program, or any covered work, by linking or + combining it with NVIDIA Corporation's libraries from the NVIDIA CUDA + Toolkit and the NVIDIA CUDA Deep Neural Network library (or a + modified version of those libraries), containing parts covered by the + terms of the respective license agreement, the licensors of this + Program grant you additional permission to convey the resulting work. +*/ + +#pragma once + +namespace lczero { + +// Contains the search artifacts that are needed e.g. to build the training +// data. The selfplay loop would fetch this from search to build training data +// frames. +struct SearchArtifacts {}; + +} // namespace lczero \ No newline at end of file diff --git a/src/search/instamove/instamove.cc b/src/search/instamove/instamove.cc new file mode 100644 index 0000000000..ab61436d85 --- /dev/null +++ b/src/search/instamove/instamove.cc @@ -0,0 +1,72 @@ +/* + This file is part of Leela Chess Zero. + Copyright (C) 2024 The LCZero Authors + + Leela Chess is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Leela Chess is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Leela Chess. If not, see . + + Additional permission under GNU GPL version 3 section 7 + + If you modify this Program, or any covered work, by linking or + combining it with NVIDIA Corporation's libraries from the NVIDIA CUDA + Toolkit and the NVIDIA CUDA Deep Neural Network library (or a + modified version of those libraries), containing parts covered by the + terms of the respective license agreement, the licensors of this + Program grant you additional permission to convey the resulting work. +*/ + +#include "search/instamove/instamove.h" + +#include +#include + +#include "chess/gamestate.h" +#include "neural/backend.h" +#include "search/register.h" +#include "search/search.h" + +namespace lczero { +namespace instamove { + +class PolicyHeadSearch : public InstamoveSearch { + public: + PolicyHeadSearch(const SearchContext& context, const GameState& game_state) + : InstamoveSearch(context), game_state_(game_state) {} + + Move GetBestMove() final { + const std::vector positions = game_state_.GetPositions(); + MoveList legal_moves = positions.back().GetBoard().GenerateLegalMoves(); + std::vector res = backend()->EvaluateBatch( + std::vector{EvalPosition{positions, legal_moves}}); + const size_t best_move_idx = + std::max_element(res[0].p.begin(), res[0].p.end()) - res[0].p.begin(); + return legal_moves[best_move_idx]; + } + + private: + const GameState game_state_; +}; + +class PolicyHeadFactory : public SearchFactory { + std::string_view GetName() const override { return "policyhead"; } + std::unique_ptr CreateEnvironment( + UciResponder* responder, const OptionsDict* options) const override { + return std::make_unique>(responder, + options); + } +}; + +REGISTER_SEARCH(PolicyHeadFactory); + +} // namespace instamove +} // namespace lczero \ No newline at end of file diff --git a/src/search/instamove/instamove.h b/src/search/instamove/instamove.h new file mode 100644 index 0000000000..32f9e7d461 --- /dev/null +++ b/src/search/instamove/instamove.h @@ -0,0 +1,80 @@ +/* + This file is part of Leela Chess Zero. + Copyright (C) 2024 The LCZero Authors + + Leela Chess is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Leela Chess is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Leela Chess. If not, see . + + Additional permission under GNU GPL version 3 section 7 + + If you modify this Program, or any covered work, by linking or + combining it with NVIDIA Corporation's libraries from the NVIDIA CUDA + Toolkit and the NVIDIA CUDA Deep Neural Network library (or a + modified version of those libraries), containing parts covered by the + terms of the respective license agreement, the licensors of this + Program grant you additional permission to convey the resulting work. +*/ + +#pragma once + +#include + +#include "chess/uciloop.h" +#include "search/search.h" + +// Base class for instamove searches (e.g. policy head and value head). +// The classes should only implement GetBestMove() method. + +namespace lczero { + +class InstamoveSearch : public SearchBase { + public: + using SearchBase::SearchBase; + + private: + virtual Move GetBestMove() = 0; + + void Start(const GoParams& go_params) final { + bestmove_ = GetBestMove(); + if (!go_params.infinite && !go_params.ponder) RespondBestMove(); + } + void Wait() final { + while (!responded_bestmove_.load()) { + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } + } + void Stop() final { RespondBestMove(); } + void Abort() final { responded_bestmove_.store(true); } + void RespondBestMove() { + if (responded_bestmove_.exchange(true)) return; + BestMoveInfo info{bestmove_}; + uci_responder()->OutputBestMove(&info); + } + + Move bestmove_; + std::atomic responded_bestmove_{false}; +}; + +template +class InstamoveEnvironment : public SearchEnvironment { + public: + using SearchEnvironment::SearchEnvironment; + + private: + std::unique_ptr CreateSearch( + const GameState& game_state) override { + return std::make_unique(context_, game_state); + } +}; + +} // namespace lczero \ No newline at end of file diff --git a/src/search/register.cc b/src/search/register.cc new file mode 100644 index 0000000000..fee7b82bff --- /dev/null +++ b/src/search/register.cc @@ -0,0 +1,41 @@ +/* + This file is part of Leela Chess Zero. + Copyright (C) 2018-2020 The LCZero Authors + + Leela Chess is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Leela Chess is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Leela Chess. If not, see . + + Additional permission under GNU GPL version 3 section 7 + + If you modify this Program, or any covered work, by linking or + combining it with NVIDIA Corporation's libraries from the NVIDIA CUDA + Toolkit and the NVIDIA CUDA Deep Neural Network library (or a + modified version of those libraries), containing parts covered by the + terms of the respective license agreement, the licensors of this + Program grant you additional permission to convey the resulting work. +*/ + +#include "search/register.h" + +namespace lczero { + +SearchManager* SearchManager::Get() { + static SearchManager factory; + return &factory; +} + +void SearchManager::AddSearchFactory(std::unique_ptr algorithm) { + algorithms_.push_back(std::move(algorithm)); +} + +} // namespace lczero \ No newline at end of file diff --git a/src/search/register.h b/src/search/register.h new file mode 100644 index 0000000000..d96ad00d37 --- /dev/null +++ b/src/search/register.h @@ -0,0 +1,62 @@ +/* + This file is part of Leela Chess Zero. + Copyright (C) 2024 The LCZero Authors + + Leela Chess is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Leela Chess is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Leela Chess. If not, see . + + Additional permission under GNU GPL version 3 section 7 + + If you modify this Program, or any covered work, by linking or + combining it with NVIDIA Corporation's libraries from the NVIDIA CUDA + Toolkit and the NVIDIA CUDA Deep Neural Network library (or a + modified version of those libraries), containing parts covered by the + terms of the respective license agreement, the licensors of this + Program grant you additional permission to convey the resulting work. +*/ + +#pragma once + +#include +#include + +#include "search/search.h" + +namespace lczero { + +class SearchFactory; + +// A singleton class that keeps one instance of each search algorithm's factory. +class SearchManager { + public: + static SearchManager* Get(); + void AddSearchFactory(std::unique_ptr); + + struct Register { + Register(std::unique_ptr factory) { + SearchManager::Get()->AddSearchFactory(std::move(factory)); + } + }; + + private: + SearchManager() = default; + + std::vector> algorithms_; +}; + +#define REGISTER_SEARCH(alg) \ + namespace { \ + static SearchManager::Register reg3b50Y##algorithm(std::make_unique()); \ + } + +} // namespace lczero \ No newline at end of file diff --git a/src/search/search.h b/src/search/search.h new file mode 100644 index 0000000000..ccdef8d4a5 --- /dev/null +++ b/src/search/search.h @@ -0,0 +1,122 @@ +/* + This file is part of Leela Chess Zero. + Copyright (C) 2024 The LCZero Authors + + Leela Chess is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Leela Chess is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Leela Chess. If not, see . + + Additional permission under GNU GPL version 3 section 7 + + If you modify this Program, or any covered work, by linking or + combining it with NVIDIA Corporation's libraries from the NVIDIA CUDA + Toolkit and the NVIDIA CUDA Deep Neural Network library (or a + modified version of those libraries), containing parts covered by the + terms of the respective license agreement, the licensors of this + Program grant you additional permission to convey the resulting work. +*/ + +#pragma once + +#include +#include + +#include "search/artifacts.h" +#include "utils/exception.h" + +namespace lczero { + +class Backend; +struct GameState; +struct GoParams; +class OptionsDict; +class OptionsParser; +class UciResponder; +class SyzygyTablebase; + +// Collection of pointers to objects that search needs but doesn't own. Just a +// convenience struct in order to avoid passing all of them separately in +// constructors. +struct SearchContext { + UciResponder* uci_responder = nullptr; + const OptionsDict* search_options = nullptr; + SyzygyTablebase* syzygy_tb = nullptr; + Backend* backend = nullptr; +}; + +// Base class for search runs. A separate instance is created for each search +// (i.e. for each move). +class SearchBase { + public: + explicit SearchBase(const SearchContext& context) : context_(context) {} + virtual ~SearchBase() = default; + + // Start the search. Must not block, should return immediately. + virtual void Start(const GoParams&) = 0; + // Wait for the search to finish. This is blocking. + virtual void Wait() = 0; + // Stops the search as soon as possible and responds with bestmove. Doesn't + // block. + virtual void Stop() = 0; + // Same as Stop(), but doesn't respond with bestmove. Doesn't block. + virtual void Abort() = 0; + // Return the data needed to build a training data frame (after the search is + // done). + virtual SearchArtifacts GetArtifacts() const { + throw Exception( + "Training data generation is not supported for this search algorithm."); + } + + protected: + UciResponder* uci_responder() const { return context_.uci_responder; } + SyzygyTablebase* syzygy_tb() const { return context_.syzygy_tb; } + Backend* backend() const { return context_.backend; } + const OptionsDict& search_options() const { return *context_.search_options; } + + private: + SearchContext context_; +}; + +// Search environment keeps the data that has to be shared between searches, +// for example the tree of the game, statistics, or whatever time manager wants +// to keep. +class SearchEnvironment { + public: + explicit SearchEnvironment(UciResponder* uci, const OptionsDict* dict) + : context_{uci, dict} {} + virtual ~SearchEnvironment() = default; + + // Resets search tree, and whatever else is needed to start a new game. + virtual void NewGame() {} + // Sets the position to search from in the future searches. + virtual std::unique_ptr CreateSearch(const GameState&) = 0; + + protected: + SearchContext context_; +}; + +// Creates an environment for a given search algorithm. One instance of the +// factory per algorithm is created at the start of the program, and registered +// in the SearchManager. +class SearchFactory { + public: + virtual ~SearchFactory() = default; + // Name of the algorithm (used in UCI options or command line). + virtual std::string_view GetName() const = 0; + // Populates the parameters of the algorithm. + virtual void PopulateParams(OptionsParser*) const {} + // Creates a new environment for the algorithm. + virtual std::unique_ptr CreateEnvironment( + UciResponder*, const OptionsDict*) const = 0; +}; + +} // namespace lczero \ No newline at end of file From ae7b22acb3255419860a211b9cf094afc675487d Mon Sep 17 00:00:00 2001 From: Alexander Lyashuk Date: Fri, 3 Jan 2025 10:55:58 +0100 Subject: [PATCH 017/212] Adding BackendManager functions to create a backend. (#2106) --- src/neural/backend.h | 3 +-- src/neural/factory.cc | 18 +++------------ src/neural/loader.cc | 25 ++++++++++++++++----- src/neural/loader.h | 12 ++++++++++ src/neural/register.cc | 44 +++++++++++++++++++++++++++++++++++++ src/neural/register.h | 16 ++++++++++++++ src/neural/shared_params.cc | 2 -- src/neural/shared_params.h | 3 +++ src/neural/wrapper.cc | 11 +++++++--- src/neural/wrapper.h | 7 +++--- 10 files changed, 110 insertions(+), 31 deletions(-) diff --git a/src/neural/backend.h b/src/neural/backend.h index 7672b812b0..4b2d3d3591 100644 --- a/src/neural/backend.h +++ b/src/neural/backend.h @@ -104,8 +104,7 @@ class BackendFactory { // Higher priority is higher. virtual int GetPriority() const = 0; virtual std::string_view GetName() const = 0; - virtual std::unique_ptr Create(const std::optional&, - const OptionsDict&) = 0; + virtual std::unique_ptr Create(const OptionsDict&) = 0; }; } // namespace lczero \ No newline at end of file diff --git a/src/neural/factory.cc b/src/neural/factory.cc index 1be3a31d15..a458a3b9e7 100644 --- a/src/neural/factory.cc +++ b/src/neural/factory.cc @@ -92,25 +92,13 @@ std::unique_ptr NetworkFactory::LoadNetwork( const std::string backend_options = options.Get(SharedBackendParams::kBackendOptionsId); - constexpr const char* kAutoDiscover = ""; - constexpr const char* kEmbed = ""; - - if (net_path == kAutoDiscover) { - net_path = DiscoverWeightsFile(); - } else if (net_path == kEmbed) { - net_path = CommandLine::BinaryName(); - } else { - CERR << "Loading weights file from: " << net_path; - } std::optional weights; - if (!net_path.empty()) { - weights = LoadWeightsFromFile(net_path); - } - + if (!net_path.empty()) weights = LoadWeights(net_path); OptionsDict network_options(&options); network_options.AddSubdictFromString(backend_options); - auto ptr = NetworkFactory::Get()->Create(backend, weights, network_options); + auto ptr = NetworkFactory::Get()->Create(backend, std::move(weights), + network_options); network_options.CheckAllOptionsRead(backend); return ptr; } diff --git a/src/neural/loader.cc b/src/neural/loader.cc index c88d985c2b..bfc3118d56 100644 --- a/src/neural/loader.cc +++ b/src/neural/loader.cc @@ -37,11 +37,12 @@ #include #include +#include "neural/shared_params.h" #include "proto/net.pb.h" #include "utils/commandline.h" #include "utils/exception.h" #include "utils/filesystem.h" -#include "utils/logging.h" +#include "utils/optionsdict.h" #include "version.h" #ifdef _WIN32 @@ -127,13 +128,11 @@ void FixOlderWeightsFile(WeightsFile* file) { net->set_network(nf::NETWORK_SE_WITH_HEADFORMAT); net->set_value(nf::VALUE_CLASSICAL); net->set_policy(nf::POLICY_CLASSICAL); - } else if (network_format == - nf::NETWORK_SE_WITH_HEADFORMAT && + } else if (network_format == nf::NETWORK_SE_WITH_HEADFORMAT && file->weights().encoder().size() > 0) { // Attention body network made with old protobuf. auto* net = file->mutable_format()->mutable_network_format(); - net->set_network( - nf::NETWORK_ATTENTIONBODY_WITH_HEADFORMAT); + net->set_network(nf::NETWORK_ATTENTIONBODY_WITH_HEADFORMAT); if (file->weights().has_smolgen_w()) { // Need to override activation defaults for smolgen. net->set_ffn_activation(nf::ACTIVATION_RELU_2); @@ -211,6 +210,22 @@ WeightsFile LoadWeightsFromFile(const std::string& filename) { return ParseWeightsProto(buffer); } +WeightsFile LoadWeights(std::string_view location) { + std::string net_path = std::string(location); + if (net_path == SharedBackendParams::kAutoDiscover) { + net_path = DiscoverWeightsFile(); + } else if (net_path == SharedBackendParams::kEmbed) { + net_path = CommandLine::BinaryName(); + } else { + CERR << "Loading weights file from: " << location; + } + return LoadWeightsFromFile(net_path); +} + +WeightsFile LoadWeightsFromOptions(const OptionsDict& options) { + return LoadWeights(options.Get(SharedBackendParams::kWeightsId)); +} + std::string DiscoverWeightsFile() { const int kMinFileSize = 500000; // 500 KB diff --git a/src/neural/loader.h b/src/neural/loader.h index 279e87e303..ef9e0a3434 100644 --- a/src/neural/loader.h +++ b/src/neural/loader.h @@ -27,7 +27,9 @@ #pragma once +#include #include +#include #include #include "neural/network.h" @@ -35,6 +37,7 @@ namespace lczero { +class OptionsDict; using FloatVector = std::vector; using FloatVectors = std::vector; @@ -43,6 +46,15 @@ using WeightsFile = pblczero::Net; // Read weights file and fill the weights structure. WeightsFile LoadWeightsFromFile(const std::string& filename); +// Read weights from the "locations", which is one of: +// * "" -- tries to find a file which looks like a weights file. +// * "" -- weights are embedded in the binary. +// * filename -- reads weights from the file. +WeightsFile LoadWeights(std::string_view location); + +// Extracts location from the "backend" parameter of options, and loads weights. +WeightsFile LoadWeightsFromOptions(const OptionsDict& options); + // Tries to find a file which looks like a weights file, and located in // directory of binary_name or one of subdirectories. If there are several such // files, returns one which has the latest modification date. diff --git a/src/neural/register.cc b/src/neural/register.cc index 56c82227d7..8048c07dd7 100644 --- a/src/neural/register.cc +++ b/src/neural/register.cc @@ -27,6 +27,10 @@ #include "neural/register.h" +#include + +#include "neural/shared_params.h" + namespace lczero { BackendManager* BackendManager::Get() { @@ -34,4 +38,44 @@ BackendManager* BackendManager::Get() { return &instance; } +std::vector BackendManager::GetBackendsList() const { + std::vector> priority_and_names; + std::transform(algorithms_.begin(), algorithms_.end(), + std::back_inserter(priority_and_names), + [](const std::unique_ptr& factory) { + return std::make_pair(factory->GetPriority(), + std::string(factory->GetName())); + }); + std::sort(priority_and_names.begin(), priority_and_names.end(), + std::greater<>()); + std::vector result; + std::transform(priority_and_names.begin(), priority_and_names.end(), + std::back_inserter(result), + [](const std::pair& p) { return p.second; }); + return result; +} + +BackendFactory* BackendManager::GetFactoryByName(std::string_view name) const { + auto iter = + std::find_if(algorithms_.begin(), algorithms_.end(), + [name](const std::unique_ptr& factory) { + return factory->GetName() == name; + }); + return iter == algorithms_.end() ? nullptr : iter->get(); +} + +std::unique_ptr BackendManager::CreateFromParams( + const OptionsDict& options) const { + const std::string backend = + options.Get(SharedBackendParams::kBackendId); + return CreateFromName(backend, options); +} + +std::unique_ptr BackendManager::CreateFromName( + std::string_view name, const OptionsDict& options) const { + BackendFactory* factory = GetFactoryByName(name); + if (!factory) throw Exception("Unknown backend: " + std::string(name)); + return factory->Create(options); +} + } // namespace lczero \ No newline at end of file diff --git a/src/neural/register.h b/src/neural/register.h index ef982de4bd..63f4cb620e 100644 --- a/src/neural/register.h +++ b/src/neural/register.h @@ -41,6 +41,22 @@ class BackendManager { algorithms_.push_back(std::move(factory)); } + // Returns list of backend names, sorted by priority (higher priority first). + std::vector GetBackendsList() const; + + // Creates a backend from the parameters. Extracts the weights file and the + // backend from the options. + std::unique_ptr CreateFromParams(const OptionsDict& options) const; + + // Creates a backend from the name. Backend name from the options is ignored. + // Note that unlike the WeightsFactory, the "options" parameter contains + // top-level parameters rather than `backend-opts`. + std::unique_ptr CreateFromName(std::string_view name, + const OptionsDict& options) const; + + // Returns a backend factory by name. Returns nullptr if not found. + BackendFactory* GetFactoryByName(std::string_view name) const; + struct Register { Register(std::unique_ptr factory) { BackendManager::Get()->AddBackend(std::move(factory)); diff --git a/src/neural/shared_params.cc b/src/neural/shared_params.cc index 77414babea..3606042d0b 100644 --- a/src/neural/shared_params.cc +++ b/src/neural/shared_params.cc @@ -60,10 +60,8 @@ void SharedBackendParams::Populate(OptionsParser* options) { options->Add(kHistoryFill, history_fill_opt) = "fen_only"; #if defined(EMBED) - constexpr const char* kEmbed = ""; options->Add(SharedBackendParams::kWeightsId) = kEmbed; #else - constexpr const char* kAutoDiscover = ""; options->Add(SharedBackendParams::kWeightsId) = kAutoDiscover; #endif const auto backends = NetworkFactory::Get()->GetBackendsList(); diff --git a/src/neural/shared_params.h b/src/neural/shared_params.h index 1640085e25..5d0e8fe3cd 100644 --- a/src/neural/shared_params.h +++ b/src/neural/shared_params.h @@ -35,6 +35,9 @@ namespace lczero { // Backend parameters that appear in UCI interface and are in use by most // backends. struct SharedBackendParams { + static const constexpr char* kEmbed = ""; + static const constexpr char* kAutoDiscover = ""; + static const OptionId kPolicySoftmaxTemp; static const OptionId kHistoryFill; static const OptionId kWeightsId; diff --git a/src/neural/wrapper.cc b/src/neural/wrapper.cc index 60c9819eaf..0108ce96a7 100644 --- a/src/neural/wrapper.cc +++ b/src/neural/wrapper.cc @@ -150,14 +150,19 @@ NetworkAsBackendFactory::NetworkAsBackendFactory(const std::string& name, : name_(name), factory_(factory), priority_(priority) {} std::unique_ptr NetworkAsBackendFactory::Create( - const std::optional& weights, const OptionsDict& options) { + const OptionsDict& options) { const std::string backend_options = options.Get(SharedBackendParams::kBackendOptionsId); OptionsDict network_options; network_options.AddSubdictFromString(backend_options); - return std::make_unique(factory_(weights, network_options), - options); + std::string net_path = + options.Get(SharedBackendParams::kWeightsId); + std::optional weights; + if (!net_path.empty()) weights = LoadWeights(net_path); + + return std::make_unique( + factory_(std::move(weights), network_options), options); } } // namespace lczero \ No newline at end of file diff --git a/src/neural/wrapper.h b/src/neural/wrapper.h index 73df876799..c11c45bab3 100644 --- a/src/neural/wrapper.h +++ b/src/neural/wrapper.h @@ -43,10 +43,9 @@ class NetworkAsBackendFactory : public BackendFactory { NetworkAsBackendFactory(const std::string& name, FactoryFunc factory, int priority = 0); - virtual int GetPriority() const { return priority_; } - virtual std::string_view GetName() const { return name_; } - virtual std::unique_ptr Create(const std::optional&, - const OptionsDict&); + int GetPriority() const override { return priority_; } + std::string_view GetName() const override { return name_; } + std::unique_ptr Create(const OptionsDict&) override; private: std::string name_; From ffd241946953841dcae36d351d2e8c063dfbe651 Mon Sep 17 00:00:00 2001 From: Alexander Lyashuk Date: Sat, 4 Jan 2025 21:06:43 +0100 Subject: [PATCH 018/212] Implement node cache as a backend layer. (#2108) --- meson.build | 1 + src/engine_classic.cc | 3 +- src/neural/memcache.cc | 153 ++++++++++++++++++++++++++ src/neural/memcache.h | 40 +++++++ src/neural/shared_params.cc | 6 + src/neural/shared_params.h | 1 + src/search/classic/stoppers/common.cc | 10 +- src/search/classic/stoppers/common.h | 4 - src/selfplay/tournament.cc | 10 +- src/tools/benchmark.cc | 6 +- src/utils/cache.h | 4 +- 11 files changed, 217 insertions(+), 21 deletions(-) create mode 100644 src/neural/memcache.cc create mode 100644 src/neural/memcache.h diff --git a/meson.build b/meson.build index 7d7476135e..9b32c8cfba 100644 --- a/meson.build +++ b/meson.build @@ -198,6 +198,7 @@ files += [ 'src/neural/cache.cc', 'src/neural/factory.cc', 'src/neural/loader.cc', + 'src/neural/memcache.cc', 'src/neural/network_legacy.cc', 'src/neural/onnx/adapters.cc', 'src/neural/onnx/builder.cc', diff --git a/src/engine_classic.cc b/src/engine_classic.cc index 8391cb11f8..44d7c96870 100644 --- a/src/engine_classic.cc +++ b/src/engine_classic.cc @@ -98,7 +98,6 @@ void EngineClassic::PopulateOptions(OptionsParser* options) { const bool is_simple = CommandLine::BinaryName().find("simple") != std::string::npos; options->Add(kThreadsOptionId, 0, 128) = 0; - options->Add(classic::kNNCacheSizeId, 0, 999999999) = 2000000; classic::SearchParams::Populate(options); ConfigFile::PopulateOptions(options); @@ -161,7 +160,7 @@ void EngineClassic::UpdateFromUciOptions() { } // Cache size. - cache_.SetCapacity(options_.Get(classic::kNNCacheSizeId)); + cache_.SetCapacity(options_.Get(SharedBackendParams::kNNCacheSizeId)); // Check whether we can update the move timer in "Go". strict_uci_timing_ = options_.Get(kStrictUciTiming); diff --git a/src/neural/memcache.cc b/src/neural/memcache.cc new file mode 100644 index 0000000000..306e021b13 --- /dev/null +++ b/src/neural/memcache.cc @@ -0,0 +1,153 @@ +/* + This file is part of Leela Chess Zero. + Copyright (C) 2025 The LCZero Authors + + Leela Chess is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Leela Chess is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Leela Chess. If not, see . + + Additional permission under GNU GPL version 3 section 7 + + If you modify this Program, or any covered work, by linking or + combining it with NVIDIA Corporation's libraries from the NVIDIA CUDA + Toolkit and the NVIDIA CUDA Deep Neural Network library (or a + modified version of those libraries), containing parts covered by the + terms of the respective license agreement, the licensors of this + Program grant you additional permission to convey the resulting work. +*/ + +#include "neural/memcache.h" + +#include "neural/cache.h" +#include "utils/smallarray.h" + +namespace lczero { +namespace { + +// TODO For now it uses the hash of the current position, ignoring repetitions +// and history. We'll likely need to have configurable hash function that we'll +// also reuse as a tree hash key. +uint64_t ComputeEvalPositionHash(const EvalPosition& pos) { + return pos.pos.back().Hash(); +} + +struct CachedValue { + float q; + float d; + float m; + std::unique_ptr p; +}; + +void CachedValueToEvalResult(const CachedValue& cv, const EvalResultPtr& ptr) { + if (ptr.d) *ptr.d = cv.d; + if (ptr.q) *ptr.q = cv.q; + if (ptr.m) *ptr.m = cv.m; + std::copy(cv.p.get(), cv.p.get() + ptr.p.size(), ptr.p.begin()); +} + +class MemCache : public Backend { + public: + MemCache(std::unique_ptr wrapped, size_t capacity) + : wrapped_backend_(std::move(wrapped)), + cache_(capacity), + max_batch_size_(wrapped_backend_->GetAttributes().maximum_batch_size) {} + + BackendAttributes GetAttributes() const override { + return wrapped_backend_->GetAttributes(); + } + std::unique_ptr CreateComputation() override; + std::optional GetCachedEvaluation(const EvalPosition&) override; + + private: + std::unique_ptr wrapped_backend_; + HashKeyedCache cache_; + const size_t max_batch_size_; + friend class MemCacheComputation; +}; + +class MemCacheComputation : public BackendComputation { + public: + MemCacheComputation(std::unique_ptr wrapped_computation, + MemCache* memcache) + : wrapped_computation_(std::move(wrapped_computation)), + memcache_(memcache) { + keys_.reserve(memcache_->max_batch_size_); + values_.reserve(memcache_->max_batch_size_); + result_ptrs_.reserve(memcache_->max_batch_size_); + } + + private: + size_t UsedBatchSize() const override { + return wrapped_computation_->UsedBatchSize(); + } + virtual AddInputResult AddInput(const EvalPosition& pos, + EvalResultPtr result) override { + const uint64_t hash = ComputeEvalPositionHash(pos); + { + HashKeyedCacheLock lock(&memcache_->cache_, hash); + if (lock.holds_value()) { + CachedValueToEvalResult(**lock, result); + return AddInputResult::FETCHED_IMMEDIATELY; + } + } + keys_.push_back(hash); + auto value = std::make_unique(); + value->p.reset(new float[result.p.size()]); + result_ptrs_.push_back(result); + return wrapped_computation_->AddInput( + pos, EvalResultPtr{&value->q, + &value->d, + &value->m, + {value->p.get(), pos.legal_moves.size()}}); + } + + virtual void ComputeBlocking() override { + wrapped_computation_->ComputeBlocking(); + for (size_t i = 0; i < keys_.size(); ++i) { + CachedValueToEvalResult(*values_[i], result_ptrs_[i]); + memcache_->cache_.Insert(keys_[i], std::move(values_[i])); + } + } + + std::unique_ptr wrapped_computation_; + std::vector keys_; + std::vector> values_; + std::vector result_ptrs_; + MemCache* memcache_; +}; + +std::unique_ptr MemCache::CreateComputation() { + return std::make_unique( + wrapped_backend_->CreateComputation(), this); +} +std::optional MemCache::GetCachedEvaluation( + const EvalPosition& pos) { + const uint64_t hash = ComputeEvalPositionHash(pos); + HashKeyedCacheLock lock(&cache_, hash); + if (!lock.holds_value()) return std::nullopt; + EvalResult result; + result.d = lock->d; + result.q = lock->q; + result.m = lock->m; + std::copy(lock->p.get(), lock->p.get() + pos.legal_moves.size(), + result.p.begin()); + return result; +} + +} // namespace + +std::unique_ptr CreateMemCache(std::unique_ptr wrapped, + size_t capacity) { + return std::make_unique(std::move(wrapped), capacity); +} + +} // namespace lczero \ No newline at end of file diff --git a/src/neural/memcache.h b/src/neural/memcache.h new file mode 100644 index 0000000000..841504c587 --- /dev/null +++ b/src/neural/memcache.h @@ -0,0 +1,40 @@ +/* + This file is part of Leela Chess Zero. + Copyright (C) 2025 The LCZero Authors + + Leela Chess is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Leela Chess is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Leela Chess. If not, see . + + Additional permission under GNU GPL version 3 section 7 + + If you modify this Program, or any covered work, by linking or + combining it with NVIDIA Corporation's libraries from the NVIDIA CUDA + Toolkit and the NVIDIA CUDA Deep Neural Network library (or a + modified version of those libraries), containing parts covered by the + terms of the respective license agreement, the licensors of this + Program grant you additional permission to convey the resulting work. +*/ + +#pragma once + +#include "neural/backend.h" + +namespace lczero { + +// Creates a caching backend wrapper, which returns values immediately if they +// are found, and forwards the request to the wrapped backend otherwise (and +// caches the result). +std::unique_ptr CreateMemCache(std::unique_ptr parent, + size_t capacity); + +} // namespace lczero \ No newline at end of file diff --git a/src/neural/shared_params.cc b/src/neural/shared_params.cc index 3606042d0b..25a82e80ce 100644 --- a/src/neural/shared_params.cc +++ b/src/neural/shared_params.cc @@ -53,6 +53,10 @@ const OptionId SharedBackendParams::kBackendOptionsId{ "Parameters of neural network backend. " "Exact parameters differ per backend.", 'o'}; +const OptionId SharedBackendParams::kNNCacheSizeId{ + "nncache", "NNCacheSize", + "Number of positions to store in a memory cache. A large cache can speed " + "up searching, but takes memory."}; void SharedBackendParams::Populate(OptionsParser* options) { options->Add(kPolicySoftmaxTemp, 0.1f, 10.0f) = 1.359f; @@ -68,6 +72,8 @@ void SharedBackendParams::Populate(OptionsParser* options) { options->Add(SharedBackendParams::kBackendId, backends) = backends.empty() ? "" : backends[0]; options->Add(SharedBackendParams::kBackendOptionsId); + options->Add(SharedBackendParams::kNNCacheSizeId, 0, 999999999) = + 2000000; } } // namespace lczero \ No newline at end of file diff --git a/src/neural/shared_params.h b/src/neural/shared_params.h index 5d0e8fe3cd..7a5a8c1b68 100644 --- a/src/neural/shared_params.h +++ b/src/neural/shared_params.h @@ -43,6 +43,7 @@ struct SharedBackendParams { static const OptionId kWeightsId; static const OptionId kBackendId; static const OptionId kBackendOptionsId; + static const OptionId kNNCacheSizeId; static void Populate(OptionsParser*); diff --git a/src/search/classic/stoppers/common.cc b/src/search/classic/stoppers/common.cc index ac8efae588..96f4a6e98b 100644 --- a/src/search/classic/stoppers/common.cc +++ b/src/search/classic/stoppers/common.cc @@ -27,14 +27,11 @@ #include "search/classic/stoppers/common.h" +#include "neural/shared_params.h" + namespace lczero { namespace classic { -const OptionId kNNCacheSizeId{ - "nncache", "NNCacheSize", - "Number of positions to store in a memory cache. A large cache can speed " - "up searching, but takes memory."}; - namespace { const OptionId kRamLimitMbId{ "ramlimit-mb", "RamLimitMb", @@ -117,7 +114,8 @@ void PopulateCommonUciStoppers(ChainedSearchStopper* stopper, const bool infinite = params.infinite || params.ponder || params.mate; // RAM limit watching stopper. - const auto cache_size_mb = options.Get(kNNCacheSizeId); + const auto cache_size_mb = + options.Get(SharedBackendParams::kNNCacheSizeId); const int ram_limit = options.Get(kRamLimitMbId); if (ram_limit) { stopper->AddStopper(std::make_unique( diff --git a/src/search/classic/stoppers/common.h b/src/search/classic/stoppers/common.h index 1be3571811..18bc6e877e 100644 --- a/src/search/classic/stoppers/common.h +++ b/src/search/classic/stoppers/common.h @@ -37,10 +37,6 @@ namespace classic { enum class RunType { kUci, kSimpleUci, kSelfplay }; void PopulateCommonStopperOptions(RunType for_what, OptionsParser* options); -// Option ID for a cache size. It's used from multiple places and there's no -// really nice place to declare, so let it be here. -extern const OptionId kNNCacheSizeId; - // Populates KLDGain and SmartPruning stoppers. void PopulateIntrinsicStoppers(ChainedSearchStopper* stopper, const OptionsDict& options); diff --git a/src/selfplay/tournament.cc b/src/selfplay/tournament.cc index 7d4be9952a..73c579c7fb 100644 --- a/src/selfplay/tournament.cc +++ b/src/selfplay/tournament.cc @@ -113,7 +113,6 @@ void SelfPlayTournament::PopulateOptions(OptionsParser* options) { SharedBackendParams::Populate(options); options->Add(kThreadsId, 1, 8) = 1; - options->Add(classic::kNNCacheSizeId, 0, 999999999) = 2000000; classic::SearchParams::Populate(options); options->Add(kShareTreesId) = true; @@ -225,13 +224,14 @@ SelfPlayTournament::SelfPlayTournament( } // Initializing cache. - cache_[0] = std::make_shared( - options.GetSubdict("player1").Get(classic::kNNCacheSizeId)); + cache_[0] = std::make_shared(options.GetSubdict("player1").Get( + SharedBackendParams::kNNCacheSizeId)); if (kShareTree) { cache_[1] = cache_[0]; } else { - cache_[1] = std::make_shared( - options.GetSubdict("player2").Get(classic::kNNCacheSizeId)); + cache_[1] = + std::make_shared(options.GetSubdict("player2").Get( + SharedBackendParams::kNNCacheSizeId)); } // SearchLimits. diff --git a/src/tools/benchmark.cc b/src/tools/benchmark.cc index e0debb969e..0a6b5b2778 100644 --- a/src/tools/benchmark.cc +++ b/src/tools/benchmark.cc @@ -52,7 +52,8 @@ void Benchmark::Run() { OptionsParser options; SharedBackendParams::Populate(&options); options.Add(kThreadsOptionId, 1, 128) = kDefaultThreads; - options.Add(classic::kNNCacheSizeId, 0, 999999999) = 200000; + options.GetMutableDefaultsOptions()->Set(SharedBackendParams::kNNCacheSizeId, + 200000); classic::SearchParams::Populate(&options); options.Add(kNodesId, -1, 999999999) = -1; @@ -98,7 +99,8 @@ void Benchmark::Run() { } NNCache cache; - cache.SetCapacity(option_dict.Get(classic::kNNCacheSizeId)); + cache.SetCapacity( + option_dict.Get(SharedBackendParams::kNNCacheSizeId)); classic::NodeTree tree; tree.ResetToPosition(position, {}); diff --git a/src/utils/cache.h b/src/utils/cache.h index 763033c3f8..e2a703a6d0 100644 --- a/src/utils/cache.h +++ b/src/utils/cache.h @@ -150,8 +150,7 @@ class HashKeyedCache { size_t idx = key % hash_.size(); while (true) { if (!hash_[idx].in_use) break; - if (hash_[idx].key == key && - hash_[idx].value.get() == value) { + if (hash_[idx].key == key && hash_[idx].value.get() == value) { --hash_[idx].pins; return; } @@ -301,6 +300,7 @@ class HashKeyedCacheLock { HashKeyedCacheLock(const HashKeyedCacheLock&) = delete; // Returns whether lock holds any value. + bool holds_value() const { return value_; } operator bool() const { return value_; } // Gets the value. From 4c1f63ef5890f3bc08a45a2ac7a3cb8c12d71724 Mon Sep 17 00:00:00 2001 From: Alexander Lyashuk Date: Sat, 4 Jan 2025 22:27:49 +0100 Subject: [PATCH 019/212] Plug new Search and Backend APIs to the engine (#2107) --- meson.build | 1 + src/chess/gamestate.cc | 6 ++- src/chess/gamestate.h | 4 +- src/chess/position.cc | 6 +++ src/chess/position.h | 7 ++- src/engine.cc | 90 +++++++++++++++++++++++++++++++ src/engine.h | 61 +++++++++++++++++++++ src/engine_classic.cc | 6 +-- src/engine_classic.h | 5 +- src/engine_loop.cc | 21 ++++---- src/engine_loop.h | 4 +- src/main.cc | 52 ++++++++++++++---- src/neural/backend.cc | 1 + src/neural/register.cc | 2 +- src/neural/register.h | 2 +- src/neural/wrapper.cc | 2 +- src/search/instamove/instamove.cc | 4 +- src/search/instamove/instamove.h | 1 + src/search/register.cc | 18 +++++++ src/search/register.h | 6 +++ src/search/search.h | 2 + src/utils/commandline.cc | 2 +- src/utils/commandline.h | 2 +- 23 files changed, 264 insertions(+), 41 deletions(-) create mode 100644 src/engine.cc create mode 100644 src/engine.h diff --git a/meson.build b/meson.build index 9b32c8cfba..f36d4cbb25 100644 --- a/meson.build +++ b/meson.build @@ -188,6 +188,7 @@ common_files += [ files += [ 'src/engine_classic.cc', 'src/engine_loop.cc', + 'src/engine.cc', 'src/neural/backends/network_check.cc', 'src/neural/backends/network_demux.cc', 'src/neural/backends/network_mux.cc', diff --git a/src/chess/gamestate.cc b/src/chess/gamestate.cc index 0a8cab2c52..4aca47f94e 100644 --- a/src/chess/gamestate.cc +++ b/src/chess/gamestate.cc @@ -43,7 +43,11 @@ std::vector GameState::GetPositions() const { positions.reserve(moves.size() + 1); positions.push_back(startpos); std::transform(moves.begin(), moves.end(), std::back_inserter(positions), - [&](const Move& m) { return Position(positions.back(), m); }); + [&](Move m) { + const Position& prev_pos = positions.back(); + if (prev_pos.IsBlackToMove()) m.Mirror(); + return Position(positions.back(), m); + }); return positions; } diff --git a/src/chess/gamestate.h b/src/chess/gamestate.h index e473813c2e..e584b2d30b 100644 --- a/src/chess/gamestate.h +++ b/src/chess/gamestate.h @@ -27,7 +27,7 @@ #pragma once -#include +#include #include "chess/position.h" @@ -37,7 +37,7 @@ namespace lczero { // state. Somewhat mirrors usi `position moves ...` command. struct GameState { Position startpos; - std::span moves; + std::vector moves; // Returns the position of the last move in the list. Position CurrentPosition() const; diff --git a/src/chess/position.cc b/src/chess/position.cc index fcc69cf278..571fd5bbe2 100644 --- a/src/chess/position.cc +++ b/src/chess/position.cc @@ -74,6 +74,12 @@ Position::Position(const ChessBoard& board, int rule50_ply, int game_ply) us_board_ = board; } +Position Position::FromFen(std::string_view fen) { + Position pos; + pos.us_board_.SetFromFen(std::string(fen), &pos.rule50_ply_, &pos.ply_count_); + return pos; +} + uint64_t Position::Hash() const { return HashCat({us_board_.Hash(), static_cast(repetitions_)}); } diff --git a/src/chess/position.h b/src/chess/position.h index f56f819824..dc679606fd 100644 --- a/src/chess/position.h +++ b/src/chess/position.h @@ -29,6 +29,7 @@ #include #include +#include #include "chess/board.h" @@ -41,6 +42,8 @@ class Position { Position(const Position& parent, Move m); // From particular position. Position(const ChessBoard& board, int rule50_ply, int game_ply); + // From fen. + static Position FromFen(std::string_view fen); uint64_t Hash() const; bool IsBlackToMove() const { return us_board_.flipped(); } @@ -76,9 +79,9 @@ class Position { // How many half-moves without capture or pawn move was there. int rule50_ply_ = 0; // How many repetitions this position had before. For new positions it's 0. - int repetitions_; + int repetitions_ = 0; // How many half-moves since the position was repeated or 0. - int cycle_length_; + int cycle_length_ = 0; // number of half-moves since beginning of the game. int ply_count_ = 0; }; diff --git a/src/engine.cc b/src/engine.cc new file mode 100644 index 0000000000..10f9d52659 --- /dev/null +++ b/src/engine.cc @@ -0,0 +1,90 @@ +/* + This file is part of Leela Chess Zero. + Copyright (C) 2024 The LCZero Authors + + Leela Chess is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Leela Chess is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Leela Chess. If not, see . + + Additional permission under GNU GPL version 3 section 7 + + If you modify this Program, or any covered work, by linking or + combining it with NVIDIA Corporation's libraries from the NVIDIA CUDA + Toolkit and the NVIDIA CUDA Deep Neural Network library (or a + modified version of those libraries), containing parts covered by the + terms of the respective license agreement, the licensors of this + Program grant you additional permission to convey the resulting work. +*/ + +#include "engine.h" + +#include + +#include "chess/gamestate.h" +#include "chess/position.h" +#include "neural/backend.h" +#include "neural/register.h" + +namespace lczero { + +Engine::Engine(std::unique_ptr env, const OptionsDict& opts) + : options_(opts), search_env_(std::move(env)) {} + +Engine::~Engine() {} + +namespace { +GameState MakeGameState(const std::string& fen, + const std::vector& moves) { + GameState state; + state.startpos = Position::FromFen(fen); + state.moves.reserve(moves.size()); + bool is_black = state.startpos.IsBlackToMove(); + std::transform(moves.begin(), moves.end(), std::back_inserter(state.moves), + [&](const std::string& move) { + return Move(move, is_black); + is_black = !is_black; + }); + return state; +} +} // namespace + +void Engine::EnsureSearchStopped() { + if (!search_) return; + search_->Abort(); + search_->Wait(); +} + +void Engine::EnsureBackendCreated() { + if (backend_) return; + backend_ = BackendManager::Get()->CreateFromParams(options_); + search_env_->SetBackend(backend_.get()); +} + +void Engine::SetPosition(const std::string& fen, + const std::vector& moves) { + EnsureBackendCreated(); + EnsureSearchStopped(); + search_ = search_env_->CreateSearch(MakeGameState(fen, moves)); +} + +void Engine::NewGame() { SetPosition(ChessBoard::kStartposFen, {}); } + +void Engine::Go(const GoParams& params) { + if (!search_) NewGame(); + search_->Start(params); +} + +void Engine::Stop() { + if (search_) search_->Stop(); +} + +} // namespace lczero diff --git a/src/engine.h b/src/engine.h new file mode 100644 index 0000000000..059a819d0d --- /dev/null +++ b/src/engine.h @@ -0,0 +1,61 @@ +/* + This file is part of Leela Chess Zero. + Copyright (C) 2024 The LCZero Authors + + Leela Chess is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Leela Chess is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Leela Chess. If not, see . + + Additional permission under GNU GPL version 3 section 7 + + If you modify this Program, or any covered work, by linking or + combining it with NVIDIA Corporation's libraries from the NVIDIA CUDA + Toolkit and the NVIDIA CUDA Deep Neural Network library (or a + modified version of those libraries), containing parts covered by the + terms of the respective license agreement, the licensors of this + Program grant you additional permission to convey the resulting work. +*/ + +#pragma once + +#include + +#include "engine_loop.h" +#include "search/search.h" + +namespace lczero { + +class Engine : public EngineControllerBase { + public: + Engine(std::unique_ptr, const OptionsDict&); + ~Engine() override; + + private: + void EnsureReady() override {}; + void NewGame() override; + void SetPosition(const std::string& fen, + const std::vector& moves) override; + void Go(const GoParams& params) override; + void PonderHit() override {} + void Stop() override; + + private: + void EnsureBackendCreated(); + void EnsureSearchStopped(); + + const OptionsDict& options_; + std::unique_ptr search_env_; + std::unique_ptr search_; + std::unique_ptr backend_; +}; + +} // namespace lczero \ No newline at end of file diff --git a/src/engine_classic.cc b/src/engine_classic.cc index 44d7c96870..28dc99a980 100644 --- a/src/engine_classic.cc +++ b/src/engine_classic.cc @@ -87,10 +87,10 @@ MoveList StringsToMovelist(const std::vector& moves, } // namespace -EngineClassic::EngineClassic(std::unique_ptr uci_responder, +EngineClassic::EngineClassic(UciResponder& uci_responder, const OptionsDict& options) : options_(options), - uci_responder_(std::move(uci_responder)), + uci_responder_(&uci_responder), current_position_{ChessBoard::kStartposFen, {}} {} void EngineClassic::PopulateOptions(OptionsParser* options) { @@ -344,7 +344,7 @@ void EngineClassic::Go(const GoParams& params) { go_params_ = params; std::unique_ptr responder = - std::make_unique(uci_responder_.get()); + std::make_unique(uci_responder_); // Setting up current position, now that it's known whether it's ponder or // not. diff --git a/src/engine_classic.h b/src/engine_classic.h index e74b6172c8..2894c40023 100644 --- a/src/engine_classic.h +++ b/src/engine_classic.h @@ -46,8 +46,7 @@ struct CurrentPosition { class EngineClassic : public EngineControllerBase { public: - EngineClassic(std::unique_ptr uci_responder, - const OptionsDict& options); + EngineClassic(UciResponder& uci_responder, const OptionsDict& options); ~EngineClassic() { // Make sure search is destructed first, and it still may be running in @@ -85,7 +84,7 @@ class EngineClassic : public EngineControllerBase { const OptionsDict& options_; - std::unique_ptr uci_responder_; + UciResponder* uci_responder_; // Locked means that there is some work to wait before responding readyok. RpSharedMutex busy_mutex_; diff --git a/src/engine_loop.cc b/src/engine_loop.cc index c59f572b47..bd39806942 100644 --- a/src/engine_loop.cc +++ b/src/engine_loop.cc @@ -40,17 +40,16 @@ const OptionId kPreload{"preload", "", "Initialize backend and load net on engine startup."}; } // namespace -EngineLoop::EngineLoop(std::unique_ptr options, - std::function( - std::unique_ptr uci_responder, - const OptionsDict& options)> - engine_factory) - : options_(std::move(options)), - engine_(engine_factory( - std::make_unique( - std::bind(&UciLoop::SendBestMove, this, std::placeholders::_1), - std::bind(&UciLoop::SendInfo, this, std::placeholders::_1)), - options_->GetOptionsDict())) { +EngineLoop::EngineLoop( + std::unique_ptr options, + std::function( + UciResponder& uci_responder, const OptionsDict& options)> + engine_factory) + : uci_responder_(std::make_unique( + [&](auto&& arg) { return SendBestMove(arg); }, + [&](auto&& arg) { return SendInfo(arg); })), + options_(std::move(options)), + engine_(engine_factory(*uci_responder_, options_->GetOptionsDict())) { options_->Add(kLogFileId); options_->Add(kPreload) = false; SharedBackendParams::Populate(options_.get()); diff --git a/src/engine_loop.h b/src/engine_loop.h index b9ace9fab2..bff7f639e9 100644 --- a/src/engine_loop.h +++ b/src/engine_loop.h @@ -60,8 +60,7 @@ class EngineLoop : public UciLoop { public: EngineLoop(std::unique_ptr options, std::function( - std::unique_ptr uci_responder, - const OptionsDict& options)> + UciResponder& uci_responder, const OptionsDict& options)> engine_factory); void RunLoop() override; @@ -77,6 +76,7 @@ class EngineLoop : public UciLoop { void CmdStop() override; private: + std::unique_ptr uci_responder_; std::unique_ptr options_; std::unique_ptr engine_; }; diff --git a/src/main.cc b/src/main.cc index 01c182e4ee..2b8f5d0d10 100644 --- a/src/main.cc +++ b/src/main.cc @@ -26,7 +26,9 @@ */ #include "chess/board.h" +#include "engine.h" #include "engine_classic.h" +#include "search/register.h" #include "selfplay/loop.h" #include "tools/backendbench.h" #include "tools/benchmark.h" @@ -62,6 +64,13 @@ int main(int argc, const char** argv) { CommandLine::RegisterMode("describenet", "Shows details about the Leela network."); + for (const std::string_view search_name : + SearchManager::Get()->GetSearchNames()) { + CommandLine::RegisterMode( + std::string(search_name), + "Use \"" + std::string(search_name) + "\" search"); + } + if (CommandLine::ConsumeCommand("selfplay")) { // Selfplay mode. SelfPlayLoop loop; @@ -81,18 +90,39 @@ int main(int argc, const char** argv) { } else if (CommandLine::ConsumeCommand("describenet")) { lczero::DescribeNetworkCmd(); } else { - // Consuming optional "uci" mode. - CommandLine::ConsumeCommand("uci"); - // Ordinary UCI engine. auto options_parser = std::make_unique(); - EngineClassic::PopulateOptions(options_parser.get()); - EngineLoop loop(std::move(options_parser), - [](std::unique_ptr uci_responder, - const OptionsDict& options) { - return std::make_unique( - std::move(uci_responder), options); - }); - loop.RunLoop(); + + bool used_new_search = false; + for (const std::string_view search_name : + SearchManager::Get()->GetSearchNames()) { + if (CommandLine::ConsumeCommand(search_name)) { + used_new_search = true; + SearchFactory* factory = + SearchManager::Get()->GetFactoryByName(search_name); + factory->PopulateParams(options_parser.get()); + EngineLoop loop( + std::move(options_parser), [factory](UciResponder& uci_responder, + const OptionsDict& options) { + return std::make_unique( + factory->CreateEnvironment(&uci_responder, &options), + options); + }); + loop.RunLoop(); + } + } + + if (!used_new_search) { + // Consuming optional "uci" mode. + CommandLine::ConsumeCommand("uci"); + // Ordinary UCI engine. + EngineClassic::PopulateOptions(options_parser.get()); + EngineLoop loop( + std::move(options_parser), + [](UciResponder& uci_responder, const OptionsDict& options) { + return std::make_unique(uci_responder, options); + }); + loop.RunLoop(); + } } } catch (std::exception& e) { std::cerr << "Unhandled exception: " << e.what() << std::endl; diff --git a/src/neural/backend.cc b/src/neural/backend.cc index 5ee0f61006..9da6ba5791 100644 --- a/src/neural/backend.cc +++ b/src/neural/backend.cc @@ -37,6 +37,7 @@ std::vector Backend::EvaluateBatch( for (const EvalPosition& pos : positions) { results.emplace_back(); EvalResult& result = results.back(); + result.p.resize(pos.legal_moves.size()); computation->AddInput( pos, EvalResultPtr{&result.q, &result.d, &result.m, std::span(result.p.data(), result.p.size())}); diff --git a/src/neural/register.cc b/src/neural/register.cc index 8048c07dd7..14a0149e03 100644 --- a/src/neural/register.cc +++ b/src/neural/register.cc @@ -38,7 +38,7 @@ BackendManager* BackendManager::Get() { return &instance; } -std::vector BackendManager::GetBackendsList() const { +std::vector BackendManager::GetBackendNames() const { std::vector> priority_and_names; std::transform(algorithms_.begin(), algorithms_.end(), std::back_inserter(priority_and_names), diff --git a/src/neural/register.h b/src/neural/register.h index 63f4cb620e..bc615d1434 100644 --- a/src/neural/register.h +++ b/src/neural/register.h @@ -42,7 +42,7 @@ class BackendManager { } // Returns list of backend names, sorted by priority (higher priority first). - std::vector GetBackendsList() const; + std::vector GetBackendNames() const; // Creates a backend from the parameters. Extracts the weights file and the // backend from the options. diff --git a/src/neural/wrapper.cc b/src/neural/wrapper.cc index 0108ce96a7..77099ed9cc 100644 --- a/src/neural/wrapper.cc +++ b/src/neural/wrapper.cc @@ -89,7 +89,7 @@ class NetworkAsBackendComputation : public BackendComputation { EvalResultPtr result) override { int transform; computation_->AddInput(EncodePositionForNN(backend_->input_format_, pos.pos, - 8, FillEmptyHistory::FEN_ONLY, + 8, backend_->fill_empty_history_, &transform)); results_.push_back(result); moves_.emplace_back(pos.legal_moves.begin(), pos.legal_moves.end()); diff --git a/src/search/instamove/instamove.cc b/src/search/instamove/instamove.cc index ab61436d85..732f733447 100644 --- a/src/search/instamove/instamove.cc +++ b/src/search/instamove/instamove.cc @@ -50,7 +50,9 @@ class PolicyHeadSearch : public InstamoveSearch { std::vector{EvalPosition{positions, legal_moves}}); const size_t best_move_idx = std::max_element(res[0].p.begin(), res[0].p.end()) - res[0].p.begin(); - return legal_moves[best_move_idx]; + Move best_move = legal_moves[best_move_idx]; + if (positions.back().IsBlackToMove()) best_move.Mirror(); + return best_move; } private: diff --git a/src/search/instamove/instamove.h b/src/search/instamove/instamove.h index 32f9e7d461..fea0cf4d16 100644 --- a/src/search/instamove/instamove.h +++ b/src/search/instamove/instamove.h @@ -45,6 +45,7 @@ class InstamoveSearch : public SearchBase { virtual Move GetBestMove() = 0; void Start(const GoParams& go_params) final { + responded_bestmove_.store(false, std::memory_order_relaxed); bestmove_ = GetBestMove(); if (!go_params.infinite && !go_params.ponder) RespondBestMove(); } diff --git a/src/search/register.cc b/src/search/register.cc index fee7b82bff..203d4fa8a9 100644 --- a/src/search/register.cc +++ b/src/search/register.cc @@ -27,6 +27,8 @@ #include "search/register.h" +#include + namespace lczero { SearchManager* SearchManager::Get() { @@ -38,4 +40,20 @@ void SearchManager::AddSearchFactory(std::unique_ptr algorithm) { algorithms_.push_back(std::move(algorithm)); } +std::vector SearchManager::GetSearchNames() const { + std::vector res; + res.reserve(algorithms_.size()); + std::transform(algorithms_.begin(), algorithms_.end(), + std::back_inserter(res), + [](const auto& alg) { return alg->GetName(); }); + return res; +} + +SearchFactory* SearchManager::GetFactoryByName(std::string_view name) const { + auto it = + std::find_if(algorithms_.begin(), algorithms_.end(), + [name](const auto& alg) { return alg->GetName() == name; }); + return it == algorithms_.end() ? nullptr : it->get(); +} + } // namespace lczero \ No newline at end of file diff --git a/src/search/register.h b/src/search/register.h index d96ad00d37..7ad1362b91 100644 --- a/src/search/register.h +++ b/src/search/register.h @@ -42,6 +42,12 @@ class SearchManager { static SearchManager* Get(); void AddSearchFactory(std::unique_ptr); + std::vector GetSearchNames() const; + + // Returns the factory for the given algorithm name. Returns nullptr if not + // found. + SearchFactory* GetFactoryByName(std::string_view name) const; + struct Register { Register(std::unique_ptr factory) { SearchManager::Get()->AddSearchFactory(std::move(factory)); diff --git a/src/search/search.h b/src/search/search.h index ccdef8d4a5..9ba58cdc59 100644 --- a/src/search/search.h +++ b/src/search/search.h @@ -99,6 +99,8 @@ class SearchEnvironment { virtual void NewGame() {} // Sets the position to search from in the future searches. virtual std::unique_ptr CreateSearch(const GameState&) = 0; + // Sets the backend to be used by the search. + virtual void SetBackend(Backend* backend) { context_.backend = backend; } protected: SearchContext context_; diff --git a/src/utils/commandline.cc b/src/utils/commandline.cc index 22df960462..48f11351be 100644 --- a/src/utils/commandline.cc +++ b/src/utils/commandline.cc @@ -56,7 +56,7 @@ void CommandLine::Init(int argc, const char** argv) { LOGFILE << "Command line: " << binary_ << params.str(); } -bool CommandLine::ConsumeCommand(const std::string& command) { +bool CommandLine::ConsumeCommand(std::string_view command) { if (arguments_.empty()) return false; if (arguments_[0] != command) return false; arguments_.erase(arguments_.begin()); diff --git a/src/utils/commandline.h b/src/utils/commandline.h index 205f155b26..c9621212b2 100644 --- a/src/utils/commandline.h +++ b/src/utils/commandline.h @@ -47,7 +47,7 @@ class CommandLine { // If the first command line parameter is @command, remove it and return // true. Otherwise return false. - static bool ConsumeCommand(const std::string& command); + static bool ConsumeCommand(std::string_view command); // Command line arguments. static const std::vector& Arguments() { return arguments_; } From 7b0ef8d511746eefcf042ae84cf7b3fb2de13400 Mon Sep 17 00:00:00 2001 From: borg323 <39573933+borg323@users.noreply.github.com> Date: Sun, 12 Jan 2025 01:21:05 +0200 Subject: [PATCH 020/212] fix appveyor build (#2110) --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 1afa3789ea..0f1538840a 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -47,7 +47,7 @@ install: - cmd: set NET_HASH=3e3444370b9fe413244fdc79671a490e19b93d3cca1669710ffeac890493d198 - cmd: IF NOT %OPENCL%==true IF NOT %DX%==true set NET=791556 - cmd: IF NOT %OPENCL%==true IF NOT %DX%==true set NET_HASH=f404e156ceb2882470fd8c032b8754af0fa0b71168328912eaef14671a256e34 -- cmd: call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" amd64 +#- cmd: call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" amd64 - cmd: set DNNL_NAME=dnnl_win_1.5.0_cpu_vcomp - cmd: IF %NAME%==cpu-dnnl IF NOT EXIST C:\cache\%DNNL_NAME% appveyor DownloadFile https://github.com/oneapi-src/oneDNN/releases/download/v1.5/dnnl_win_1.5.0_cpu_vcomp.zip - cmd: IF %NAME%==cpu-dnnl IF NOT EXIST C:\cache\%DNNL_NAME% 7z x dnnl_win_1.5.0_cpu_vcomp.zip -oC:\cache From 6d578c0154a5338d10fefe0449705d255c5d0157 Mon Sep 17 00:00:00 2001 From: Alexander Lyashuk Date: Fri, 24 Jan 2025 17:51:06 +0100 Subject: [PATCH 021/212] Add a makefile for OpenBench (#2113) --- OpenBench/Makefile | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 OpenBench/Makefile diff --git a/OpenBench/Makefile b/OpenBench/Makefile new file mode 100644 index 0000000000..2eb5ead5d9 --- /dev/null +++ b/OpenBench/Makefile @@ -0,0 +1,7 @@ + +ifndef EXE + EXE = $(CURDIR)/lc0 +endif + +all: + cd .. && sh ./build.sh && mv build/release/lc0 $(EXE) From 2da3a5b52307958eea2dcc82be0cc6fa8d434ba7 Mon Sep 17 00:00:00 2001 From: Alexander Lyashuk Date: Sat, 25 Jan 2025 22:28:21 +0100 Subject: [PATCH 022/212] Fix openbench-specific issues (#2115) --- OpenBench/Makefile | 10 ++++++++-- src/main.cc | 3 ++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/OpenBench/Makefile b/OpenBench/Makefile index 2eb5ead5d9..5e6277d7ff 100644 --- a/OpenBench/Makefile +++ b/OpenBench/Makefile @@ -1,7 +1,13 @@ - ifndef EXE EXE = $(CURDIR)/lc0 endif all: - cd .. && sh ./build.sh && mv build/release/lc0 $(EXE) +ifdef EVALFILE + ../build.sh -Dembed=true && mv ../build/release/lc0 $(EXE) + cat $(EVALFILE) >> $(EXE) + perl -e "printf '%sLc0!', pack('V', -s '$(EVALFILE)')" >> $(EXE) +else + ../build.sh && mv ../build/release/lc0 $(EXE) +endif + diff --git a/src/main.cc b/src/main.cc index 2b8f5d0d10..918ba2e2b5 100644 --- a/src/main.cc +++ b/src/main.cc @@ -75,7 +75,8 @@ int main(int argc, const char** argv) { // Selfplay mode. SelfPlayLoop loop; loop.RunLoop(); - } else if (CommandLine::ConsumeCommand("benchmark")) { + } else if (CommandLine::ConsumeCommand("benchmark") || + CommandLine::ConsumeCommand("bench")) { // Benchmark mode. Benchmark benchmark; benchmark.Run(); From 142ffcef9d8711dd9417a107d12388a935c0929b Mon Sep 17 00:00:00 2001 From: Alexander Lyashuk Date: Sun, 2 Feb 2025 14:10:08 +0100 Subject: [PATCH 023/212] Chmod build.sh before running. (#2117) --- OpenBench/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/OpenBench/Makefile b/OpenBench/Makefile index 5e6277d7ff..dd61aaebcf 100644 --- a/OpenBench/Makefile +++ b/OpenBench/Makefile @@ -3,6 +3,7 @@ ifndef EXE endif all: + chmod +x ../build.sh ifdef EVALFILE ../build.sh -Dembed=true && mv ../build/release/lc0 $(EXE) cat $(EVALFILE) >> $(EXE) From 64d39515a4531b9db8576147e6634f25f54adcff Mon Sep 17 00:00:00 2001 From: Alexander Lyashuk Date: Mon, 3 Feb 2025 13:55:16 +0100 Subject: [PATCH 024/212] Update benchmark defaults for OpenBench (#2118) --- src/tools/benchmark.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tools/benchmark.cc b/src/tools/benchmark.cc index 0a6b5b2778..b3f2debeff 100644 --- a/src/tools/benchmark.cc +++ b/src/tools/benchmark.cc @@ -57,9 +57,9 @@ void Benchmark::Run() { classic::SearchParams::Populate(&options); options.Add(kNodesId, -1, 999999999) = -1; - options.Add(kMovetimeId, -1, 999999999) = 10000; + options.Add(kMovetimeId, -1, 999999999) = 500; options.Add(kFenId) = ""; - options.Add(kNumPositionsId, 1, 34) = 34; + options.Add(kNumPositionsId, 1, 34) = 10; if (!options.ProcessAllFlags()) return; From d97cbc1b610361e067ea6ba59240cca5c851ff9e Mon Sep 17 00:00:00 2001 From: Alexander Lyashuk Date: Fri, 7 Feb 2025 08:31:36 +0100 Subject: [PATCH 025/212] Use `bench` for a short benchmark and `benchmark` for a full one. (#2120) --- src/main.cc | 10 +++++++--- src/tools/benchmark.cc | 11 ++++++++--- src/tools/benchmark.h | 2 +- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/main.cc b/src/main.cc index 918ba2e2b5..5bfd079a0f 100644 --- a/src/main.cc +++ b/src/main.cc @@ -56,6 +56,7 @@ int main(int argc, const char** argv) { CommandLine::RegisterMode("uci", "(default) Act as UCI engine"); CommandLine::RegisterMode("selfplay", "Play games with itself"); CommandLine::RegisterMode("benchmark", "Quick benchmark"); + CommandLine::RegisterMode("bench", "Very quick benchmark"); CommandLine::RegisterMode("backendbench", "Quick benchmark of backend only"); CommandLine::RegisterMode("leela2onnx", "Convert Leela network to ONNX."); @@ -75,11 +76,14 @@ int main(int argc, const char** argv) { // Selfplay mode. SelfPlayLoop loop; loop.RunLoop(); - } else if (CommandLine::ConsumeCommand("benchmark") || - CommandLine::ConsumeCommand("bench")) { - // Benchmark mode. + } else if (CommandLine::ConsumeCommand("benchmark")) { + // Benchmark mode, longer version. Benchmark benchmark; benchmark.Run(); + } else if (CommandLine::ConsumeCommand("bench")) { + // Benchmark mode, shorter version. + Benchmark benchmark; + benchmark.Run(/*run_shorter_benchmark=*/true); } else if (CommandLine::ConsumeCommand("backendbench")) { // Backend Benchmark mode. BackendBenchmark benchmark; diff --git a/src/tools/benchmark.cc b/src/tools/benchmark.cc index b3f2debeff..3564132045 100644 --- a/src/tools/benchmark.cc +++ b/src/tools/benchmark.cc @@ -48,7 +48,7 @@ const OptionId kNumPositionsId{"num-positions", "", "The number of benchmark positions to test."}; } // namespace -void Benchmark::Run() { +void Benchmark::Run(bool run_shorter_benchmark) { OptionsParser options; SharedBackendParams::Populate(&options); options.Add(kThreadsOptionId, 1, 128) = kDefaultThreads; @@ -57,9 +57,14 @@ void Benchmark::Run() { classic::SearchParams::Populate(&options); options.Add(kNodesId, -1, 999999999) = -1; - options.Add(kMovetimeId, -1, 999999999) = 500; options.Add(kFenId) = ""; - options.Add(kNumPositionsId, 1, 34) = 10; + if (run_shorter_benchmark) { + options.Add(kMovetimeId, -1, 999999999) = 500; + options.Add(kNumPositionsId, 1, 34) = 10; + } else { + options.Add(kMovetimeId, -1, 999999999) = 10000; + options.Add(kNumPositionsId, 1, 34) = 34; + } if (!options.ProcessAllFlags()) return; diff --git a/src/tools/benchmark.h b/src/tools/benchmark.h index d14ea6b53d..f6f19754ae 100644 --- a/src/tools/benchmark.h +++ b/src/tools/benchmark.h @@ -78,7 +78,7 @@ class Benchmark{ "3Qb1k1/1r2ppb1/pN1n2q1/Pp1Pp1Pr/4P2p/4BP2/4B1R1/1R5K b - - 11 40" }; - void Run(); + void Run(bool run_shorter_benchmark = false); void OnBestMove(const BestMoveInfo& move); void OnInfo(const std::vector& infos); }; From dfb8fbe03042d05de7abdd627d3614abc8f9fa80 Mon Sep 17 00:00:00 2001 From: Alexander Lyashuk Date: Fri, 7 Feb 2025 08:31:56 +0100 Subject: [PATCH 026/212] Add AUTHORs file (#2116) * Generate AUTHORS file. * Address review comment. --- AUTHORS | 113 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 AUTHORS diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000000..d1fabfddfe --- /dev/null +++ b/AUTHORS @@ -0,0 +1,113 @@ +A-childs-encyclopedia +Adam Treat +Alex Greason +Alexander Lyashuk +Alexis Olson +alice +almaudoh +Aloril +Andrew Grant +Andy Olsen +Ankan +Ankan Banerjee +Anson Hu +Asger Alstrup Palm +baum +benini +borg323 +Boštjan Mejak +Brandon Lin +Brett Holman +Carlo Wood +cn4750 +Cong +Contrad Namiseb (Bonan) +cwbriscoe +danegraphics +Daniel Monroe +Daniel Uranga +Dieter Dobbelaere +dje-dev +Dominik Schlösser +DU-jdto +dubslow +Dubslow +Ed Lee +Epanek +Error323 +evalon32 +exa +exoticorn +F. Huizinga +fischerandom +fohristiwhirl +Francis +Francis Li +Francois +Francois Pays +François Pays +Ganesh Krishnan +GBeauregard +Gian-Carlo Pascutto +gmorenz +Google LLC +gsobala +Hace +Hans Ekbrand +Henrik Forstén +Ikko Eltociear Ashimine +Jack Thomson +James Horsfall Thomas +jjoshua2 +John Newlin +Karl Kfoury +kiilas +Kip Hamiltons +Kovax +Leandro Álvarez González +Linmiao Xu +Lisa Butterfly +Luka Rahne +Marcin Stefaniuk +Martin +Martin Senft +masterkni6 +masterkni666 +Mike Roberts +Naphthalin +nathan-lc0 +Neelesh Jain +nguyenpham +noobpwnftw +Ofek Shochat +oscardssmith +Pan +patrik-ha +PaulJeFi +Pratik Dixit +QxC4eva +Raj +Reece H. Dunn +Ron Wolf +Sami Kiminki +Shreyas Kapur +shtayerc +Simon +slash +students +SunnyWar +TesseractA +Tilps +Timofey Kondrashov +Ting-Hsuan Huang +Tony Su +trre123 +Usman Haider +uyhcire +Valentin +Valeriy Huz +Victor Popovici +Videodr0me +Viren6 +Yan Zhang +zz4032 \ No newline at end of file From 49d9f12238e4dabe476e9eea7135055b5b35a90c Mon Sep 17 00:00:00 2001 From: Alexander Lyashuk Date: Fri, 7 Feb 2025 08:33:59 +0100 Subject: [PATCH 027/212] Make MemCache / Wrapper backends thread-safe (#2112) * Atomic vector * Lockless MemCache * Lockless threadsafe wrapper. * Bugfix * Build fix. * Fixing elo-gaining bug. --- src/neural/memcache.cc | 40 ++++++++++-------- src/neural/wrapper.cc | 44 +++++++++++--------- src/utils/atomic_vector.h | 86 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 134 insertions(+), 36 deletions(-) create mode 100644 src/utils/atomic_vector.h diff --git a/src/neural/memcache.cc b/src/neural/memcache.cc index 306e021b13..b176c94cf7 100644 --- a/src/neural/memcache.cc +++ b/src/neural/memcache.cc @@ -28,6 +28,7 @@ #include "neural/memcache.h" #include "neural/cache.h" +#include "utils/atomic_vector.h" #include "utils/smallarray.h" namespace lczero { @@ -79,11 +80,8 @@ class MemCacheComputation : public BackendComputation { MemCacheComputation(std::unique_ptr wrapped_computation, MemCache* memcache) : wrapped_computation_(std::move(wrapped_computation)), - memcache_(memcache) { - keys_.reserve(memcache_->max_batch_size_); - values_.reserve(memcache_->max_batch_size_); - result_ptrs_.reserve(memcache_->max_batch_size_); - } + memcache_(memcache), + entries_(memcache->max_batch_size_) {} private: size_t UsedBatchSize() const override { @@ -99,10 +97,11 @@ class MemCacheComputation : public BackendComputation { return AddInputResult::FETCHED_IMMEDIATELY; } } - keys_.push_back(hash); - auto value = std::make_unique(); - value->p.reset(new float[result.p.size()]); - result_ptrs_.push_back(result); + size_t entry_idx = entries_.emplace_back( + Entry{hash, std::make_unique(), result}); + auto& value = entries_[entry_idx].value; + value->p.reset(pos.legal_moves.empty() ? nullptr + : new float[pos.legal_moves.size()]); return wrapped_computation_->AddInput( pos, EvalResultPtr{&value->q, &value->d, @@ -112,17 +111,21 @@ class MemCacheComputation : public BackendComputation { virtual void ComputeBlocking() override { wrapped_computation_->ComputeBlocking(); - for (size_t i = 0; i < keys_.size(); ++i) { - CachedValueToEvalResult(*values_[i], result_ptrs_[i]); - memcache_->cache_.Insert(keys_[i], std::move(values_[i])); + for (auto& entry : entries_) { + CachedValueToEvalResult(*entry.value, entry.result_ptr); + memcache_->cache_.Insert(entry.key, std::move(entry.value)); } } + struct Entry { + uint64_t key; + std::unique_ptr value; + EvalResultPtr result_ptr; + }; + std::unique_ptr wrapped_computation_; - std::vector keys_; - std::vector> values_; - std::vector result_ptrs_; MemCache* memcache_; + AtomicVector entries_; }; std::unique_ptr MemCache::CreateComputation() { @@ -138,8 +141,11 @@ std::optional MemCache::GetCachedEvaluation( result.d = lock->d; result.q = lock->q; result.m = lock->m; - std::copy(lock->p.get(), lock->p.get() + pos.legal_moves.size(), - result.p.begin()); + if (lock->p) { + result.p.reserve(pos.legal_moves.size()); + std::copy(lock->p.get(), lock->p.get() + pos.legal_moves.size(), + std::back_inserter(result.p)); + } return result; } diff --git a/src/neural/wrapper.cc b/src/neural/wrapper.cc index 77099ed9cc..4c6d0ed545 100644 --- a/src/neural/wrapper.cc +++ b/src/neural/wrapper.cc @@ -32,6 +32,7 @@ #include "neural/encoder.h" #include "neural/shared_params.h" +#include "utils/atomic_vector.h" #include "utils/fastmath.h" namespace lczero { @@ -77,30 +78,30 @@ class NetworkAsBackend : public Backend { class NetworkAsBackendComputation : public BackendComputation { public: NetworkAsBackendComputation(NetworkAsBackend* backend) - : backend_(backend), computation_(backend_->network_->NewComputation()) { - results_.reserve(backend_->attrs_.maximum_batch_size); - moves_.reserve(backend_->attrs_.maximum_batch_size); - transforms_.reserve(backend_->attrs_.maximum_batch_size); - } + : backend_(backend), + computation_(backend_->network_->NewComputation()), + entries_(backend_->attrs_.maximum_batch_size) {} - size_t UsedBatchSize() const override { return computation_->GetBatchSize(); } + size_t UsedBatchSize() const override { return entries_.size(); } AddInputResult AddInput(const EvalPosition& pos, EvalResultPtr result) override { int transform; - computation_->AddInput(EncodePositionForNN(backend_->input_format_, pos.pos, - 8, backend_->fill_empty_history_, - &transform)); - results_.push_back(result); - moves_.emplace_back(pos.legal_moves.begin(), pos.legal_moves.end()); - transforms_.push_back(transform); + const size_t idx = entries_.emplace_back(Entry{ + .input = EncodePositionForNN(backend_->input_format_, pos.pos, 8, + backend_->fill_empty_history_, &transform), + .legal_moves = MoveList(pos.legal_moves.begin(), pos.legal_moves.end()), + .result = result, + .transform = 0}); + entries_[idx].transform = transform; return ENQUEUED_FOR_EVAL; } void ComputeBlocking() override { + for (auto& entry : entries_) computation_->AddInput(std::move(entry.input)); computation_->ComputeBlocking(); - for (size_t i = 0; i < results_.size(); ++i) { - const EvalResultPtr& result = results_[i]; + for (size_t i = 0; i < entries_.size(); ++i) { + const EvalResultPtr& result = entries_[i].result; if (result.q) *result.q = computation_->GetQVal(i); if (result.d) *result.d = computation_->GetDVal(i); if (result.m) *result.m = computation_->GetMVal(i); @@ -110,8 +111,8 @@ class NetworkAsBackendComputation : public BackendComputation { void SoftmaxPolicy(std::span dst, const NetworkComputation* computation, int idx) { - const std::vector& moves = moves_[idx]; - const int transform = transforms_[idx]; + const std::vector& moves = entries_[idx].legal_moves; + const int transform = entries_[idx].transform; // Copy the values to the destination array and compute the maximum. const float max_p = std::accumulate( moves.begin(), moves.end(), -std::numeric_limits::infinity(), @@ -131,11 +132,16 @@ class NetworkAsBackendComputation : public BackendComputation { } private: + struct Entry { + InputPlanes input; + MoveList legal_moves; + EvalResultPtr result; + int transform; + }; + NetworkAsBackend* backend_; std::unique_ptr computation_; - std::vector> moves_; - std::vector results_; - std::vector transforms_; + AtomicVector entries_; }; std::unique_ptr NetworkAsBackend::CreateComputation() { diff --git a/src/utils/atomic_vector.h b/src/utils/atomic_vector.h new file mode 100644 index 0000000000..50c371fd3c --- /dev/null +++ b/src/utils/atomic_vector.h @@ -0,0 +1,86 @@ +/* + This file is part of Leela Chess Zero. + Copyright (C) 2024 The LCZero Authors + + Leela Chess is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Leela Chess is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Leela Chess. If not, see . + + Additional permission under GNU GPL version 3 section 7 + + If you modify this Program, or any covered work, by linking or + combining it with NVIDIA Corporation's libraries from the NVIDIA CUDA + Toolkit and the NVIDIA CUDA Deep Neural Network library (or a + modified version of those libraries), containing parts covered by the + terms of the respective license agreement, the licensors of this + Program grant you additional permission to convey the resulting work. +*/ + +#pragma once + +namespace lczero { + +template +class AtomicVector { + public: + explicit AtomicVector(size_t capacity) : capacity_(capacity), size_(0) { + data_ = new + typename std::aligned_storage::type[capacity]; + } + + ~AtomicVector() { + clear(); + delete[] data_; + } + + // Thread safe, returns the index of the inserted element. + template + size_t emplace_back(Args&&... args) { + size_t i = size_.fetch_add(1, std::memory_order_relaxed); + assert(i < capacity_); + new (&data_[i]) T(std::forward(args)...); + return i; + } + + T& operator[](size_t i) { + assert(i < size()); + return *reinterpret_cast(&data_[i]); + } + + const T& operator[](size_t i) const { + assert(i < size()); + return *reinterpret_cast(&data_[i]); + } + + size_t size() const { return size_.load(std::memory_order_relaxed); } + size_t capacity() const { return capacity_; } + + // Not thread safe. + void clear() { + for (size_t i = size_.load(std::memory_order_relaxed); i-- > 0;) { + reinterpret_cast(&data_[i])->~T(); + } + size_.store(0, std::memory_order_relaxed); + } + + T* begin() { return reinterpret_cast(data_); } + T* end() { return reinterpret_cast(data_) + size(); } + const T* begin() const { return reinterpret_cast(data_); } + const T* end() const { return reinterpret_cast(data_) + size(); } + + private: + const size_t capacity_; + std::atomic size_; + typename std::aligned_storage::type* data_; +}; + +} // namespace lczero \ No newline at end of file From 26afe2178badb1a30fc4c9e5bf33255bbf83ed04 Mon Sep 17 00:00:00 2001 From: Viet-Anh Tran <55154899+CallOn84@users.noreply.github.com> Date: Sat, 22 Feb 2025 10:58:46 +0000 Subject: [PATCH 028/212] Update logging.h (#2124) --- src/utils/logging.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/utils/logging.h b/src/utils/logging.h index a9508de12c..907aaf8f6c 100644 --- a/src/utils/logging.h +++ b/src/utils/logging.h @@ -27,6 +27,7 @@ #pragma once +#include #include #include #include @@ -89,4 +90,4 @@ std::string FormatTime(std::chrono::time_point time); #define LOGFILE ::lczero::LogMessage(__FILE__, __LINE__) #define CERR ::lczero::StderrLogMessage(__FILE__, __LINE__) -#define COUT ::lczero::StdoutLogMessage(__FILE__, __LINE__) \ No newline at end of file +#define COUT ::lczero::StdoutLogMessage(__FILE__, __LINE__) From 1209835f83916536eb3106e4fc1b69f85c107078 Mon Sep 17 00:00:00 2001 From: Alexander Lyashuk Date: Sat, 22 Feb 2025 16:25:43 +0100 Subject: [PATCH 029/212] Introduce a "valuehead" search algorithm. (#2121) --- .gitignore | 1 + meson.build | 1 + src/chess/callbacks.h | 14 ++--- src/chess/position.h | 2 + src/engine_classic.cc | 78 -------------------------- src/neural/backend.h | 2 +- src/neural/batchsplit.cc | 92 +++++++++++++++++++++++++++++++ src/neural/batchsplit.h | 38 +++++++++++++ src/neural/memcache.cc | 11 ++-- src/neural/memcache.h | 3 +- src/search/instamove/instamove.cc | 81 ++++++++++++++++++++++++++- src/search/instamove/instamove.h | 15 ++++- src/search/register.h | 6 +- src/search/search.h | 10 ---- 14 files changed, 244 insertions(+), 110 deletions(-) create mode 100644 src/neural/batchsplit.cc create mode 100644 src/neural/batchsplit.h diff --git a/.gitignore b/.gitignore index ea18c9ee58..ae0570869a 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ .cache/ .clangd/ build/ +builddir/ __pycache__/ compile_commands.json CUDA_NN/ diff --git a/meson.build b/meson.build index f36d4cbb25..0760f28898 100644 --- a/meson.build +++ b/meson.build @@ -163,6 +163,7 @@ common_files += [ 'src/chess/position.cc', 'src/chess/uciloop.cc', 'src/neural/backend.cc', + 'src/neural/batchsplit.cc', 'src/neural/decoder.cc', 'src/neural/encoder.cc', 'src/neural/register.cc', diff --git a/src/chess/callbacks.h b/src/chess/callbacks.h index 7e28d271b1..6c9d724a81 100644 --- a/src/chess/callbacks.h +++ b/src/chess/callbacks.h @@ -68,24 +68,24 @@ struct ThinkingInfo { // Hash fullness * 1000 int hashfull = -1; // Moves to mate. - std::optional mate; + std::optional mate = std::nullopt; // Win in centipawns. - std::optional score; + std::optional score = std::nullopt; // Win/Draw/Lose probability * 1000. struct WDL { int w; int d; int l; }; - std::optional wdl; + std::optional wdl = std::nullopt; // Number of successful TB probes (not the same as playouts ending in TB hit). int tb_hits = -1; // Best line found. Moves are from perspective of white player. - std::vector pv; + std::vector pv = {}; // Multipv index. int multipv = -1; // Freeform comment. - std::string comment; + std::string comment = ""; // Those are extensions and not really UCI protocol. // 1 if it's "player1", 2 if it's "player2" @@ -93,9 +93,9 @@ struct ThinkingInfo { // Index of the game in the tournament (0-based). int game_id = -1; // The color of the player, if known. - std::optional is_black; + std::optional is_black = std::nullopt; // Moves left - std::optional moves_left; + std::optional moves_left = std::nullopt; }; // Is sent when a single game is finished. diff --git a/src/chess/position.h b/src/chess/position.h index dc679606fd..638314232e 100644 --- a/src/chess/position.h +++ b/src/chess/position.h @@ -98,6 +98,8 @@ class PositionHistory { PositionHistory() = default; PositionHistory(const PositionHistory& other) = default; PositionHistory(PositionHistory&& other) = default; + PositionHistory(std::span positions) + : positions_(positions.begin(), positions.end()) {} PositionHistory& operator=(const PositionHistory& other) = default; PositionHistory& operator=(PositionHistory&& other) = default; diff --git a/src/engine_classic.cc b/src/engine_classic.cc index 28dc99a980..f48fe4a04f 100644 --- a/src/engine_classic.cc +++ b/src/engine_classic.cc @@ -61,11 +61,6 @@ const OptionId kStrictUciTiming{"strict-uci-timing", "StrictTiming", "The UCI host compensates for lag, waits for " "the 'readyok' reply before sending 'go' and " "only then starts timing."}; -const OptionId kValueOnly{ - "value-only", "ValueOnly", - "In value only mode all search parameters are ignored and the position is " - "evaluated by getting the valuation of every child position and choosing " - "the worst for the opponent."}; const OptionId kClearTree{"", "ClearTree", "Clear the tree before the next search."}; @@ -123,7 +118,6 @@ void EngineClassic::PopulateOptions(OptionsParser* options) { options->Add(kStrictUciTiming) = false; options->HideOption(kStrictUciTiming); - options->Add(kValueOnly) = false; options->Add(kClearTree); options->HideOption(kClearTree); } @@ -265,74 +259,6 @@ class PonderResponseTransformer : public TransformingUciResponder { std::string ponder_move_; }; -void ValueOnlyGo(classic::NodeTree* tree, Network* network, - const OptionsDict& options, - std::unique_ptr responder) { - auto input_format = network->GetCapabilities().input_format; - - const auto& board = tree->GetPositionHistory().Last().GetBoard(); - auto legal_moves = board.GenerateLegalMoves(); - tree->GetCurrentHead()->CreateEdges(legal_moves); - PositionHistory history = tree->GetPositionHistory(); - std::vector planes; - for (auto edge : tree->GetCurrentHead()->Edges()) { - history.Append(edge.GetMove()); - if (history.ComputeGameResult() == GameResult::UNDECIDED) { - planes.emplace_back(EncodePositionForNN( - input_format, history, 8, FillEmptyHistory::FEN_ONLY, nullptr)); - } - history.Pop(); - } - - std::vector comp_q; - int batch_size = options.Get(classic::SearchParams::kMiniBatchSizeId); - if (batch_size == 0) batch_size = network->GetMiniBatchSize(); - - for (size_t i = 0; i < planes.size(); i += batch_size) { - auto comp = network->NewComputation(); - for (int j = 0; j < batch_size; j++) { - comp->AddInput(std::move(planes[i + j])); - if (i + j + 1 == planes.size()) break; - } - comp->ComputeBlocking(); - - for (int j = 0; j < batch_size; j++) comp_q.push_back(comp->GetQVal(j)); - } - - Move best; - int comp_idx = 0; - float max_q = std::numeric_limits::lowest(); - for (auto edge : tree->GetCurrentHead()->Edges()) { - history.Append(edge.GetMove()); - auto result = history.ComputeGameResult(); - float q = -1; - if (result == GameResult::UNDECIDED) { - // NN eval is for side to move perspective - so if its good, its bad for - // us. - q = -comp_q[comp_idx]; - comp_idx++; - } else if (result == GameResult::DRAW) { - q = 0; - } else { - // A legal move to a non-drawn terminal without tablebases must be a - // win. - q = 1; - } - if (q >= max_q) { - max_q = q; - best = edge.GetMove(tree->GetPositionHistory().IsBlackToMove()); - } - history.Pop(); - } - std::vector infos; - ThinkingInfo thinking; - thinking.depth = 1; - infos.push_back(thinking); - responder->OutputThinkingInfo(&infos); - BestMoveInfo info(best); - responder->OutputBestMove(&info); -} - } // namespace void EngineClassic::Go(const GoParams& params) { @@ -374,10 +300,6 @@ void EngineClassic::Go(const GoParams& params) { // Strip movesleft information from the response. responder = std::make_unique(std::move(responder)); } - if (options_.Get(kValueOnly)) { - ValueOnlyGo(tree_.get(), network_.get(), options_, std::move(responder)); - return; - } if (options_.Get