Compare commits
109 Commits
release_0.
...
v0.90
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
515f5f5c47 | ||
|
|
adcd8ea7c6 | ||
|
|
cf2400036e | ||
|
|
3e930e4f2d | ||
|
|
a9ec2dd295 | ||
|
|
df2cdaca50 | ||
|
|
c6f2a7e186 | ||
|
|
e7d17ec4f4 | ||
|
|
b5f7cbfadf | ||
|
|
be0f346ec9 | ||
|
|
d16d9a9988 | ||
|
|
6ff994126a | ||
|
|
18e4fc3690 | ||
|
|
8da4907e89 | ||
|
|
ade3f30237 | ||
|
|
b511638ca1 | ||
|
|
eabcc0e210 | ||
|
|
5de7e12704 | ||
|
|
8d1098a983 | ||
|
|
9252b686ae | ||
|
|
2be85fc62a | ||
|
|
feb6ae3e18 | ||
|
|
54980b8959 | ||
|
|
c1e4a0f2c6 | ||
|
|
bfddc2c42c | ||
|
|
17df5fd296 | ||
|
|
4c74336384 | ||
|
|
ba98e0cdf2 | ||
|
|
eaab364a63 | ||
|
|
797ba8e72d | ||
|
|
253fdd8a42 | ||
|
|
91c513a0c1 | ||
|
|
5e582b0fa7 | ||
|
|
146e83f3b3 | ||
|
|
5dfb27fb2d | ||
|
|
77c03538b0 | ||
|
|
37dc82c3ff | ||
|
|
ea850ecd20 | ||
|
|
995698b0cb | ||
|
|
2d875ec019 | ||
|
|
503cc42f48 | ||
|
|
2c61f02add | ||
|
|
bbe0dbd7ec | ||
|
|
5e97de6a41 | ||
|
|
65db8d0626 | ||
|
|
711397d645 | ||
|
|
207f058711 | ||
|
|
84d992babc | ||
|
|
be7bc07ca3 | ||
|
|
edae664afb | ||
|
|
f4521bf6aa | ||
|
|
3078b5944d | ||
|
|
a448a8320c | ||
|
|
956e73f183 | ||
|
|
5c2575535f | ||
|
|
81c1cd40ca | ||
|
|
b72eab3e07 | ||
|
|
360f25ec27 | ||
|
|
c7bc739ed2 | ||
|
|
60a9af567c | ||
|
|
9080bba815 | ||
|
|
2e052e74b6 | ||
|
|
1ca5698221 | ||
|
|
70be1e38c2 | ||
|
|
37c75aac41 | ||
|
|
82dca3c108 | ||
|
|
2f7087eba1 | ||
|
|
680a1b36f3 | ||
|
|
ad4de0d718 | ||
|
|
7ea5b772fb | ||
|
|
7aed8f3d48 | ||
|
|
8c8021dfa7 | ||
|
|
3f312e30db | ||
|
|
c85181dd8a | ||
|
|
6d5b34d824 | ||
|
|
5aa42b5f11 | ||
|
|
263e2038e9 | ||
|
|
b374e0a7ab | ||
|
|
45c89a6792 | ||
|
|
8eab966998 | ||
|
|
09bd9e68cf | ||
|
|
00465d243d | ||
|
|
7814183199 | ||
|
|
359ed9c5bc | ||
|
|
29a1356669 | ||
|
|
cf8d5b9b76 | ||
|
|
fdcae024e7 | ||
|
|
7b1b11390a | ||
|
|
5465b73e7c | ||
|
|
4352fcdb15 | ||
|
|
b833b642ec | ||
|
|
99a714be64 | ||
|
|
7b9043cf71 | ||
|
|
259fb809e9 | ||
|
|
a36c3ed4f4 | ||
|
|
6fb4c5efef | ||
|
|
4eeeded7d1 | ||
|
|
f83e62dca5 | ||
|
|
331cd3e4f7 | ||
|
|
617f572c0f | ||
|
|
20845e8ccf | ||
|
|
224786f67f | ||
|
|
9837b09b20 | ||
|
|
0944360416 | ||
|
|
ac3d03089b | ||
|
|
28bd6cde22 | ||
|
|
00ea7b83c9 | ||
|
|
67c38805a1 | ||
|
|
5f34078fba |
@@ -6,8 +6,8 @@ CheckOptions:
|
|||||||
- { key: readability-identifier-naming.TypedefCase, value: CamelCase }
|
- { key: readability-identifier-naming.TypedefCase, value: CamelCase }
|
||||||
- { key: readability-identifier-naming.TypeTemplateParameterCase, value: CamelCase }
|
- { key: readability-identifier-naming.TypeTemplateParameterCase, value: CamelCase }
|
||||||
- { key: readability-identifier-naming.MemberCase, value: lower_case }
|
- { key: readability-identifier-naming.MemberCase, value: lower_case }
|
||||||
- { key: readability-identifier-naming.PrivateMemberSuffix, value: '_' }
|
- { key: readability-identifier-naming.PrivateMemberSuffix, value: '_' }
|
||||||
- { key: readability-identifier-naming.ProtectedMemberSuffix, value: '_' }
|
- { key: readability-identifier-naming.ProtectedMemberSuffix, value: '_' }
|
||||||
- { key: readability-identifier-naming.EnumCase, value: CamelCase }
|
- { key: readability-identifier-naming.EnumCase, value: CamelCase }
|
||||||
- { key: readability-identifier-naming.EnumConstant, value: CamelCase }
|
- { key: readability-identifier-naming.EnumConstant, value: CamelCase }
|
||||||
- { key: readability-identifier-naming.EnumConstantPrefix, value: k }
|
- { key: readability-identifier-naming.EnumConstantPrefix, value: k }
|
||||||
|
|||||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -92,3 +92,7 @@ metastore_db
|
|||||||
|
|
||||||
plugin/updater_gpu/test/cpp/data
|
plugin/updater_gpu/test/cpp/data
|
||||||
/include/xgboost/build_config.h
|
/include/xgboost/build_config.h
|
||||||
|
|
||||||
|
# files from R-package source install
|
||||||
|
**/config.status
|
||||||
|
R-package/src/Makevars
|
||||||
|
|||||||
52
.travis.yml
52
.travis.yml
@@ -3,7 +3,6 @@ sudo: required
|
|||||||
|
|
||||||
# Enabling test on Linux and OS X
|
# Enabling test on Linux and OS X
|
||||||
os:
|
os:
|
||||||
- linux
|
|
||||||
- osx
|
- osx
|
||||||
|
|
||||||
osx_image: xcode9.3
|
osx_image: xcode9.3
|
||||||
@@ -11,65 +10,22 @@ osx_image: xcode9.3
|
|||||||
# Use Build Matrix to do lint and build seperately
|
# Use Build Matrix to do lint and build seperately
|
||||||
env:
|
env:
|
||||||
matrix:
|
matrix:
|
||||||
# code lint
|
|
||||||
- TASK=lint
|
|
||||||
# r package test
|
|
||||||
- TASK=r_test
|
|
||||||
# python package test
|
# python package test
|
||||||
- TASK=python_test
|
- TASK=python_test
|
||||||
- TASK=python_lightweight_test
|
|
||||||
# java package test
|
# java package test
|
||||||
- TASK=java_test
|
- TASK=java_test
|
||||||
# cmake test
|
# cmake test
|
||||||
- TASK=cmake_test
|
# - TASK=cmake_test
|
||||||
# c++ test
|
|
||||||
- TASK=cpp_test
|
|
||||||
# distributed test
|
|
||||||
- TASK=distributed_test
|
|
||||||
# address sanitizer test
|
|
||||||
- TASK=sanitizer_test
|
|
||||||
|
|
||||||
matrix:
|
|
||||||
exclude:
|
|
||||||
- os: osx
|
|
||||||
env: TASK=lint
|
|
||||||
- os: osx
|
|
||||||
env: TASK=cmake_test
|
|
||||||
- os: linux
|
|
||||||
env: TASK=r_test
|
|
||||||
- os: osx
|
|
||||||
env: TASK=python_lightweight_test
|
|
||||||
- os: osx
|
|
||||||
env: TASK=cpp_test
|
|
||||||
- os: osx
|
|
||||||
env: TASK=distributed_test
|
|
||||||
- os: osx
|
|
||||||
env: TASK=sanitizer_test
|
|
||||||
|
|
||||||
# dependent apt packages
|
# dependent apt packages
|
||||||
addons:
|
addons:
|
||||||
apt:
|
|
||||||
sources:
|
|
||||||
- llvm-toolchain-trusty-5.0
|
|
||||||
- ubuntu-toolchain-r-test
|
|
||||||
- george-edison55-precise-backports
|
|
||||||
packages:
|
|
||||||
- clang
|
|
||||||
- clang-tidy-5.0
|
|
||||||
- cmake-data
|
|
||||||
- doxygen
|
|
||||||
- wget
|
|
||||||
- libcurl4-openssl-dev
|
|
||||||
- unzip
|
|
||||||
- graphviz
|
|
||||||
- gcc-4.8
|
|
||||||
- g++-4.8
|
|
||||||
- gcc-7
|
|
||||||
- g++-7
|
|
||||||
homebrew:
|
homebrew:
|
||||||
packages:
|
packages:
|
||||||
- gcc@7
|
- gcc@7
|
||||||
- graphviz
|
- graphviz
|
||||||
|
- openssl
|
||||||
|
- libgit2
|
||||||
|
- r
|
||||||
update: true
|
update: true
|
||||||
|
|
||||||
before_install:
|
before_install:
|
||||||
|
|||||||
479
CMakeLists.txt
479
CMakeLists.txt
@@ -1,344 +1,229 @@
|
|||||||
cmake_minimum_required (VERSION 3.2)
|
cmake_minimum_required(VERSION 3.3)
|
||||||
project(xgboost)
|
project(xgboost LANGUAGES CXX C VERSION 0.90)
|
||||||
include(cmake/Utils.cmake)
|
include(cmake/Utils.cmake)
|
||||||
list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/modules")
|
list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/modules")
|
||||||
find_package(OpenMP)
|
cmake_policy(SET CMP0022 NEW)
|
||||||
|
|
||||||
|
message(STATUS "CMake version ${CMAKE_VERSION}")
|
||||||
|
if (MSVC)
|
||||||
|
cmake_minimum_required(VERSION 3.11)
|
||||||
|
endif (MSVC)
|
||||||
|
|
||||||
set_default_configuration_release()
|
set_default_configuration_release()
|
||||||
msvc_use_static_runtime()
|
|
||||||
|
|
||||||
# Options
|
|
||||||
## GPUs
|
|
||||||
option(USE_CUDA "Build with GPU acceleration" OFF)
|
|
||||||
option(USE_NCCL "Build with multiple GPUs support" OFF)
|
|
||||||
set(GPU_COMPUTE_VER "" CACHE STRING
|
|
||||||
"Space separated list of compute versions to be built against, e.g. '35 61'")
|
|
||||||
|
|
||||||
|
#-- Options
|
||||||
|
option(BUILD_C_DOC "Build documentation for C APIs using Doxygen." OFF)
|
||||||
|
option(USE_OPENMP "Build with OpenMP support." ON)
|
||||||
## Bindings
|
## Bindings
|
||||||
option(JVM_BINDINGS "Build JVM bindings" OFF)
|
option(JVM_BINDINGS "Build JVM bindings" OFF)
|
||||||
option(R_LIB "Build shared library for R package" OFF)
|
option(R_LIB "Build shared library for R package" OFF)
|
||||||
|
## Dev
|
||||||
## Devs
|
option(GOOGLE_TEST "Build google tests" OFF)
|
||||||
|
option(USE_DMLC_GTEST "Use google tests bundled with dmlc-core submodule (EXPERIMENTAL)" OFF)
|
||||||
|
option(USE_NVTX "Build with cuda profiling annotations. Developers only." OFF)
|
||||||
|
set(NVTX_HEADER_DIR "" CACHE PATH "Path to the stand-alone nvtx header")
|
||||||
|
## CUDA
|
||||||
|
option(USE_CUDA "Build with GPU acceleration" OFF)
|
||||||
|
option(USE_NCCL "Build with NCCL to enable multi-GPU support." OFF)
|
||||||
|
option(BUILD_WITH_SHARED_NCCL "Build with shared NCCL library." OFF)
|
||||||
|
set(GPU_COMPUTE_VER "" CACHE STRING
|
||||||
|
"Semicolon separated list of compute versions to be built against, e.g. '35;61'")
|
||||||
|
if (BUILD_WITH_SHARED_NCCL AND (NOT USE_NCCL))
|
||||||
|
message(SEND_ERROR "Build XGBoost with -DUSE_NCCL=ON to enable BUILD_WITH_SHARED_NCCL.")
|
||||||
|
endif (BUILD_WITH_SHARED_NCCL AND (NOT USE_NCCL))
|
||||||
|
## Sanitizers
|
||||||
option(USE_SANITIZER "Use santizer flags" OFF)
|
option(USE_SANITIZER "Use santizer flags" OFF)
|
||||||
option(SANITIZER_PATH "Path to sanitizes.")
|
option(SANITIZER_PATH "Path to sanitizes.")
|
||||||
set(ENABLED_SANITIZERS "address" "leak" CACHE STRING
|
set(ENABLED_SANITIZERS "address" "leak" CACHE STRING
|
||||||
"Semicolon separated list of sanitizer names. E.g 'address;leak'. Supported sanitizers are
|
"Semicolon separated list of sanitizer names. E.g 'address;leak'. Supported sanitizers are
|
||||||
address, leak and thread.")
|
address, leak and thread.")
|
||||||
option(GOOGLE_TEST "Build google tests" OFF)
|
## Plugins
|
||||||
|
|
||||||
# Plugins
|
|
||||||
option(PLUGIN_LZ4 "Build lz4 plugin" OFF)
|
option(PLUGIN_LZ4 "Build lz4 plugin" OFF)
|
||||||
option(PLUGIN_DENSE_PARSER "Build dense parser plugin" OFF)
|
option(PLUGIN_DENSE_PARSER "Build dense parser plugin" OFF)
|
||||||
|
|
||||||
# Deprecation warning
|
## Deprecation warning
|
||||||
if(USE_AVX)
|
if (USE_AVX)
|
||||||
message(WARNING "The option 'USE_AVX' is deprecated as experimental AVX features have been removed from xgboost.")
|
message(WARNING "The option 'USE_AVX' is deprecated as experimental AVX features have been removed from xgboost.")
|
||||||
endif()
|
endif (USE_AVX)
|
||||||
|
|
||||||
# Compiler flags
|
|
||||||
set(CMAKE_CXX_STANDARD 11)
|
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
|
||||||
if(OpenMP_CXX_FOUND OR OPENMP_FOUND)
|
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
|
|
||||||
endif()
|
|
||||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
|
||||||
if(MSVC)
|
|
||||||
# Multithreaded compilation
|
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP")
|
|
||||||
else()
|
|
||||||
# Correct error for GCC 5 and cuda
|
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_MWAITXINTRIN_H_INCLUDED -D_FORCE_INLINES")
|
|
||||||
# Performance
|
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -funroll-loops")
|
|
||||||
endif()
|
|
||||||
if(WIN32 AND MINGW)
|
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libstdc++")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Check existence of software pre-fetching
|
|
||||||
include(CheckCXXSourceCompiles)
|
|
||||||
check_cxx_source_compiles("
|
|
||||||
#include <xmmintrin.h>
|
|
||||||
int main() {
|
|
||||||
char data = 0;
|
|
||||||
const char* address = &data;
|
|
||||||
_mm_prefetch(address, _MM_HINT_NTA);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
" XGBOOST_MM_PREFETCH_PRESENT)
|
|
||||||
check_cxx_source_compiles("
|
|
||||||
int main() {
|
|
||||||
char data = 0;
|
|
||||||
const char* address = &data;
|
|
||||||
__builtin_prefetch(address, 0, 0);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
" XGBOOST_BUILTIN_PREFETCH_PRESENT)
|
|
||||||
|
|
||||||
# Sanitizer
|
# Sanitizer
|
||||||
if(USE_SANITIZER)
|
if (USE_SANITIZER)
|
||||||
|
# Older CMake versions have had troubles with Sanitizer
|
||||||
|
cmake_minimum_required(VERSION 3.12)
|
||||||
include(cmake/Sanitizer.cmake)
|
include(cmake/Sanitizer.cmake)
|
||||||
enable_sanitizers("${ENABLED_SANITIZERS}")
|
enable_sanitizers("${ENABLED_SANITIZERS}")
|
||||||
endif(USE_SANITIZER)
|
endif (USE_SANITIZER)
|
||||||
|
|
||||||
|
if (USE_CUDA)
|
||||||
|
cmake_minimum_required(VERSION 3.12)
|
||||||
|
SET(USE_OPENMP ON CACHE BOOL "CUDA requires OpenMP" FORCE)
|
||||||
|
# `export CXX=' is ignored by CMake CUDA.
|
||||||
|
set(CMAKE_CUDA_HOST_COMPILER ${CMAKE_CXX_COMPILER})
|
||||||
|
message(STATUS "Configured CUDA host compiler: ${CMAKE_CUDA_HOST_COMPILER}")
|
||||||
|
|
||||||
|
enable_language(CUDA)
|
||||||
|
set(GEN_CODE "")
|
||||||
|
format_gencode_flags("${GPU_COMPUTE_VER}" GEN_CODE)
|
||||||
|
message(STATUS "CUDA GEN_CODE: ${GEN_CODE}")
|
||||||
|
endif (USE_CUDA)
|
||||||
|
|
||||||
# dmlc-core
|
# dmlc-core
|
||||||
add_subdirectory(dmlc-core)
|
msvc_use_static_runtime()
|
||||||
set(LINK_LIBRARIES dmlc rabit)
|
add_subdirectory(${PROJECT_SOURCE_DIR}/dmlc-core)
|
||||||
|
set_target_properties(dmlc PROPERTIES
|
||||||
# enable custom logging
|
CXX_STANDARD 11
|
||||||
add_definitions(-DDMLC_LOG_CUSTOMIZE=1)
|
CXX_STANDARD_REQUIRED ON
|
||||||
|
POSITION_INDEPENDENT_CODE ON)
|
||||||
# compiled code customizations for R package
|
list(APPEND LINKED_LIBRARIES_PRIVATE dmlc)
|
||||||
if(R_LIB)
|
|
||||||
add_definitions(
|
|
||||||
-DXGBOOST_STRICT_R_MODE=1
|
|
||||||
-DXGBOOST_CUSTOMIZE_GLOBAL_PRNG=1
|
|
||||||
-DDMLC_LOG_BEFORE_THROW=0
|
|
||||||
-DDMLC_DISABLE_STDIN=1
|
|
||||||
-DDMLC_LOG_CUSTOMIZE=1
|
|
||||||
-DRABIT_CUSTOMIZE_MSG_
|
|
||||||
-DRABIT_STRICT_CXX98_
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Gather source files
|
|
||||||
include_directories (
|
|
||||||
${PROJECT_SOURCE_DIR}/include
|
|
||||||
${PROJECT_SOURCE_DIR}/dmlc-core/include
|
|
||||||
${PROJECT_SOURCE_DIR}/rabit/include
|
|
||||||
)
|
|
||||||
|
|
||||||
# Generate configurable header
|
|
||||||
set(CMAKE_LOCAL "${PROJECT_SOURCE_DIR}/cmake")
|
|
||||||
set(INCLUDE_ROOT "${PROJECT_SOURCE_DIR}/include")
|
|
||||||
message(STATUS "${CMAKE_LOCAL}/build_config.h.in -> ${INCLUDE_ROOT}/xgboost/build_config.h")
|
|
||||||
configure_file("${CMAKE_LOCAL}/build_config.h.in" "${INCLUDE_ROOT}/xgboost/build_config.h")
|
|
||||||
|
|
||||||
file(GLOB_RECURSE SOURCES
|
|
||||||
src/*.cc
|
|
||||||
src/*.h
|
|
||||||
include/*.h
|
|
||||||
)
|
|
||||||
|
|
||||||
# Only add main function for executable target
|
|
||||||
list(REMOVE_ITEM SOURCES ${PROJECT_SOURCE_DIR}/src/cli_main.cc)
|
|
||||||
|
|
||||||
file(GLOB_RECURSE CUDA_SOURCES
|
|
||||||
src/*.cu
|
|
||||||
src/*.cuh
|
|
||||||
)
|
|
||||||
|
|
||||||
# Add plugins to source files
|
|
||||||
if(PLUGIN_LZ4)
|
|
||||||
list(APPEND SOURCES plugin/lz4/sparse_page_lz4_format.cc)
|
|
||||||
link_libraries(lz4)
|
|
||||||
endif()
|
|
||||||
if(PLUGIN_DENSE_PARSER)
|
|
||||||
list(APPEND SOURCES plugin/dense_parser/dense_libsvm.cc)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# rabit
|
# rabit
|
||||||
# TODO: Use CMakeLists.txt from rabit.
|
# full rabit doesn't build on windows, so we can't import it as subdirectory
|
||||||
set(RABIT_SOURCES
|
if(MINGW OR R_LIB)
|
||||||
|
set(RABIT_SOURCES
|
||||||
|
rabit/src/engine_empty.cc
|
||||||
|
rabit/src/c_api.cc)
|
||||||
|
else ()
|
||||||
|
set(RABIT_SOURCES
|
||||||
rabit/src/allreduce_base.cc
|
rabit/src/allreduce_base.cc
|
||||||
rabit/src/allreduce_robust.cc
|
rabit/src/allreduce_robust.cc
|
||||||
rabit/src/engine.cc
|
rabit/src/engine.cc
|
||||||
rabit/src/c_api.cc
|
rabit/src/c_api.cc)
|
||||||
)
|
endif (MINGW OR R_LIB)
|
||||||
set(RABIT_EMPTY_SOURCES
|
add_library(rabit STATIC ${RABIT_SOURCES})
|
||||||
rabit/src/engine_empty.cc
|
target_include_directories(rabit PRIVATE
|
||||||
rabit/src/c_api.cc
|
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/dmlc-core/include>
|
||||||
)
|
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/rabit/include/rabit>)
|
||||||
|
set_target_properties(rabit
|
||||||
|
PROPERTIES
|
||||||
|
CXX_STANDARD 11
|
||||||
|
CXX_STANDARD_REQUIRED ON
|
||||||
|
POSITION_INDEPENDENT_CODE ON)
|
||||||
|
list(APPEND LINKED_LIBRARIES_PRIVATE rabit)
|
||||||
|
|
||||||
if(MINGW OR R_LIB)
|
# Exports some R specific definitions and objects
|
||||||
# build a dummy rabit library
|
if (R_LIB)
|
||||||
add_library(rabit STATIC ${RABIT_EMPTY_SOURCES})
|
add_subdirectory(${PROJECT_SOURCE_DIR}/R-package)
|
||||||
else()
|
endif (R_LIB)
|
||||||
add_library(rabit STATIC ${RABIT_SOURCES})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if (GENERATE_COMPILATION_DATABASE)
|
# core xgboost
|
||||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
add_subdirectory(${PROJECT_SOURCE_DIR}/src)
|
||||||
endif (GENERATE_COMPILATION_DATABASE)
|
set(XGBOOST_OBJ_SOURCES "${XGBOOST_OBJ_SOURCES};$<TARGET_OBJECTS:objxgboost>")
|
||||||
|
|
||||||
if(USE_CUDA AND (NOT GENERATE_COMPILATION_DATABASE))
|
#-- Shared library
|
||||||
find_package(CUDA 8.0 REQUIRED)
|
add_library(xgboost SHARED ${XGBOOST_OBJ_SOURCES} ${PLUGINS_SOURCES})
|
||||||
cmake_minimum_required(VERSION 3.5)
|
target_include_directories(xgboost
|
||||||
|
INTERFACE
|
||||||
|
$<INSTALL_INTERFACE:${CMAKE_INSTALL_PREFIX}/include>
|
||||||
|
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>)
|
||||||
|
target_link_libraries(xgboost PRIVATE ${LINKED_LIBRARIES_PRIVATE})
|
||||||
|
|
||||||
add_definitions(-DXGBOOST_USE_CUDA)
|
# This creates its own shared library `xgboost4j'.
|
||||||
|
if (JVM_BINDINGS)
|
||||||
|
add_subdirectory(${PROJECT_SOURCE_DIR}/jvm-packages)
|
||||||
|
endif (JVM_BINDINGS)
|
||||||
|
#-- End shared library
|
||||||
|
|
||||||
include_directories(cub)
|
#-- CLI for xgboost
|
||||||
|
add_executable(runxgboost ${PROJECT_SOURCE_DIR}/src/cli_main.cc ${XGBOOST_OBJ_SOURCES})
|
||||||
|
# For cli_main.cc only
|
||||||
|
if (USE_OPENMP)
|
||||||
|
find_package(OpenMP REQUIRED)
|
||||||
|
target_compile_options(runxgboost PRIVATE ${OpenMP_CXX_FLAGS})
|
||||||
|
endif (USE_OPENMP)
|
||||||
|
target_include_directories(runxgboost
|
||||||
|
PRIVATE
|
||||||
|
${PROJECT_SOURCE_DIR}/include
|
||||||
|
${PROJECT_SOURCE_DIR}/dmlc-core/include
|
||||||
|
${PROJECT_SOURCE_DIR}/rabit/include)
|
||||||
|
target_link_libraries(runxgboost PRIVATE ${LINKED_LIBRARIES_PRIVATE})
|
||||||
|
set_target_properties(
|
||||||
|
runxgboost PROPERTIES
|
||||||
|
OUTPUT_NAME xgboost
|
||||||
|
CXX_STANDARD 11
|
||||||
|
CXX_STANDARD_REQUIRED ON)
|
||||||
|
#-- End CLI for xgboost
|
||||||
|
|
||||||
if(USE_NCCL)
|
set_output_directory(runxgboost ${PROJECT_SOURCE_DIR})
|
||||||
find_package(Nccl REQUIRED)
|
set_output_directory(xgboost ${PROJECT_SOURCE_DIR}/lib)
|
||||||
cuda_include_directories(${NCCL_INCLUDE_DIR})
|
# Ensure these two targets do not build simultaneously, as they produce outputs with conflicting names
|
||||||
add_definitions(-DXGBOOST_USE_NCCL)
|
add_dependencies(xgboost runxgboost)
|
||||||
endif()
|
|
||||||
|
|
||||||
set(GENCODE_FLAGS "")
|
#-- Installing XGBoost
|
||||||
format_gencode_flags("${GPU_COMPUTE_VER}" GENCODE_FLAGS)
|
if (R_LIB)
|
||||||
message("cuda architecture flags: ${GENCODE_FLAGS}")
|
|
||||||
|
|
||||||
set(CUDA_NVCC_FLAGS "${CUDA_NVCC_FLAGS};--expt-extended-lambda;--expt-relaxed-constexpr;${GENCODE_FLAGS};-lineinfo;")
|
|
||||||
if(NOT MSVC)
|
|
||||||
set(CUDA_NVCC_FLAGS "${CUDA_NVCC_FLAGS};-Xcompiler -fPIC; -Xcompiler -Werror; -std=c++11")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
cuda_add_library(gpuxgboost ${CUDA_SOURCES} STATIC)
|
|
||||||
|
|
||||||
if(USE_NCCL)
|
|
||||||
link_directories(${NCCL_LIBRARY})
|
|
||||||
target_link_libraries(gpuxgboost ${NCCL_LIB_NAME})
|
|
||||||
endif()
|
|
||||||
list(APPEND LINK_LIBRARIES gpuxgboost)
|
|
||||||
|
|
||||||
elseif (USE_CUDA AND GENERATE_COMPILATION_DATABASE)
|
|
||||||
# Enable CUDA language to generate a compilation database.
|
|
||||||
cmake_minimum_required(VERSION 3.8)
|
|
||||||
|
|
||||||
find_package(CUDA 8.0 REQUIRED)
|
|
||||||
enable_language(CUDA)
|
|
||||||
set(CMAKE_CUDA_COMPILER clang++)
|
|
||||||
set(CUDA_SEPARABLE_COMPILATION ON)
|
|
||||||
if (NOT CLANG_CUDA_GENCODE)
|
|
||||||
set(CLANG_CUDA_GENCODE "--cuda-gpu-arch=sm_35")
|
|
||||||
endif (NOT CLANG_CUDA_GENCODE)
|
|
||||||
set(CMAKE_CUDA_FLAGS " -Wno-deprecated ${CLANG_CUDA_GENCODE} -fPIC ${GENCODE} -std=c++11 -x cuda")
|
|
||||||
message(STATUS "CMAKE_CUDA_FLAGS: ${CMAKE_CUDA_FLAGS}")
|
|
||||||
|
|
||||||
add_library(gpuxgboost STATIC ${CUDA_SOURCES})
|
|
||||||
|
|
||||||
if(USE_NCCL)
|
|
||||||
find_package(Nccl REQUIRED)
|
|
||||||
target_include_directories(gpuxgboost PUBLIC ${NCCL_INCLUDE_DIR})
|
|
||||||
target_compile_definitions(gpuxgboost PUBLIC -DXGBOOST_USE_NCCL)
|
|
||||||
target_link_libraries(gpuxgboost PUBLIC ${NCCL_LIB_NAME})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
target_compile_definitions(gpuxgboost PUBLIC -DXGBOOST_USE_CUDA)
|
|
||||||
# A hack for CMake to make arguments valid for clang++
|
|
||||||
string(REPLACE "-x cu" "-x cuda" CMAKE_CUDA_COMPILE_PTX_COMPILATION
|
|
||||||
${CMAKE_CUDA_COMPILE_PTX_COMPILATION})
|
|
||||||
string(REPLACE "-x cu" "-x cuda" CMAKE_CUDA_COMPILE_WHOLE_COMPILATION
|
|
||||||
${CMAKE_CUDA_COMPILE_WHOLE_COMPILATION})
|
|
||||||
string(REPLACE "-x cu" "-x cuda" CMAKE_CUDA_COMPILE_SEPARABLE_COMPILATION
|
|
||||||
${CMAKE_CUDA_COMPILE_SEPARABLE_COMPILATION})
|
|
||||||
target_include_directories(gpuxgboost PUBLIC cub)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
|
|
||||||
# flags and sources for R-package
|
|
||||||
if(R_LIB)
|
|
||||||
file(GLOB_RECURSE R_SOURCES
|
|
||||||
R-package/src/*.h
|
|
||||||
R-package/src/*.c
|
|
||||||
R-package/src/*.cc
|
|
||||||
)
|
|
||||||
list(APPEND SOURCES ${R_SOURCES})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
add_library(objxgboost OBJECT ${SOURCES})
|
|
||||||
|
|
||||||
# building shared library for R package
|
|
||||||
if(R_LIB)
|
|
||||||
find_package(LibR REQUIRED)
|
|
||||||
|
|
||||||
list(APPEND LINK_LIBRARIES "${LIBR_CORE_LIBRARY}")
|
|
||||||
MESSAGE(STATUS "LIBR_CORE_LIBRARY " ${LIBR_CORE_LIBRARY})
|
|
||||||
|
|
||||||
# Shared library target for the R package
|
|
||||||
add_library(xgboost SHARED $<TARGET_OBJECTS:objxgboost>)
|
|
||||||
include_directories(xgboost
|
|
||||||
"${LIBR_INCLUDE_DIRS}"
|
|
||||||
"${PROJECT_SOURCE_DIR}"
|
|
||||||
)
|
|
||||||
|
|
||||||
target_link_libraries(xgboost ${LINK_LIBRARIES})
|
|
||||||
# R uses no lib prefix in shared library names of its packages
|
|
||||||
set_target_properties(xgboost PROPERTIES PREFIX "")
|
set_target_properties(xgboost PROPERTIES PREFIX "")
|
||||||
if(APPLE)
|
if (APPLE)
|
||||||
set_target_properties(xgboost PROPERTIES SUFFIX ".so")
|
set_target_properties(xgboost PROPERTIES SUFFIX ".so")
|
||||||
endif()
|
endif (APPLE)
|
||||||
|
|
||||||
setup_rpackage_install_target(xgboost ${CMAKE_CURRENT_BINARY_DIR})
|
setup_rpackage_install_target(xgboost ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
# use a dummy location for any other remaining installs
|
|
||||||
set(CMAKE_INSTALL_PREFIX "${CMAKE_CURRENT_BINARY_DIR}/dummy_inst")
|
set(CMAKE_INSTALL_PREFIX "${CMAKE_CURRENT_BINARY_DIR}/dummy_inst")
|
||||||
|
endif (R_LIB)
|
||||||
|
if (MINGW)
|
||||||
|
set_target_properties(xgboost PROPERTIES PREFIX "")
|
||||||
|
endif (MINGW)
|
||||||
|
|
||||||
# main targets: shared library & exe
|
if (BUILD_C_DOC)
|
||||||
else()
|
include(cmake/Doc.cmake)
|
||||||
# Executable
|
run_doxygen()
|
||||||
add_executable(runxgboost $<TARGET_OBJECTS:objxgboost> src/cli_main.cc)
|
endif (BUILD_C_DOC)
|
||||||
set_target_properties(runxgboost PROPERTIES
|
|
||||||
OUTPUT_NAME xgboost
|
|
||||||
)
|
|
||||||
set_output_directory(runxgboost ${PROJECT_SOURCE_DIR})
|
|
||||||
target_link_libraries(runxgboost ${LINK_LIBRARIES})
|
|
||||||
|
|
||||||
# Shared library
|
include(GNUInstallDirs)
|
||||||
add_library(xgboost SHARED $<TARGET_OBJECTS:objxgboost>)
|
# Exposing only C APIs.
|
||||||
target_link_libraries(xgboost ${LINK_LIBRARIES})
|
install(FILES
|
||||||
set_output_directory(xgboost ${PROJECT_SOURCE_DIR}/lib)
|
"${PROJECT_SOURCE_DIR}/include/xgboost/c_api.h"
|
||||||
if(MINGW)
|
DESTINATION
|
||||||
# remove the 'lib' prefix to conform to windows convention for shared library names
|
include/xgboost/)
|
||||||
set_target_properties(xgboost PROPERTIES PREFIX "")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
#Ensure these two targets do not build simultaneously, as they produce outputs with conflicting names
|
install(TARGETS xgboost runxgboost
|
||||||
add_dependencies(xgboost runxgboost)
|
EXPORT XGBoostTargets
|
||||||
endif()
|
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||||
|
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||||
|
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||||
|
INCLUDES DESTINATION ${LIBLEGACY_INCLUDE_DIRS})
|
||||||
|
install(EXPORT XGBoostTargets
|
||||||
|
FILE XGBoostTargets.cmake
|
||||||
|
NAMESPACE xgboost::
|
||||||
|
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/xgboost)
|
||||||
|
|
||||||
# JVM
|
include(CMakePackageConfigHelpers)
|
||||||
if(JVM_BINDINGS)
|
configure_package_config_file(
|
||||||
find_package(JNI QUIET REQUIRED)
|
${CMAKE_CURRENT_LIST_DIR}/cmake/xgboost-config.cmake.in
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/cmake/xgboost-config.cmake
|
||||||
|
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/xgboost)
|
||||||
|
write_basic_package_version_file(
|
||||||
|
${CMAKE_BINARY_DIR}/cmake/xgboost-config-version.cmake
|
||||||
|
VERSION ${XGBOOST_VERSION}
|
||||||
|
COMPATIBILITY AnyNewerVersion)
|
||||||
|
install(
|
||||||
|
FILES
|
||||||
|
${CMAKE_BINARY_DIR}/cmake/xgboost-config.cmake
|
||||||
|
${CMAKE_BINARY_DIR}/cmake/xgboost-config-version.cmake
|
||||||
|
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/xgboost)
|
||||||
|
|
||||||
add_library(xgboost4j SHARED
|
#-- Test
|
||||||
$<TARGET_OBJECTS:objxgboost>
|
if (GOOGLE_TEST)
|
||||||
jvm-packages/xgboost4j/src/native/xgboost4j.cpp)
|
|
||||||
target_include_directories(xgboost4j
|
|
||||||
PRIVATE ${JNI_INCLUDE_DIRS}
|
|
||||||
PRIVATE jvm-packages/xgboost4j/src/native)
|
|
||||||
target_link_libraries(xgboost4j
|
|
||||||
${LINK_LIBRARIES}
|
|
||||||
${JAVA_JVM_LIBRARY})
|
|
||||||
set_output_directory(xgboost4j ${PROJECT_SOURCE_DIR}/lib)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
|
|
||||||
# Test
|
|
||||||
if(GOOGLE_TEST)
|
|
||||||
enable_testing()
|
enable_testing()
|
||||||
find_package(GTest REQUIRED)
|
# Unittests.
|
||||||
|
add_subdirectory(${PROJECT_SOURCE_DIR}/tests/cpp)
|
||||||
|
add_test(
|
||||||
|
NAME TestXGBoostLib
|
||||||
|
COMMAND testxgboost
|
||||||
|
WORKING_DIRECTORY ${PROJECT_BINARY_DIR})
|
||||||
|
|
||||||
file(GLOB_RECURSE TEST_SOURCES "tests/cpp/*.cc")
|
# CLI tests
|
||||||
auto_source_group("${TEST_SOURCES}")
|
configure_file(
|
||||||
|
${PROJECT_SOURCE_DIR}/tests/cli/machine.conf.in
|
||||||
|
${PROJECT_BINARY_DIR}/tests/cli/machine.conf
|
||||||
|
@ONLY)
|
||||||
|
add_test(
|
||||||
|
NAME TestXGBoostCLI
|
||||||
|
COMMAND runxgboost ${PROJECT_BINARY_DIR}/tests/cli/machine.conf
|
||||||
|
WORKING_DIRECTORY ${PROJECT_BINARY_DIR})
|
||||||
|
set_tests_properties(TestXGBoostCLI
|
||||||
|
PROPERTIES
|
||||||
|
PASS_REGULAR_EXPRESSION ".*test-rmse:0.087.*")
|
||||||
|
endif (GOOGLE_TEST)
|
||||||
|
|
||||||
if(USE_CUDA AND (NOT GENERATE_COMPILATION_DATABASE))
|
# For MSVC: Call msvc_use_static_runtime() once again to completely
|
||||||
file(GLOB_RECURSE CUDA_TEST_SOURCES "tests/cpp/*.cu")
|
# replace /MD with /MT. See https://github.com/dmlc/xgboost/issues/4462
|
||||||
cuda_include_directories(${GTEST_INCLUDE_DIRS})
|
# for issues caused by mixing of /MD and /MT flags
|
||||||
cuda_compile(CUDA_TEST_OBJS ${CUDA_TEST_SOURCES})
|
msvc_use_static_runtime()
|
||||||
elseif (USE_CUDA AND GENERATE_COMPILATION_DATABASE)
|
|
||||||
file(GLOB_RECURSE CUDA_TEST_SOURCES "tests/cpp/*.cu")
|
|
||||||
else()
|
|
||||||
set(CUDA_TEST_OBJS "")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if (USE_CUDA AND GENERATE_COMPILATION_DATABASE)
|
|
||||||
add_executable(testxgboost ${TEST_SOURCES} ${CUDA_TEST_SOURCES}
|
|
||||||
$<TARGET_OBJECTS:objxgboost>)
|
|
||||||
target_include_directories(testxgboost PRIVATE cub)
|
|
||||||
else ()
|
|
||||||
add_executable(testxgboost ${TEST_SOURCES} ${CUDA_TEST_OBJS}
|
|
||||||
$<TARGET_OBJECTS:objxgboost>)
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
set_output_directory(testxgboost ${PROJECT_SOURCE_DIR})
|
|
||||||
target_include_directories(testxgboost
|
|
||||||
PRIVATE ${GTEST_INCLUDE_DIRS})
|
|
||||||
target_link_libraries(testxgboost ${GTEST_LIBRARIES} ${LINK_LIBRARIES})
|
|
||||||
|
|
||||||
add_test(TestXGBoost testxgboost)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
|
|
||||||
# Group sources
|
|
||||||
auto_source_group("${SOURCES}")
|
|
||||||
|
|||||||
@@ -88,3 +88,4 @@ List of Contributors
|
|||||||
* [Chen Qin](https://github.com/chenqin)
|
* [Chen Qin](https://github.com/chenqin)
|
||||||
* [Sam Wilkinson](https://samwilkinson.io)
|
* [Sam Wilkinson](https://samwilkinson.io)
|
||||||
* [Matthew Jones](https://github.com/mt-jones)
|
* [Matthew Jones](https://github.com/mt-jones)
|
||||||
|
* [Jiaxiang Li](https://github.com/JiaxiangBU)
|
||||||
|
|||||||
450
Jenkinsfile
vendored
450
Jenkinsfile
vendored
@@ -3,125 +3,343 @@
|
|||||||
// Jenkins pipeline
|
// Jenkins pipeline
|
||||||
// See documents at https://jenkins.io/doc/book/pipeline/jenkinsfile/
|
// See documents at https://jenkins.io/doc/book/pipeline/jenkinsfile/
|
||||||
|
|
||||||
import groovy.transform.Field
|
|
||||||
|
|
||||||
/* Unrestricted tasks: tasks that do NOT generate artifacts */
|
|
||||||
|
|
||||||
// Command to run command inside a docker container
|
// Command to run command inside a docker container
|
||||||
def dockerRun = 'tests/ci_build/ci_build.sh'
|
dockerRun = 'tests/ci_build/ci_build.sh'
|
||||||
// Utility functions
|
|
||||||
@Field
|
|
||||||
def utils
|
|
||||||
|
|
||||||
def buildMatrix = [
|
|
||||||
[ "enabled": true, "os" : "linux", "withGpu": true, "withNccl": true, "withOmp": true, "pythonVersion": "2.7", "cudaVersion": "9.2", "multiGpu": true],
|
|
||||||
[ "enabled": true, "os" : "linux", "withGpu": true, "withNccl": true, "withOmp": true, "pythonVersion": "2.7", "cudaVersion": "9.2" ],
|
|
||||||
[ "enabled": true, "os" : "linux", "withGpu": true, "withNccl": true, "withOmp": true, "pythonVersion": "2.7", "cudaVersion": "8.0" ],
|
|
||||||
[ "enabled": true, "os" : "linux", "withGpu": true, "withNccl": false, "withOmp": true, "pythonVersion": "2.7", "cudaVersion": "8.0" ],
|
|
||||||
]
|
|
||||||
|
|
||||||
pipeline {
|
pipeline {
|
||||||
// Each stage specify its own agent
|
// Each stage specify its own agent
|
||||||
agent none
|
agent none
|
||||||
|
|
||||||
// Setup common job properties
|
environment {
|
||||||
options {
|
DOCKER_CACHE_REPO = '492475357299.dkr.ecr.us-west-2.amazonaws.com'
|
||||||
ansiColor('xterm')
|
|
||||||
timestamps()
|
|
||||||
timeout(time: 120, unit: 'MINUTES')
|
|
||||||
buildDiscarder(logRotator(numToKeepStr: '10'))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build stages
|
|
||||||
stages {
|
|
||||||
stage('Jenkins: Get sources') {
|
|
||||||
agent {
|
|
||||||
label 'unrestricted'
|
|
||||||
}
|
|
||||||
steps {
|
|
||||||
script {
|
|
||||||
utils = load('tests/ci_build/jenkins_tools.Groovy')
|
|
||||||
utils.checkoutSrcs()
|
|
||||||
}
|
|
||||||
stash name: 'srcs', excludes: '.git/'
|
|
||||||
milestone label: 'Sources ready', ordinal: 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage('Jenkins: Build & Test') {
|
|
||||||
steps {
|
|
||||||
script {
|
|
||||||
parallel (buildMatrix.findAll{it['enabled']}.collectEntries{ c ->
|
|
||||||
def buildName = utils.getBuildName(c)
|
|
||||||
utils.buildFactory(buildName, c, false, this.&buildPlatformCmake)
|
|
||||||
} + [ "clang-tidy" : { buildClangTidyJob() } ])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Build platform and test it via cmake.
|
|
||||||
*/
|
|
||||||
def buildPlatformCmake(buildName, conf, nodeReq, dockerTarget) {
|
|
||||||
def opts = utils.cmakeOptions(conf)
|
|
||||||
// Destination dir for artifacts
|
|
||||||
def distDir = "dist/${buildName}"
|
|
||||||
def dockerArgs = ""
|
|
||||||
if (conf["withGpu"]) {
|
|
||||||
dockerArgs = "--build-arg CUDA_VERSION=" + conf["cudaVersion"]
|
|
||||||
}
|
|
||||||
def test_suite = conf["withGpu"] ? (conf["multiGpu"] ? "mgpu" : "gpu") : "cpu"
|
|
||||||
// Build node - this is returned result
|
|
||||||
retry(1) {
|
|
||||||
node(nodeReq) {
|
|
||||||
unstash name: 'srcs'
|
|
||||||
echo """
|
|
||||||
|===== XGBoost CMake build =====
|
|
||||||
| dockerTarget: ${dockerTarget}
|
|
||||||
| cmakeOpts : ${opts}
|
|
||||||
|=========================
|
|
||||||
""".stripMargin('|')
|
|
||||||
// Invoke command inside docker
|
|
||||||
sh """
|
|
||||||
${dockerRun} ${dockerTarget} ${dockerArgs} tests/ci_build/build_via_cmake.sh ${opts}
|
|
||||||
${dockerRun} ${dockerTarget} ${dockerArgs} tests/ci_build/test_${test_suite}.sh
|
|
||||||
"""
|
|
||||||
if (!conf["multiGpu"]) {
|
|
||||||
sh """
|
|
||||||
${dockerRun} ${dockerTarget} ${dockerArgs} bash -c "cd python-package; rm -f dist/*; python setup.py bdist_wheel --universal"
|
|
||||||
rm -rf "${distDir}"; mkdir -p "${distDir}/py"
|
|
||||||
cp xgboost "${distDir}"
|
|
||||||
cp -r python-package/dist "${distDir}/py"
|
|
||||||
# Test the wheel for compatibility on a barebones CPU container
|
|
||||||
${dockerRun} release ${dockerArgs} bash -c " \
|
|
||||||
pip install --user python-package/dist/xgboost-*-none-any.whl && \
|
|
||||||
pytest -v --fulltrace -s tests/python"
|
|
||||||
# Test the wheel for compatibility on CUDA 10.0 container
|
|
||||||
${dockerRun} gpu --build-arg CUDA_VERSION=10.0 bash -c " \
|
|
||||||
pip install --user python-package/dist/xgboost-*-none-any.whl && \
|
|
||||||
pytest -v -s --fulltrace -m '(not mgpu) and (not slow)' tests/python-gpu"
|
|
||||||
"""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Run a clang-tidy job on a GPU machine
|
|
||||||
*/
|
|
||||||
def buildClangTidyJob() {
|
|
||||||
def nodeReq = "linux && gpu && unrestricted"
|
|
||||||
node(nodeReq) {
|
|
||||||
unstash name: 'srcs'
|
|
||||||
echo "Running clang-tidy job..."
|
|
||||||
// Invoke command inside docker
|
|
||||||
// Install Google Test and Python yaml
|
|
||||||
dockerTarget = "clang_tidy"
|
|
||||||
dockerArgs = "--build-arg CUDA_VERSION=9.2"
|
|
||||||
sh """
|
|
||||||
${dockerRun} ${dockerTarget} ${dockerArgs} tests/ci_build/clang_tidy.sh
|
|
||||||
"""
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Setup common job properties
|
||||||
|
options {
|
||||||
|
ansiColor('xterm')
|
||||||
|
timestamps()
|
||||||
|
timeout(time: 120, unit: 'MINUTES')
|
||||||
|
buildDiscarder(logRotator(numToKeepStr: '10'))
|
||||||
|
preserveStashes()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build stages
|
||||||
|
stages {
|
||||||
|
stage('Jenkins Linux: Get sources') {
|
||||||
|
agent { label 'linux && cpu' }
|
||||||
|
steps {
|
||||||
|
script {
|
||||||
|
checkoutSrcs()
|
||||||
|
}
|
||||||
|
stash name: 'srcs'
|
||||||
|
milestone ordinal: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage('Jenkins Linux: Formatting Check') {
|
||||||
|
agent none
|
||||||
|
steps {
|
||||||
|
script {
|
||||||
|
parallel ([
|
||||||
|
'clang-tidy': { ClangTidy() },
|
||||||
|
'lint': { Lint() },
|
||||||
|
'sphinx-doc': { SphinxDoc() },
|
||||||
|
'doxygen': { Doxygen() }
|
||||||
|
])
|
||||||
|
}
|
||||||
|
milestone ordinal: 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage('Jenkins Linux: Build') {
|
||||||
|
agent none
|
||||||
|
steps {
|
||||||
|
script {
|
||||||
|
parallel ([
|
||||||
|
'build-cpu': { BuildCPU() },
|
||||||
|
'build-gpu-cuda8.0': { BuildCUDA(cuda_version: '8.0') },
|
||||||
|
'build-gpu-cuda9.0': { BuildCUDA(cuda_version: '9.0') },
|
||||||
|
'build-gpu-cuda10.0': { BuildCUDA(cuda_version: '10.0') },
|
||||||
|
'build-gpu-cuda10.1': { BuildCUDA(cuda_version: '10.1') },
|
||||||
|
'build-jvm-packages': { BuildJVMPackages(spark_version: '2.4.3') },
|
||||||
|
'build-jvm-doc': { BuildJVMDoc() }
|
||||||
|
])
|
||||||
|
}
|
||||||
|
milestone ordinal: 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage('Jenkins Linux: Test') {
|
||||||
|
agent none
|
||||||
|
steps {
|
||||||
|
script {
|
||||||
|
parallel ([
|
||||||
|
'test-python-cpu': { TestPythonCPU() },
|
||||||
|
'test-python-gpu-cuda8.0': { TestPythonGPU(cuda_version: '8.0') },
|
||||||
|
'test-python-gpu-cuda9.0': { TestPythonGPU(cuda_version: '9.0') },
|
||||||
|
'test-python-gpu-cuda10.0': { TestPythonGPU(cuda_version: '10.0') },
|
||||||
|
'test-python-gpu-cuda10.1': { TestPythonGPU(cuda_version: '10.1') },
|
||||||
|
'test-python-mgpu-cuda10.1': { TestPythonGPU(cuda_version: '10.1', multi_gpu: true) },
|
||||||
|
'test-cpp-gpu': { TestCppGPU(cuda_version: '10.1') },
|
||||||
|
'test-cpp-mgpu': { TestCppGPU(cuda_version: '10.1', multi_gpu: true) },
|
||||||
|
'test-jvm-jdk8': { CrossTestJVMwithJDK(jdk_version: '8', spark_version: '2.4.3') },
|
||||||
|
'test-jvm-jdk11': { CrossTestJVMwithJDK(jdk_version: '11') },
|
||||||
|
'test-jvm-jdk12': { CrossTestJVMwithJDK(jdk_version: '12') },
|
||||||
|
'test-r-3.4.4': { TestR(use_r35: false) },
|
||||||
|
'test-r-3.5.3': { TestR(use_r35: true) }
|
||||||
|
])
|
||||||
|
}
|
||||||
|
milestone ordinal: 4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check out source code from git
|
||||||
|
def checkoutSrcs() {
|
||||||
|
retry(5) {
|
||||||
|
try {
|
||||||
|
timeout(time: 2, unit: 'MINUTES') {
|
||||||
|
checkout scm
|
||||||
|
sh 'git submodule update --init'
|
||||||
|
}
|
||||||
|
} catch (exc) {
|
||||||
|
deleteDir()
|
||||||
|
error "Failed to fetch source codes"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def ClangTidy() {
|
||||||
|
node('linux && cpu') {
|
||||||
|
unstash name: 'srcs'
|
||||||
|
echo "Running clang-tidy job..."
|
||||||
|
def container_type = "clang_tidy"
|
||||||
|
def docker_binary = "docker"
|
||||||
|
def dockerArgs = "--build-arg CUDA_VERSION=9.2"
|
||||||
|
sh """
|
||||||
|
${dockerRun} ${container_type} ${docker_binary} ${dockerArgs} tests/ci_build/clang_tidy.sh
|
||||||
|
"""
|
||||||
|
deleteDir()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def Lint() {
|
||||||
|
node('linux && cpu') {
|
||||||
|
unstash name: 'srcs'
|
||||||
|
echo "Running lint..."
|
||||||
|
def container_type = "cpu"
|
||||||
|
def docker_binary = "docker"
|
||||||
|
sh """
|
||||||
|
${dockerRun} ${container_type} ${docker_binary} make lint
|
||||||
|
"""
|
||||||
|
deleteDir()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def SphinxDoc() {
|
||||||
|
node('linux && cpu') {
|
||||||
|
unstash name: 'srcs'
|
||||||
|
echo "Running sphinx-doc..."
|
||||||
|
def container_type = "cpu"
|
||||||
|
def docker_binary = "docker"
|
||||||
|
def docker_extra_params = "CI_DOCKER_EXTRA_PARAMS_INIT='-e SPHINX_GIT_BRANCH=${BRANCH_NAME}'"
|
||||||
|
sh """#!/bin/bash
|
||||||
|
${docker_extra_params} ${dockerRun} ${container_type} ${docker_binary} make -C doc html
|
||||||
|
"""
|
||||||
|
deleteDir()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def Doxygen() {
|
||||||
|
node('linux && cpu') {
|
||||||
|
unstash name: 'srcs'
|
||||||
|
echo "Running doxygen..."
|
||||||
|
def container_type = "cpu"
|
||||||
|
def docker_binary = "docker"
|
||||||
|
sh """
|
||||||
|
${dockerRun} ${container_type} ${docker_binary} tests/ci_build/doxygen.sh ${BRANCH_NAME}
|
||||||
|
"""
|
||||||
|
archiveArtifacts artifacts: "build/${BRANCH_NAME}.tar.bz2", allowEmptyArchive: true
|
||||||
|
echo 'Uploading doc...'
|
||||||
|
s3Upload file: "build/${BRANCH_NAME}.tar.bz2", bucket: 'xgboost-docs', acl: 'PublicRead', path: "doxygen/${BRANCH_NAME}.tar.bz2"
|
||||||
|
deleteDir()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def BuildCPU() {
|
||||||
|
node('linux && cpu') {
|
||||||
|
unstash name: 'srcs'
|
||||||
|
echo "Build CPU"
|
||||||
|
def container_type = "cpu"
|
||||||
|
def docker_binary = "docker"
|
||||||
|
sh """
|
||||||
|
${dockerRun} ${container_type} ${docker_binary} tests/ci_build/build_via_cmake.sh
|
||||||
|
${dockerRun} ${container_type} ${docker_binary} build/testxgboost
|
||||||
|
"""
|
||||||
|
// Sanitizer test
|
||||||
|
def docker_extra_params = "CI_DOCKER_EXTRA_PARAMS_INIT='-e ASAN_SYMBOLIZER_PATH=/usr/bin/llvm-symbolizer -e ASAN_OPTIONS=symbolize=1 --cap-add SYS_PTRACE'"
|
||||||
|
def docker_args = "--build-arg CMAKE_VERSION=3.12"
|
||||||
|
sh """
|
||||||
|
${dockerRun} ${container_type} ${docker_binary} ${docker_args} tests/ci_build/build_via_cmake.sh -DUSE_SANITIZER=ON -DENABLED_SANITIZERS="address" \
|
||||||
|
-DCMAKE_BUILD_TYPE=Debug -DSANITIZER_PATH=/usr/lib/x86_64-linux-gnu/
|
||||||
|
${docker_extra_params} ${dockerRun} ${container_type} ${docker_binary} build/testxgboost
|
||||||
|
"""
|
||||||
|
deleteDir()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def BuildCUDA(args) {
|
||||||
|
node('linux && cpu') {
|
||||||
|
unstash name: 'srcs'
|
||||||
|
echo "Build with CUDA ${args.cuda_version}"
|
||||||
|
def container_type = "gpu_build"
|
||||||
|
def docker_binary = "docker"
|
||||||
|
def docker_args = "--build-arg CUDA_VERSION=${args.cuda_version}"
|
||||||
|
sh """
|
||||||
|
${dockerRun} ${container_type} ${docker_binary} ${docker_args} tests/ci_build/build_via_cmake.sh -DUSE_CUDA=ON -DUSE_NCCL=ON -DOPEN_MP:BOOL=ON
|
||||||
|
${dockerRun} ${container_type} ${docker_binary} ${docker_args} bash -c "cd python-package && rm -rf dist/* && python setup.py bdist_wheel --universal"
|
||||||
|
"""
|
||||||
|
// Stash wheel for CUDA 8.0 / 9.0 target
|
||||||
|
if (args.cuda_version == '8.0') {
|
||||||
|
echo 'Stashing Python wheel...'
|
||||||
|
stash name: 'xgboost_whl_cuda8', includes: 'python-package/dist/*.whl'
|
||||||
|
} else if (args.cuda_version == '9.0') {
|
||||||
|
echo 'Stashing Python wheel...'
|
||||||
|
stash name: 'xgboost_whl_cuda9', includes: 'python-package/dist/*.whl'
|
||||||
|
archiveArtifacts artifacts: "python-package/dist/*.whl", allowEmptyArchive: true
|
||||||
|
echo 'Stashing C++ test executable (testxgboost)...'
|
||||||
|
stash name: 'xgboost_cpp_tests', includes: 'build/testxgboost'
|
||||||
|
}
|
||||||
|
deleteDir()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def BuildJVMPackages(args) {
|
||||||
|
node('linux && cpu') {
|
||||||
|
unstash name: 'srcs'
|
||||||
|
echo "Build XGBoost4J-Spark with Spark ${args.spark_version}"
|
||||||
|
def container_type = "jvm"
|
||||||
|
def docker_binary = "docker"
|
||||||
|
// Use only 4 CPU cores
|
||||||
|
def docker_extra_params = "CI_DOCKER_EXTRA_PARAMS_INIT='--cpuset-cpus 0-3'"
|
||||||
|
sh """
|
||||||
|
${docker_extra_params} ${dockerRun} ${container_type} ${docker_binary} tests/ci_build/build_jvm_packages.sh ${args.spark_version}
|
||||||
|
"""
|
||||||
|
echo 'Stashing XGBoost4J JAR...'
|
||||||
|
stash name: 'xgboost4j_jar', includes: 'jvm-packages/xgboost4j/target/*.jar,jvm-packages/xgboost4j-spark/target/*.jar,jvm-packages/xgboost4j-example/target/*.jar'
|
||||||
|
deleteDir()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def BuildJVMDoc() {
|
||||||
|
node('linux && cpu') {
|
||||||
|
unstash name: 'srcs'
|
||||||
|
echo "Building JVM doc..."
|
||||||
|
def container_type = "jvm"
|
||||||
|
def docker_binary = "docker"
|
||||||
|
sh """
|
||||||
|
${dockerRun} ${container_type} ${docker_binary} tests/ci_build/build_jvm_doc.sh ${BRANCH_NAME}
|
||||||
|
"""
|
||||||
|
archiveArtifacts artifacts: "jvm-packages/${BRANCH_NAME}.tar.bz2", allowEmptyArchive: true
|
||||||
|
echo 'Uploading doc...'
|
||||||
|
s3Upload file: "jvm-packages/${BRANCH_NAME}.tar.bz2", bucket: 'xgboost-docs', acl: 'PublicRead', path: "${BRANCH_NAME}.tar.bz2"
|
||||||
|
deleteDir()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def TestPythonCPU() {
|
||||||
|
node('linux && cpu') {
|
||||||
|
unstash name: 'xgboost_whl_cuda9'
|
||||||
|
unstash name: 'srcs'
|
||||||
|
echo "Test Python CPU"
|
||||||
|
def container_type = "cpu"
|
||||||
|
def docker_binary = "docker"
|
||||||
|
sh """
|
||||||
|
${dockerRun} ${container_type} ${docker_binary} tests/ci_build/test_python.sh cpu
|
||||||
|
"""
|
||||||
|
deleteDir()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def TestPythonGPU(args) {
|
||||||
|
nodeReq = (args.multi_gpu) ? 'linux && mgpu' : 'linux && gpu'
|
||||||
|
node(nodeReq) {
|
||||||
|
if (args.cuda_version == '8.0') {
|
||||||
|
unstash name: 'xgboost_whl_cuda8'
|
||||||
|
} else {
|
||||||
|
unstash name: 'xgboost_whl_cuda9'
|
||||||
|
}
|
||||||
|
unstash name: 'srcs'
|
||||||
|
echo "Test Python GPU: CUDA ${args.cuda_version}"
|
||||||
|
def container_type = "gpu"
|
||||||
|
def docker_binary = "nvidia-docker"
|
||||||
|
def docker_args = "--build-arg CUDA_VERSION=${args.cuda_version}"
|
||||||
|
if (args.multi_gpu) {
|
||||||
|
echo "Using multiple GPUs"
|
||||||
|
sh """
|
||||||
|
${dockerRun} ${container_type} ${docker_binary} ${docker_args} tests/ci_build/test_python.sh mgpu
|
||||||
|
"""
|
||||||
|
} else {
|
||||||
|
echo "Using a single GPU"
|
||||||
|
sh """
|
||||||
|
${dockerRun} ${container_type} ${docker_binary} ${docker_args} tests/ci_build/test_python.sh gpu
|
||||||
|
"""
|
||||||
|
}
|
||||||
|
deleteDir()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def TestCppGPU(args) {
|
||||||
|
nodeReq = (args.multi_gpu) ? 'linux && mgpu' : 'linux && gpu'
|
||||||
|
node(nodeReq) {
|
||||||
|
unstash name: 'xgboost_cpp_tests'
|
||||||
|
unstash name: 'srcs'
|
||||||
|
echo "Test C++, CUDA ${args.cuda_version}"
|
||||||
|
def container_type = "gpu"
|
||||||
|
def docker_binary = "nvidia-docker"
|
||||||
|
def docker_args = "--build-arg CUDA_VERSION=${args.cuda_version}"
|
||||||
|
if (args.multi_gpu) {
|
||||||
|
echo "Using multiple GPUs"
|
||||||
|
sh "${dockerRun} ${container_type} ${docker_binary} ${docker_args} build/testxgboost --gtest_filter=*.MGPU_*"
|
||||||
|
} else {
|
||||||
|
echo "Using a single GPU"
|
||||||
|
sh "${dockerRun} ${container_type} ${docker_binary} ${docker_args} build/testxgboost --gtest_filter=-*.MGPU_*"
|
||||||
|
}
|
||||||
|
deleteDir()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def CrossTestJVMwithJDK(args) {
|
||||||
|
node('linux && cpu') {
|
||||||
|
unstash name: 'xgboost4j_jar'
|
||||||
|
unstash name: 'srcs'
|
||||||
|
if (args.spark_version != null) {
|
||||||
|
echo "Test XGBoost4J on a machine with JDK ${args.jdk_version}, Spark ${args.spark_version}"
|
||||||
|
} else {
|
||||||
|
echo "Test XGBoost4J on a machine with JDK ${args.jdk_version}"
|
||||||
|
}
|
||||||
|
def container_type = "jvm_cross"
|
||||||
|
def docker_binary = "docker"
|
||||||
|
def spark_arg = (args.spark_version != null) ? "--build-arg SPARK_VERSION=${args.spark_version}" : ""
|
||||||
|
def docker_args = "--build-arg JDK_VERSION=${args.jdk_version} ${spark_arg}"
|
||||||
|
// Run integration tests only when spark_version is given
|
||||||
|
def docker_extra_params = (args.spark_version != null) ? "CI_DOCKER_EXTRA_PARAMS_INIT='-e RUN_INTEGRATION_TEST=1'" : ""
|
||||||
|
sh """
|
||||||
|
${docker_extra_params} ${dockerRun} ${container_type} ${docker_binary} ${docker_args} tests/ci_build/test_jvm_cross.sh
|
||||||
|
"""
|
||||||
|
deleteDir()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def TestR(args) {
|
||||||
|
node('linux && cpu') {
|
||||||
|
unstash name: 'srcs'
|
||||||
|
echo "Test R package"
|
||||||
|
def container_type = "rproject"
|
||||||
|
def docker_binary = "docker"
|
||||||
|
def use_r35_flag = (args.use_r35) ? "1" : "0"
|
||||||
|
def docker_args = "--build-arg USE_R35=${use_r35_flag}"
|
||||||
|
sh """
|
||||||
|
${dockerRun} ${container_type} ${docker_binary} ${docker_args} tests/ci_build/build_test_rpkg.sh
|
||||||
|
"""
|
||||||
|
deleteDir()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,123 +0,0 @@
|
|||||||
#!/usr/bin/groovy
|
|
||||||
// -*- mode: groovy -*-
|
|
||||||
// Jenkins pipeline
|
|
||||||
// See documents at https://jenkins.io/doc/book/pipeline/jenkinsfile/
|
|
||||||
|
|
||||||
import groovy.transform.Field
|
|
||||||
|
|
||||||
/* Restricted tasks: tasks generating artifacts, such as binary wheels and
|
|
||||||
documentation */
|
|
||||||
|
|
||||||
// Command to run command inside a docker container
|
|
||||||
def dockerRun = 'tests/ci_build/ci_build.sh'
|
|
||||||
// Utility functions
|
|
||||||
@Field
|
|
||||||
def utils
|
|
||||||
@Field
|
|
||||||
def commit_id
|
|
||||||
@Field
|
|
||||||
def branch_name
|
|
||||||
|
|
||||||
def buildMatrix = [
|
|
||||||
[ "enabled": true, "os" : "linux", "withGpu": true, "withNccl": true, "withOmp": true, "pythonVersion": "2.7", "cudaVersion": "9.2" ],
|
|
||||||
[ "enabled": true, "os" : "linux", "withGpu": true, "withNccl": true, "withOmp": true, "pythonVersion": "2.7", "cudaVersion": "8.0" ],
|
|
||||||
[ "enabled": true, "os" : "linux", "withGpu": true, "withNccl": false, "withOmp": true, "pythonVersion": "2.7", "cudaVersion": "8.0" ],
|
|
||||||
]
|
|
||||||
|
|
||||||
pipeline {
|
|
||||||
// Each stage specify its own agent
|
|
||||||
agent none
|
|
||||||
|
|
||||||
// Setup common job properties
|
|
||||||
options {
|
|
||||||
ansiColor('xterm')
|
|
||||||
timestamps()
|
|
||||||
timeout(time: 120, unit: 'MINUTES')
|
|
||||||
buildDiscarder(logRotator(numToKeepStr: '10'))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build stages
|
|
||||||
stages {
|
|
||||||
stage('Jenkins: Get sources') {
|
|
||||||
agent {
|
|
||||||
label 'restricted'
|
|
||||||
}
|
|
||||||
steps {
|
|
||||||
script {
|
|
||||||
utils = load('tests/ci_build/jenkins_tools.Groovy')
|
|
||||||
utils.checkoutSrcs()
|
|
||||||
commit_id = "${GIT_COMMIT}"
|
|
||||||
branch_name = "${GIT_LOCAL_BRANCH}"
|
|
||||||
}
|
|
||||||
stash name: 'srcs', excludes: '.git/'
|
|
||||||
milestone label: 'Sources ready', ordinal: 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage('Jenkins: Build doc') {
|
|
||||||
steps {
|
|
||||||
script {
|
|
||||||
retry(1) {
|
|
||||||
node('linux && cpu && restricted') {
|
|
||||||
unstash name: 'srcs'
|
|
||||||
echo 'Building doc...'
|
|
||||||
dir ('jvm-packages') {
|
|
||||||
sh "bash ./build_doc.sh ${commit_id}"
|
|
||||||
archiveArtifacts artifacts: "${commit_id}.tar.bz2", allowEmptyArchive: true
|
|
||||||
echo 'Deploying doc...'
|
|
||||||
withAWS(credentials:'xgboost-doc-bucket') {
|
|
||||||
s3Upload file: "${commit_id}.tar.bz2", bucket: 'xgboost-docs', acl: 'PublicRead', path: "${branch_name}.tar.bz2"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stage('Jenkins: Build artifacts') {
|
|
||||||
steps {
|
|
||||||
script {
|
|
||||||
parallel (buildMatrix.findAll{it['enabled']}.collectEntries{ c ->
|
|
||||||
def buildName = utils.getBuildName(c)
|
|
||||||
utils.buildFactory(buildName, c, true, this.&buildPlatformCmake)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Build platform and test it via cmake.
|
|
||||||
*/
|
|
||||||
def buildPlatformCmake(buildName, conf, nodeReq, dockerTarget) {
|
|
||||||
def opts = utils.cmakeOptions(conf)
|
|
||||||
// Destination dir for artifacts
|
|
||||||
def distDir = "dist/${buildName}"
|
|
||||||
def dockerArgs = ""
|
|
||||||
if(conf["withGpu"]){
|
|
||||||
dockerArgs = "--build-arg CUDA_VERSION=" + conf["cudaVersion"]
|
|
||||||
}
|
|
||||||
// Build node - this is returned result
|
|
||||||
retry(1) {
|
|
||||||
node(nodeReq) {
|
|
||||||
unstash name: 'srcs'
|
|
||||||
echo """
|
|
||||||
|===== XGBoost CMake build =====
|
|
||||||
| dockerTarget: ${dockerTarget}
|
|
||||||
| cmakeOpts : ${opts}
|
|
||||||
|=========================
|
|
||||||
""".stripMargin('|')
|
|
||||||
// Invoke command inside docker
|
|
||||||
sh """
|
|
||||||
${dockerRun} ${dockerTarget} ${dockerArgs} tests/ci_build/build_via_cmake.sh ${opts}
|
|
||||||
${dockerRun} ${dockerTarget} ${dockerArgs} bash -c "cd python-package; rm -f dist/*; python setup.py bdist_wheel --universal"
|
|
||||||
rm -rf "${distDir}"; mkdir -p "${distDir}/py"
|
|
||||||
cp xgboost "${distDir}"
|
|
||||||
cp -r lib "${distDir}"
|
|
||||||
cp -r python-package/dist "${distDir}/py"
|
|
||||||
"""
|
|
||||||
archiveArtifacts artifacts: "${distDir}/**/*.*", allowEmptyArchive: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
134
Jenkinsfile-win64
Normal file
134
Jenkinsfile-win64
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
#!/usr/bin/groovy
|
||||||
|
// -*- mode: groovy -*-
|
||||||
|
|
||||||
|
/* Jenkins pipeline for Windows AMD64 target */
|
||||||
|
|
||||||
|
pipeline {
|
||||||
|
agent none
|
||||||
|
// Build stages
|
||||||
|
stages {
|
||||||
|
stage('Jenkins Win64: Get sources') {
|
||||||
|
agent { label 'win64 && build' }
|
||||||
|
steps {
|
||||||
|
script {
|
||||||
|
checkoutSrcs()
|
||||||
|
}
|
||||||
|
stash name: 'srcs'
|
||||||
|
milestone ordinal: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage('Jenkins Win64: Build') {
|
||||||
|
agent none
|
||||||
|
steps {
|
||||||
|
script {
|
||||||
|
parallel ([
|
||||||
|
'build-win64-cuda9.0': { BuildWin64() }
|
||||||
|
])
|
||||||
|
}
|
||||||
|
milestone ordinal: 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage('Jenkins Win64: Test') {
|
||||||
|
agent none
|
||||||
|
steps {
|
||||||
|
script {
|
||||||
|
parallel ([
|
||||||
|
'test-win64-cpu': { TestWin64CPU() },
|
||||||
|
'test-win64-gpu-cuda9.0': { TestWin64GPU(cuda_target: 'cuda9') },
|
||||||
|
'test-win64-gpu-cuda10.0': { TestWin64GPU(cuda_target: 'cuda10_0') },
|
||||||
|
'test-win64-gpu-cuda10.1': { TestWin64GPU(cuda_target: 'cuda10_1') }
|
||||||
|
])
|
||||||
|
}
|
||||||
|
milestone ordinal: 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check out source code from git
|
||||||
|
def checkoutSrcs() {
|
||||||
|
retry(5) {
|
||||||
|
try {
|
||||||
|
timeout(time: 2, unit: 'MINUTES') {
|
||||||
|
checkout scm
|
||||||
|
sh 'git submodule update --init'
|
||||||
|
}
|
||||||
|
} catch (exc) {
|
||||||
|
deleteDir()
|
||||||
|
error "Failed to fetch source codes"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def BuildWin64() {
|
||||||
|
node('win64 && build') {
|
||||||
|
unstash name: 'srcs'
|
||||||
|
echo "Building XGBoost for Windows AMD64 target..."
|
||||||
|
bat "nvcc --version"
|
||||||
|
bat """
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
cmake .. -G"Visual Studio 15 2017 Win64" -DUSE_CUDA=ON -DCMAKE_VERBOSE_MAKEFILE=ON -DGOOGLE_TEST=ON -DUSE_DMLC_GTEST=ON
|
||||||
|
"""
|
||||||
|
bat """
|
||||||
|
cd build
|
||||||
|
"C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community\\MSBuild\\15.0\\Bin\\MSBuild.exe" xgboost.sln /m /p:Configuration=Release /nodeReuse:false
|
||||||
|
"""
|
||||||
|
bat """
|
||||||
|
cd python-package
|
||||||
|
conda activate && python setup.py bdist_wheel --universal
|
||||||
|
"""
|
||||||
|
echo "Insert vcomp140.dll (OpenMP runtime) into the wheel..."
|
||||||
|
bat """
|
||||||
|
cd python-package\\dist
|
||||||
|
COPY /B ..\\..\\tests\\ci_build\\insert_vcomp140.py
|
||||||
|
conda activate && python insert_vcomp140.py *.whl
|
||||||
|
"""
|
||||||
|
echo 'Stashing Python wheel...'
|
||||||
|
stash name: 'xgboost_whl', includes: 'python-package/dist/*.whl'
|
||||||
|
archiveArtifacts artifacts: "python-package/dist/*.whl", allowEmptyArchive: true
|
||||||
|
echo 'Stashing C++ test executable (testxgboost)...'
|
||||||
|
stash name: 'xgboost_cpp_tests', includes: 'build/testxgboost.exe'
|
||||||
|
deleteDir()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def TestWin64CPU() {
|
||||||
|
node('win64 && cpu') {
|
||||||
|
unstash name: 'srcs'
|
||||||
|
unstash name: 'xgboost_whl'
|
||||||
|
echo "Test Win64 CPU"
|
||||||
|
echo "Installing Python wheel..."
|
||||||
|
bat "conda activate && (python -m pip uninstall -y xgboost || cd .)"
|
||||||
|
bat """
|
||||||
|
conda activate && for /R %%i in (python-package\\dist\\*.whl) DO python -m pip install "%%i"
|
||||||
|
"""
|
||||||
|
echo "Running Python tests..."
|
||||||
|
bat "conda activate && python -m pytest -v -s --fulltrace tests\\python"
|
||||||
|
bat "conda activate && python -m pip uninstall -y xgboost"
|
||||||
|
deleteDir()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def TestWin64GPU(args) {
|
||||||
|
node("win64 && gpu && ${args.cuda_target}") {
|
||||||
|
unstash name: 'srcs'
|
||||||
|
unstash name: 'xgboost_whl'
|
||||||
|
unstash name: 'xgboost_cpp_tests'
|
||||||
|
echo "Test Win64 GPU (${args.cuda_target})"
|
||||||
|
bat "nvcc --version"
|
||||||
|
echo "Running C++ tests..."
|
||||||
|
bat "build\\testxgboost.exe"
|
||||||
|
echo "Installing Python wheel..."
|
||||||
|
bat "conda activate && (python -m pip uninstall -y xgboost || cd .)"
|
||||||
|
bat """
|
||||||
|
conda activate && for /R %%i in (python-package\\dist\\*.whl) DO python -m pip install "%%i"
|
||||||
|
"""
|
||||||
|
echo "Running Python tests..."
|
||||||
|
bat """
|
||||||
|
conda activate && python -m pytest -v -s --fulltrace -m "(not slow) and (not mgpu)" tests\\python-gpu
|
||||||
|
"""
|
||||||
|
bat "conda activate && python -m pip uninstall -y xgboost"
|
||||||
|
deleteDir()
|
||||||
|
}
|
||||||
|
}
|
||||||
8
Makefile
8
Makefile
@@ -173,10 +173,14 @@ xgboost: $(CLI_OBJ) $(ALL_DEP)
|
|||||||
$(CXX) $(CFLAGS) -o $@ $(filter %.o %.a, $^) $(LDFLAGS)
|
$(CXX) $(CFLAGS) -o $@ $(filter %.o %.a, $^) $(LDFLAGS)
|
||||||
|
|
||||||
rcpplint:
|
rcpplint:
|
||||||
python2 dmlc-core/scripts/lint.py xgboost ${LINT_LANG} R-package/src
|
python3 dmlc-core/scripts/lint.py xgboost ${LINT_LANG} R-package/src
|
||||||
|
|
||||||
lint: rcpplint
|
lint: rcpplint
|
||||||
python2 dmlc-core/scripts/lint.py xgboost ${LINT_LANG} include src plugin python-package
|
python3 dmlc-core/scripts/lint.py --exclude_path python-package/xgboost/dmlc-core \
|
||||||
|
python-package/xgboost/include python-package/xgboost/lib \
|
||||||
|
python-package/xgboost/make python-package/xgboost/rabit \
|
||||||
|
python-package/xgboost/src --pylint-rc ${PWD}/python-package/.pylintrc xgboost \
|
||||||
|
${LINT_LANG} include src plugin python-package
|
||||||
|
|
||||||
pylint:
|
pylint:
|
||||||
flake8 --ignore E501 python-package
|
flake8 --ignore E501 python-package
|
||||||
|
|||||||
136
NEWS.md
136
NEWS.md
@@ -3,6 +3,142 @@ XGBoost Change Log
|
|||||||
|
|
||||||
This file records the changes in xgboost library in reverse chronological order.
|
This file records the changes in xgboost library in reverse chronological order.
|
||||||
|
|
||||||
|
## v0.90 (2019.05.18)
|
||||||
|
|
||||||
|
### XGBoost Python package drops Python 2.x (#4379, #4381)
|
||||||
|
Python 2.x is reaching its end-of-life at the end of this year. [Many scientific Python packages are now moving to drop Python 2.x](https://python3statement.org/).
|
||||||
|
|
||||||
|
### XGBoost4J-Spark now requires Spark 2.4.x (#4377)
|
||||||
|
* Spark 2.3 is reaching its end-of-life soon. See discussion at #4389.
|
||||||
|
* **Consistent handling of missing values** (#4309, #4349, #4411): Many users had reported issue with inconsistent predictions between XGBoost4J-Spark and the Python XGBoost package. The issue was caused by Spark mis-handling non-zero missing values (NaN, -1, 999 etc). We now alert the user whenever Spark doesn't handle missing values correctly (#4309, #4349). See [the tutorial for dealing with missing values in XGBoost4J-Spark](https://xgboost.readthedocs.io/en/release_0.90/jvm/xgboost4j_spark_tutorial.html#dealing-with-missing-values). This fix also depends on the availability of Spark 2.4.x.
|
||||||
|
|
||||||
|
### Roadmap: better performance scaling for multi-core CPUs (#4310)
|
||||||
|
* Poor performance scaling of the `hist` algorithm for multi-core CPUs has been under investigation (#3810). #4310 optimizes quantile sketches and other pre-processing tasks. Special thanks to @SmirnovEgorRu.
|
||||||
|
|
||||||
|
### Roadmap: Harden distributed training (#4250)
|
||||||
|
* Make distributed training in XGBoost more robust by hardening [Rabit](https://github.com/dmlc/rabit), which implements [the AllReduce primitive](https://en.wikipedia.org/wiki/Reduce_%28parallel_pattern%29). In particular, improve test coverage on mechanisms for fault tolerance and recovery. Special thanks to @chenqin.
|
||||||
|
|
||||||
|
### New feature: Multi-class metric functions for GPUs (#4368)
|
||||||
|
* Metrics for multi-class classification have been ported to GPU: `merror`, `mlogloss`. Special thanks to @trivialfis.
|
||||||
|
* With supported metrics, XGBoost will select the correct devices based on your system and `n_gpus` parameter.
|
||||||
|
|
||||||
|
### New feature: Scikit-learn-like random forest API (#4148, #4255, #4258)
|
||||||
|
* XGBoost Python package now offers `XGBRFClassifier` and `XGBRFRegressor` API to train random forests. See [the tutorial](https://xgboost.readthedocs.io/en/release_0.90/tutorials/rf.html). Special thanks to @canonizer
|
||||||
|
|
||||||
|
### New feature: use external memory in GPU predictor (#4284, #4396, #4438, #4457)
|
||||||
|
* It is now possible to make predictions on GPU when the input is read from external memory. This is useful when you want to make predictions with big dataset that does not fit into the GPU memory. Special thanks to @rongou, @canonizer, @sriramch.
|
||||||
|
|
||||||
|
```python
|
||||||
|
dtest = xgboost.DMatrix('test_data.libsvm#dtest.cache')
|
||||||
|
bst.set_param('predictor', 'gpu_predictor')
|
||||||
|
bst.predict(dtest)
|
||||||
|
```
|
||||||
|
|
||||||
|
* Coming soon: GPU training (`gpu_hist`) with external memory
|
||||||
|
|
||||||
|
### New feature: XGBoost can now handle comments in LIBSVM files (#4430)
|
||||||
|
* Special thanks to @trivialfis and @hcho3
|
||||||
|
|
||||||
|
### New feature: Embed XGBoost in your C/C++ applications using CMake (#4323, #4333, #4453)
|
||||||
|
* It is now easier than ever to embed XGBoost in your C/C++ applications. In your CMakeLists.txt, add `xgboost::xgboost` as a linked library:
|
||||||
|
|
||||||
|
```cmake
|
||||||
|
find_package(xgboost REQUIRED)
|
||||||
|
add_executable(api-demo c-api-demo.c)
|
||||||
|
target_link_libraries(api-demo xgboost::xgboost)
|
||||||
|
```
|
||||||
|
|
||||||
|
[XGBoost C API documentation is available.](https://xgboost.readthedocs.io/en/release_0.90/dev) Special thanks to @trivialfis
|
||||||
|
|
||||||
|
### Performance improvements
|
||||||
|
* Use feature interaction constraints to narrow split search space (#4341, #4428)
|
||||||
|
* Additional optimizations for `gpu_hist` (#4248, #4283)
|
||||||
|
* Reduce OpenMP thread launches in `gpu_hist` (#4343)
|
||||||
|
* Additional optimizations for multi-node multi-GPU random forests. (#4238)
|
||||||
|
* Allocate unique prediction buffer for each input matrix, to avoid re-sizing GPU array (#4275)
|
||||||
|
* Remove various synchronisations from CUDA API calls (#4205)
|
||||||
|
* XGBoost4J-Spark
|
||||||
|
- Allow the user to control whether to cache partitioned training data, to potentially reduce execution time (#4268)
|
||||||
|
|
||||||
|
### Bug-fixes
|
||||||
|
* Fix node reuse in `hist` (#4404)
|
||||||
|
* Fix GPU histogram allocation (#4347)
|
||||||
|
* Fix matrix attributes not sliced (#4311)
|
||||||
|
* Revise AUC and AUCPR metrics now work with weighted ranking task (#4216, #4436)
|
||||||
|
* Fix timer invocation for InitDataOnce() in `gpu_hist` (#4206)
|
||||||
|
* Fix R-devel errors (#4251)
|
||||||
|
* Make gradient update in GPU linear updater thread-safe (#4259)
|
||||||
|
* Prevent out-of-range access in column matrix (#4231)
|
||||||
|
* Don't store DMatrix handle in Python object until it's initialized, to improve exception safety (#4317)
|
||||||
|
* XGBoost4J-Spark
|
||||||
|
- Fix non-deterministic order within a zipped partition on prediction (#4388)
|
||||||
|
- Remove race condition on tracker shutdown (#4224)
|
||||||
|
- Allow set the parameter `maxLeaves`. (#4226)
|
||||||
|
- Allow partial evaluation of dataframe before prediction (#4407)
|
||||||
|
- Automatically set `maximize_evaluation_metrics` if not explicitly given (#4446)
|
||||||
|
|
||||||
|
### API changes
|
||||||
|
* Deprecate `reg:linear` in favor of `reg:squarederror`. (#4267, #4427)
|
||||||
|
* Add attribute getter and setter to the Booster object in XGBoost4J (#4336)
|
||||||
|
|
||||||
|
### Maintenance: Refactor C++ code for legibility and maintainability
|
||||||
|
* Fix clang-tidy warnings. (#4149)
|
||||||
|
* Remove deprecated C APIs. (#4266)
|
||||||
|
* Use Monitor class to time functions in `hist`. (#4273)
|
||||||
|
* Retire DVec class in favour of c++20 style span for device memory. (#4293)
|
||||||
|
* Improve HostDeviceVector exception safety (#4301)
|
||||||
|
|
||||||
|
### Maintenance: testing, continuous integration, build system
|
||||||
|
* **Major refactor of CMakeLists.txt** (#4323, #4333, #4453): adopt modern CMake and export XGBoost as a target
|
||||||
|
* **Major improvement in Jenkins CI pipeline** (#4234)
|
||||||
|
- Migrate all Linux tests to Jenkins (#4401)
|
||||||
|
- Builds and tests are now de-coupled, to test an artifact against multiple versions of CUDA, JDK, and other dependencies (#4401)
|
||||||
|
- Add Windows GPU to Jenkins CI pipeline (#4463, #4469)
|
||||||
|
* Support CUDA 10.1 (#4223, #4232, #4265, #4468)
|
||||||
|
* Python wheels are now built with CUDA 9.0, so that JIT is not required on Volta architecture (#4459)
|
||||||
|
* Integrate with NVTX CUDA profiler (#4205)
|
||||||
|
* Add a test for cpu predictor using external memory (#4308)
|
||||||
|
* Refactor tests to get rid of duplication (#4358)
|
||||||
|
* Remove test dependency on `craigcitro/r-travis`, since it's deprecated (#4353)
|
||||||
|
* Add files from local R build to `.gitignore` (#4346)
|
||||||
|
* Make XGBoost4J compatible with Java 9+ by revising NativeLibLoader (#4351)
|
||||||
|
* Jenkins build for CUDA 10.0 (#4281)
|
||||||
|
* Remove remaining `silent` and `debug_verbose` in Python tests (#4299)
|
||||||
|
* Use all cores to build XGBoost4J lib on linux (#4304)
|
||||||
|
* Upgrade Jenkins Linux build environment to GCC 5.3.1, CMake 3.6.0 (#4306)
|
||||||
|
* Make CMakeLists.txt compatible with CMake 3.3 (#4420)
|
||||||
|
* Add OpenMP option in CMakeLists.txt (#4339)
|
||||||
|
* Get rid of a few trivial compiler warnings (#4312)
|
||||||
|
* Add external Docker build cache, to speed up builds on Jenkins CI (#4331, #4334, #4458)
|
||||||
|
* Fix Windows tests (#4403)
|
||||||
|
* Fix a broken python test (#4395)
|
||||||
|
* Use a fixed seed to split data in XGBoost4J-Spark tests, for reproducibility (#4417)
|
||||||
|
* Add additional Python tests to test training under constraints (#4426)
|
||||||
|
* Enable building with shared NCCL. (#4447)
|
||||||
|
|
||||||
|
### Usability Improvements, Documentation
|
||||||
|
* Document limitation of one-split-at-a-time Greedy tree learning heuristic (#4233)
|
||||||
|
* Update build doc: PyPI wheel now support multi-GPU (#4219)
|
||||||
|
* Fix docs for `num_parallel_tree` (#4221)
|
||||||
|
* Fix document about `colsample_by*` parameter (#4340)
|
||||||
|
* Make the train and test input with same colnames. (#4329)
|
||||||
|
* Update R contribute link. (#4236)
|
||||||
|
* Fix travis R tests (#4277)
|
||||||
|
* Log version number in crash log in XGBoost4J-Spark (#4271, #4303)
|
||||||
|
* Allow supression of Rabit output in Booster::train in XGBoost4J (#4262)
|
||||||
|
* Add tutorial on handling missing values in XGBoost4J-Spark (#4425)
|
||||||
|
* Fix typos (#4345, #4393, #4432, #4435)
|
||||||
|
* Added language classifier in setup.py (#4327)
|
||||||
|
* Added Travis CI badge (#4344)
|
||||||
|
* Add BentoML to use case section (#4400)
|
||||||
|
* Remove subtly sexist remark (#4418)
|
||||||
|
* Add R vignette about parsing JSON dumps (#4439)
|
||||||
|
|
||||||
|
### Acknowledgement
|
||||||
|
**Contributors**: Nan Zhu (@CodingCat), Adam Pocock (@Craigacp), Daniel Hen (@Daniel8hen), Jiaxiang Li (@JiaxiangBU), Rory Mitchell (@RAMitchell), Egor Smirnov (@SmirnovEgorRu), Andy Adinets (@canonizer), Jonas (@elcombato), Harry Braviner (@harrybraviner), Philip Hyunsu Cho (@hcho3), Tong He (@hetong007), James Lamb (@jameslamb), Jean-Francois Zinque (@jeffzi), Yang Yang (@jokerkeny), Mayank Suman (@mayanksuman), jess (@monkeywithacupcake), Hajime Morrita (@omo), Ravi Kalia (@project-delphi), @ras44, Rong Ou (@rongou), Shaochen Shi (@shishaochen), Xu Xiao (@sperlingxx), @sriramch, Jiaming Yuan (@trivialfis), Christopher Suchanek (@wsuchy), Bozhao (@yubozhao)
|
||||||
|
|
||||||
|
**Reviewers**: Nan Zhu (@CodingCat), Adam Pocock (@Craigacp), Daniel Hen (@Daniel8hen), Jiaxiang Li (@JiaxiangBU), Laurae (@Laurae2), Rory Mitchell (@RAMitchell), Egor Smirnov (@SmirnovEgorRu), @alois-bissuel, Andy Adinets (@canonizer), Chen Qin (@chenqin), Harry Braviner (@harrybraviner), Philip Hyunsu Cho (@hcho3), Tong He (@hetong007), @jakirkham, James Lamb (@jameslamb), Julien Schueller (@jschueller), Mayank Suman (@mayanksuman), Hajime Morrita (@omo), Rong Ou (@rongou), Sara Robinson (@sararob), Shaochen Shi (@shishaochen), Xu Xiao (@sperlingxx), @sriramch, Sean Owen (@srowen), Sergei Lebedev (@superbobry), Yuan (Terry) Tang (@terrytangyuan), Theodore Vasiloudis (@thvasilo), Matthew Tovbin (@tovbinm), Jiaming Yuan (@trivialfis), Xin Yin (@xydrolase)
|
||||||
|
|
||||||
## v0.82 (2019.03.03)
|
## v0.82 (2019.03.03)
|
||||||
This release is packed with many new features and bug fixes.
|
This release is packed with many new features and bug fixes.
|
||||||
|
|
||||||
|
|||||||
34
R-package/CMakeLists.txt
Normal file
34
R-package/CMakeLists.txt
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
find_package(LibR REQUIRED)
|
||||||
|
message(STATUS "LIBR_CORE_LIBRARY " ${LIBR_CORE_LIBRARY})
|
||||||
|
|
||||||
|
file(GLOB_RECURSE R_SOURCES
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/src/*.cc
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/src/*.c)
|
||||||
|
# Use object library to expose symbols
|
||||||
|
add_library(xgboost-r OBJECT ${R_SOURCES})
|
||||||
|
|
||||||
|
set(R_DEFINITIONS
|
||||||
|
-DXGBOOST_STRICT_R_MODE=1
|
||||||
|
-DXGBOOST_CUSTOMIZE_GLOBAL_PRNG=1
|
||||||
|
-DDMLC_LOG_BEFORE_THROW=0
|
||||||
|
-DDMLC_DISABLE_STDIN=1
|
||||||
|
-DDMLC_LOG_CUSTOMIZE=1
|
||||||
|
-DRABIT_CUSTOMIZE_MSG_
|
||||||
|
-DRABIT_STRICT_CXX98_)
|
||||||
|
target_compile_definitions(xgboost-r
|
||||||
|
PRIVATE ${R_DEFINITIONS})
|
||||||
|
target_include_directories(xgboost-r
|
||||||
|
PRIVATE
|
||||||
|
${LIBR_INCLUDE_DIRS}
|
||||||
|
${PROJECT_SOURCE_DIR}/include
|
||||||
|
${PROJECT_SOURCE_DIR}/dmlc-core/include
|
||||||
|
${PROJECT_SOURCE_DIR}/rabit/include)
|
||||||
|
set_target_properties(
|
||||||
|
xgboost-r PROPERTIES
|
||||||
|
CXX_STANDARD 11
|
||||||
|
CXX_STANDARD_REQUIRED ON
|
||||||
|
POSITION_INDEPENDENT_CODE ON)
|
||||||
|
|
||||||
|
set(XGBOOST_DEFINITIONS ${R_DEFINITIONS} PARENT_SCOPE)
|
||||||
|
set(XGBOOST_OBJ_SOURCES $<TARGET_OBJECTS:xgboost-r> PARENT_SCOPE)
|
||||||
|
set(LINKED_LIBRARIES_PRIVATE ${LINKED_LIBRARIES_PRIVATE} ${LIBR_CORE_LIBRARY} PARENT_SCOPE)
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
Package: xgboost
|
Package: xgboost
|
||||||
Type: Package
|
Type: Package
|
||||||
Title: Extreme Gradient Boosting
|
Title: Extreme Gradient Boosting
|
||||||
Version: 0.81.0.1
|
Version: 0.82.0.1
|
||||||
Date: 2018-08-13
|
Date: 2019-03-11
|
||||||
Authors@R: c(
|
Authors@R: c(
|
||||||
person("Tianqi", "Chen", role = c("aut"),
|
person("Tianqi", "Chen", role = c("aut"),
|
||||||
email = "tianqi.tchen@gmail.com"),
|
email = "tianqi.tchen@gmail.com"),
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
#' WARNING: side-effects!!! Be aware that these callback functions access and modify things in
|
#' WARNING: side-effects!!! Be aware that these callback functions access and modify things in
|
||||||
#' the environment from which they are called from, which is a fairly uncommon thing to do in R.
|
#' the environment from which they are called from, which is a fairly uncommon thing to do in R.
|
||||||
#'
|
#'
|
||||||
#' To write a custom callback closure, make sure you first understand the main concepts about R envoronments.
|
#' To write a custom callback closure, make sure you first understand the main concepts about R environments.
|
||||||
#' Check either R documentation on \code{\link[base]{environment}} or the
|
#' Check either R documentation on \code{\link[base]{environment}} or the
|
||||||
#' \href{http://adv-r.had.co.nz/Environments.html}{Environments chapter} from the "Advanced R"
|
#' \href{http://adv-r.had.co.nz/Environments.html}{Environments chapter} from the "Advanced R"
|
||||||
#' book by Hadley Wickham. Further, the best option is to read the code of some of the existing callbacks -
|
#' book by Hadley Wickham. Further, the best option is to read the code of some of the existing callbacks -
|
||||||
@@ -154,7 +154,7 @@ cb.evaluation.log <- function() {
|
|||||||
callback
|
callback
|
||||||
}
|
}
|
||||||
|
|
||||||
#' Callback closure for restetting the booster's parameters at each iteration.
|
#' Callback closure for resetting the booster's parameters at each iteration.
|
||||||
#'
|
#'
|
||||||
#' @param new_params a list where each element corresponds to a parameter that needs to be reset.
|
#' @param new_params a list where each element corresponds to a parameter that needs to be reset.
|
||||||
#' Each element's value must be either a vector of values of length \code{nrounds}
|
#' Each element's value must be either a vector of values of length \code{nrounds}
|
||||||
@@ -470,7 +470,7 @@ cb.save.model <- function(save_period = 0, save_name = "xgboost.model") {
|
|||||||
#' to the order of rows in the original dataset. Note that when a custom \code{folds} list is
|
#' to the order of rows in the original dataset. Note that when a custom \code{folds} list is
|
||||||
#' provided in \code{xgb.cv}, the predictions would only be returned properly when this list is a
|
#' provided in \code{xgb.cv}, the predictions would only be returned properly when this list is a
|
||||||
#' non-overlapping list of k sets of indices, as in a standard k-fold CV. The predictions would not be
|
#' non-overlapping list of k sets of indices, as in a standard k-fold CV. The predictions would not be
|
||||||
#' meaningful when user-profided folds have overlapping indices as in, e.g., random sampling splits.
|
#' meaningful when user-provided folds have overlapping indices as in, e.g., random sampling splits.
|
||||||
#' When some of the indices in the training dataset are not included into user-provided \code{folds},
|
#' When some of the indices in the training dataset are not included into user-provided \code{folds},
|
||||||
#' their prediction value would be \code{NA}.
|
#' their prediction value would be \code{NA}.
|
||||||
#'
|
#'
|
||||||
@@ -681,7 +681,7 @@ cb.gblinear.history <- function(sparse=FALSE) {
|
|||||||
#' using the \code{cb.gblinear.history()} callback.
|
#' using the \code{cb.gblinear.history()} callback.
|
||||||
#' @param class_index zero-based class index to extract the coefficients for only that
|
#' @param class_index zero-based class index to extract the coefficients for only that
|
||||||
#' specific class in a multinomial multiclass model. When it is NULL, all the
|
#' specific class in a multinomial multiclass model. When it is NULL, all the
|
||||||
#' coeffients are returned. Has no effect in non-multiclass models.
|
#' coefficients are returned. Has no effect in non-multiclass models.
|
||||||
#'
|
#'
|
||||||
#' @return
|
#' @return
|
||||||
#' For an \code{xgb.train} result, a matrix (either dense or sparse) with the columns
|
#' For an \code{xgb.train} result, a matrix (either dense or sparse) with the columns
|
||||||
|
|||||||
@@ -209,13 +209,14 @@ generate.cv.folds <- function(nfold, nrows, stratified, label, params) {
|
|||||||
if (exists('objective', where = params) &&
|
if (exists('objective', where = params) &&
|
||||||
is.character(params$objective)) {
|
is.character(params$objective)) {
|
||||||
# If 'objective' provided in params, assume that y is a classification label
|
# If 'objective' provided in params, assume that y is a classification label
|
||||||
# unless objective is reg:linear
|
# unless objective is reg:squarederror
|
||||||
if (params$objective != 'reg:linear')
|
if (params$objective != 'reg:squarederror')
|
||||||
y <- factor(y)
|
y <- factor(y)
|
||||||
} else {
|
} else {
|
||||||
# If no 'objective' given in params, it means that user either wants to use
|
# If no 'objective' given in params, it means that user either wants to
|
||||||
# the default 'reg:linear' objective or has provided a custom obj function.
|
# use the default 'reg:squarederror' objective or has provided a custom
|
||||||
# Here, assume classification setting when y has 5 or less unique values:
|
# obj function. Here, assume classification setting when y has 5 or less
|
||||||
|
# unique values:
|
||||||
if (length(unique(y)) <= 5)
|
if (length(unique(y)) <= 5)
|
||||||
y <- factor(y)
|
y <- factor(y)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ xgb.get.handle <- function(object) {
|
|||||||
#' its handle (pointer) to an internal xgboost model would be invalid. The majority of xgboost methods
|
#' its handle (pointer) to an internal xgboost model would be invalid. The majority of xgboost methods
|
||||||
#' should still work for such a model object since those methods would be using
|
#' should still work for such a model object since those methods would be using
|
||||||
#' \code{xgb.Booster.complete} internally. However, one might find it to be more efficient to call the
|
#' \code{xgb.Booster.complete} internally. However, one might find it to be more efficient to call the
|
||||||
#' \code{xgb.Booster.complete} function explicitely once after loading a model as an R-object.
|
#' \code{xgb.Booster.complete} function explicitly once after loading a model as an R-object.
|
||||||
#' That would prevent further repeated implicit reconstruction of an internal booster model.
|
#' That would prevent further repeated implicit reconstruction of an internal booster model.
|
||||||
#'
|
#'
|
||||||
#' @return
|
#' @return
|
||||||
@@ -162,7 +162,7 @@ xgb.Booster.complete <- function(object, saveraw = TRUE) {
|
|||||||
#'
|
#'
|
||||||
#' With \code{predinteraction = TRUE}, SHAP values of contributions of interaction of each pair of features
|
#' With \code{predinteraction = TRUE}, SHAP values of contributions of interaction of each pair of features
|
||||||
#' are computed. Note that this operation might be rather expensive in terms of compute and memory.
|
#' are computed. Note that this operation might be rather expensive in terms of compute and memory.
|
||||||
#' Since it quadratically depends on the number of features, it is recommended to perfom selection
|
#' Since it quadratically depends on the number of features, it is recommended to perform selection
|
||||||
#' of the most important features first. See below about the format of the returned results.
|
#' of the most important features first. See below about the format of the returned results.
|
||||||
#'
|
#'
|
||||||
#' @return
|
#' @return
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ dim.xgb.DMatrix <- function(x) {
|
|||||||
#' Handling of column names of \code{xgb.DMatrix}
|
#' Handling of column names of \code{xgb.DMatrix}
|
||||||
#'
|
#'
|
||||||
#' Only column names are supported for \code{xgb.DMatrix}, thus setting of
|
#' Only column names are supported for \code{xgb.DMatrix}, thus setting of
|
||||||
#' row names would have no effect and returnten row names would be NULL.
|
#' row names would have no effect and returned row names would be NULL.
|
||||||
#'
|
#'
|
||||||
#' @param x object of class \code{xgb.DMatrix}
|
#' @param x object of class \code{xgb.DMatrix}
|
||||||
#' @param value a list of two elements: the first one is ignored
|
#' @param value a list of two elements: the first one is ignored
|
||||||
@@ -266,10 +266,10 @@ setinfo.xgb.DMatrix <- function(object, name, info, ...) {
|
|||||||
|
|
||||||
|
|
||||||
#' Get a new DMatrix containing the specified rows of
|
#' Get a new DMatrix containing the specified rows of
|
||||||
#' orginal xgb.DMatrix object
|
#' original xgb.DMatrix object
|
||||||
#'
|
#'
|
||||||
#' Get a new DMatrix containing the specified rows of
|
#' Get a new DMatrix containing the specified rows of
|
||||||
#' orginal xgb.DMatrix object
|
#' original xgb.DMatrix object
|
||||||
#'
|
#'
|
||||||
#' @param object Object of class "xgb.DMatrix"
|
#' @param object Object of class "xgb.DMatrix"
|
||||||
#' @param idxset a integer vector of indices of rows needed
|
#' @param idxset a integer vector of indices of rows needed
|
||||||
@@ -301,12 +301,17 @@ slice.xgb.DMatrix <- function(object, idxset, ...) {
|
|||||||
|
|
||||||
attr_list <- attributes(object)
|
attr_list <- attributes(object)
|
||||||
nr <- nrow(object)
|
nr <- nrow(object)
|
||||||
len <- sapply(attr_list, length)
|
len <- sapply(attr_list, NROW)
|
||||||
ind <- which(len == nr)
|
ind <- which(len == nr)
|
||||||
if (length(ind) > 0) {
|
if (length(ind) > 0) {
|
||||||
nms <- names(attr_list)[ind]
|
nms <- names(attr_list)[ind]
|
||||||
for (i in seq_along(ind)) {
|
for (i in seq_along(ind)) {
|
||||||
attr(ret, nms[i]) <- attr(object, nms[i])[idxset]
|
obj_attr <- attr(object, nms[i])
|
||||||
|
if (NCOL(obj_attr) > 1) {
|
||||||
|
attr(ret, nms[i]) <- obj_attr[idxset,]
|
||||||
|
} else {
|
||||||
|
attr(ret, nms[i]) <- obj_attr[idxset]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return(structure(ret, class = "xgb.DMatrix"))
|
return(structure(ret, class = "xgb.DMatrix"))
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
#' \itemize{
|
#' \itemize{
|
||||||
#' \item \code{objective} objective function, common ones are
|
#' \item \code{objective} objective function, common ones are
|
||||||
#' \itemize{
|
#' \itemize{
|
||||||
#' \item \code{reg:linear} linear regression
|
#' \item \code{reg:squarederror} Regression with squared loss
|
||||||
#' \item \code{binary:logistic} logistic regression for classification
|
#' \item \code{binary:logistic} logistic regression for classification
|
||||||
#' }
|
#' }
|
||||||
#' \item \code{eta} step size of each boosting step
|
#' \item \code{eta} step size of each boosting step
|
||||||
@@ -39,7 +39,7 @@
|
|||||||
#' }
|
#' }
|
||||||
#' @param obj customized objective function. Returns gradient and second order
|
#' @param obj customized objective function. Returns gradient and second order
|
||||||
#' gradient with given prediction and dtrain.
|
#' gradient with given prediction and dtrain.
|
||||||
#' @param feval custimized evaluation function. Returns
|
#' @param feval customized evaluation function. Returns
|
||||||
#' \code{list(metric='metric-name', value='metric-value')} with given
|
#' \code{list(metric='metric-name', value='metric-value')} with given
|
||||||
#' prediction and dtrain.
|
#' prediction and dtrain.
|
||||||
#' @param stratified a \code{boolean} indicating whether sampling of folds should be stratified
|
#' @param stratified a \code{boolean} indicating whether sampling of folds should be stratified
|
||||||
@@ -84,7 +84,7 @@
|
|||||||
#' capture parameters changed by the \code{\link{cb.reset.parameters}} callback.
|
#' capture parameters changed by the \code{\link{cb.reset.parameters}} callback.
|
||||||
#' \item \code{callbacks} callback functions that were either automatically assigned or
|
#' \item \code{callbacks} callback functions that were either automatically assigned or
|
||||||
#' explicitly passed.
|
#' explicitly passed.
|
||||||
#' \item \code{evaluation_log} evaluation history storead as a \code{data.table} with the
|
#' \item \code{evaluation_log} evaluation history stored as a \code{data.table} with the
|
||||||
#' first column corresponding to iteration number and the rest corresponding to the
|
#' first column corresponding to iteration number and the rest corresponding to the
|
||||||
#' CV-based evaluation means and standard deviations for the training and test CV-sets.
|
#' CV-based evaluation means and standard deviations for the training and test CV-sets.
|
||||||
#' It is created by the \code{\link{cb.evaluation.log}} callback.
|
#' It is created by the \code{\link{cb.evaluation.log}} callback.
|
||||||
|
|||||||
@@ -30,8 +30,8 @@
|
|||||||
#' Setting \code{rel_to_first = TRUE} allows to see the picture from the perspective of
|
#' Setting \code{rel_to_first = TRUE} allows to see the picture from the perspective of
|
||||||
#' "what is feature's importance contribution relative to the most important feature?"
|
#' "what is feature's importance contribution relative to the most important feature?"
|
||||||
#'
|
#'
|
||||||
#' The ggplot-backend method also performs 1-D custering of the importance values,
|
#' The ggplot-backend method also performs 1-D clustering of the importance values,
|
||||||
#' with bar colors coresponding to different clusters that have somewhat similar importance values.
|
#' with bar colors corresponding to different clusters that have somewhat similar importance values.
|
||||||
#'
|
#'
|
||||||
#' @return
|
#' @return
|
||||||
#' The \code{xgb.plot.importance} function creates a \code{barplot} (when \code{plot=TRUE})
|
#' The \code{xgb.plot.importance} function creates a \code{barplot} (when \code{plot=TRUE})
|
||||||
|
|||||||
@@ -31,7 +31,7 @@
|
|||||||
#' @param plot_loess whether to plot loess-smoothed curves. The smoothing is only done for features with
|
#' @param plot_loess whether to plot loess-smoothed curves. The smoothing is only done for features with
|
||||||
#' more than 5 distinct values.
|
#' more than 5 distinct values.
|
||||||
#' @param col_loess a color to use for the loess curves.
|
#' @param col_loess a color to use for the loess curves.
|
||||||
#' @param span_loess the \code{span} paramerer in \code{\link[stats]{loess}}'s call.
|
#' @param span_loess the \code{span} parameter in \code{\link[stats]{loess}}'s call.
|
||||||
#' @param which whether to do univariate or bivariate plotting. NOTE: only 1D is implemented so far.
|
#' @param which whether to do univariate or bivariate plotting. NOTE: only 1D is implemented so far.
|
||||||
#' @param plot whether a plot should be drawn. If FALSE, only a lits of matrices is returned.
|
#' @param plot whether a plot should be drawn. If FALSE, only a lits of matrices is returned.
|
||||||
#' @param ... other parameters passed to \code{plot}.
|
#' @param ... other parameters passed to \code{plot}.
|
||||||
|
|||||||
@@ -42,7 +42,7 @@
|
|||||||
#' \itemize{
|
#' \itemize{
|
||||||
#' \item \code{objective} specify the learning task and the corresponding learning objective, users can pass a self-defined function to it. The default objective options are below:
|
#' \item \code{objective} specify the learning task and the corresponding learning objective, users can pass a self-defined function to it. The default objective options are below:
|
||||||
#' \itemize{
|
#' \itemize{
|
||||||
#' \item \code{reg:linear} linear regression (Default).
|
#' \item \code{reg:squarederror} Regression with squared loss (Default).
|
||||||
#' \item \code{reg:logistic} logistic regression.
|
#' \item \code{reg:logistic} logistic regression.
|
||||||
#' \item \code{binary:logistic} logistic regression for binary classification. Output probability.
|
#' \item \code{binary:logistic} logistic regression for binary classification. Output probability.
|
||||||
#' \item \code{binary:logitraw} logistic regression for binary classification, output score before logistic transformation.
|
#' \item \code{binary:logitraw} logistic regression for binary classification, output score before logistic transformation.
|
||||||
@@ -68,7 +68,7 @@
|
|||||||
#' the performance of each round's model on mat1 and mat2.
|
#' the performance of each round's model on mat1 and mat2.
|
||||||
#' @param obj customized objective function. Returns gradient and second order
|
#' @param obj customized objective function. Returns gradient and second order
|
||||||
#' gradient with given prediction and dtrain.
|
#' gradient with given prediction and dtrain.
|
||||||
#' @param feval custimized evaluation function. Returns
|
#' @param feval customized evaluation function. Returns
|
||||||
#' \code{list(metric='metric-name', value='metric-value')} with given
|
#' \code{list(metric='metric-name', value='metric-value')} with given
|
||||||
#' prediction and dtrain.
|
#' prediction and dtrain.
|
||||||
#' @param verbose If 0, xgboost will stay silent. If 1, it will print information about performance.
|
#' @param verbose If 0, xgboost will stay silent. If 1, it will print information about performance.
|
||||||
@@ -118,7 +118,7 @@
|
|||||||
#' when the \code{eval_metric} parameter is not provided.
|
#' when the \code{eval_metric} parameter is not provided.
|
||||||
#' User may set one or several \code{eval_metric} parameters.
|
#' User may set one or several \code{eval_metric} parameters.
|
||||||
#' Note that when using a customized metric, only this single metric can be used.
|
#' Note that when using a customized metric, only this single metric can be used.
|
||||||
#' The folloiwing is the list of built-in metrics for which Xgboost provides optimized implementation:
|
#' The following is the list of built-in metrics for which Xgboost provides optimized implementation:
|
||||||
#' \itemize{
|
#' \itemize{
|
||||||
#' \item \code{rmse} root mean square error. \url{http://en.wikipedia.org/wiki/Root_mean_square_error}
|
#' \item \code{rmse} root mean square error. \url{http://en.wikipedia.org/wiki/Root_mean_square_error}
|
||||||
#' \item \code{logloss} negative log-likelihood. \url{http://en.wikipedia.org/wiki/Log-likelihood}
|
#' \item \code{logloss} negative log-likelihood. \url{http://en.wikipedia.org/wiki/Log-likelihood}
|
||||||
@@ -147,14 +147,14 @@
|
|||||||
#' \item \code{handle} a handle (pointer) to the xgboost model in memory.
|
#' \item \code{handle} a handle (pointer) to the xgboost model in memory.
|
||||||
#' \item \code{raw} a cached memory dump of the xgboost model saved as R's \code{raw} type.
|
#' \item \code{raw} a cached memory dump of the xgboost model saved as R's \code{raw} type.
|
||||||
#' \item \code{niter} number of boosting iterations.
|
#' \item \code{niter} number of boosting iterations.
|
||||||
#' \item \code{evaluation_log} evaluation history storead as a \code{data.table} with the
|
#' \item \code{evaluation_log} evaluation history stored as a \code{data.table} with the
|
||||||
#' first column corresponding to iteration number and the rest corresponding to evaluation
|
#' first column corresponding to iteration number and the rest corresponding to evaluation
|
||||||
#' metrics' values. It is created by the \code{\link{cb.evaluation.log}} callback.
|
#' metrics' values. It is created by the \code{\link{cb.evaluation.log}} callback.
|
||||||
#' \item \code{call} a function call.
|
#' \item \code{call} a function call.
|
||||||
#' \item \code{params} parameters that were passed to the xgboost library. Note that it does not
|
#' \item \code{params} parameters that were passed to the xgboost library. Note that it does not
|
||||||
#' capture parameters changed by the \code{\link{cb.reset.parameters}} callback.
|
#' capture parameters changed by the \code{\link{cb.reset.parameters}} callback.
|
||||||
#' \item \code{callbacks} callback functions that were either automatically assigned or
|
#' \item \code{callbacks} callback functions that were either automatically assigned or
|
||||||
#' explicitely passed.
|
#' explicitly passed.
|
||||||
#' \item \code{best_iteration} iteration number with the best evaluation metric value
|
#' \item \code{best_iteration} iteration number with the best evaluation metric value
|
||||||
#' (only available with early stopping).
|
#' (only available with early stopping).
|
||||||
#' \item \code{best_ntreelimit} the \code{ntreelimit} value corresponding to the best iteration,
|
#' \item \code{best_ntreelimit} the \code{ntreelimit} value corresponding to the best iteration,
|
||||||
@@ -163,7 +163,7 @@
|
|||||||
#' \item \code{best_score} the best evaluation metric value during early stopping.
|
#' \item \code{best_score} the best evaluation metric value during early stopping.
|
||||||
#' (only available with early stopping).
|
#' (only available with early stopping).
|
||||||
#' \item \code{feature_names} names of the training dataset features
|
#' \item \code{feature_names} names of the training dataset features
|
||||||
#' (only when comun names were defined in training data).
|
#' (only when column names were defined in training data).
|
||||||
#' \item \code{nfeatures} number of features in training data.
|
#' \item \code{nfeatures} number of features in training data.
|
||||||
#' }
|
#' }
|
||||||
#'
|
#'
|
||||||
@@ -186,7 +186,7 @@
|
|||||||
#' watchlist <- list(train = dtrain, eval = dtest)
|
#' watchlist <- list(train = dtrain, eval = dtest)
|
||||||
#'
|
#'
|
||||||
#' ## A simple xgb.train example:
|
#' ## A simple xgb.train example:
|
||||||
#' param <- list(max_depth = 2, eta = 1, silent = 1, nthread = 2,
|
#' param <- list(max_depth = 2, eta = 1, verbose = 0, nthread = 2,
|
||||||
#' objective = "binary:logistic", eval_metric = "auc")
|
#' objective = "binary:logistic", eval_metric = "auc")
|
||||||
#' bst <- xgb.train(param, dtrain, nrounds = 2, watchlist)
|
#' bst <- xgb.train(param, dtrain, nrounds = 2, watchlist)
|
||||||
#'
|
#'
|
||||||
@@ -207,12 +207,12 @@
|
|||||||
#'
|
#'
|
||||||
#' # These functions could be used by passing them either:
|
#' # These functions could be used by passing them either:
|
||||||
#' # as 'objective' and 'eval_metric' parameters in the params list:
|
#' # as 'objective' and 'eval_metric' parameters in the params list:
|
||||||
#' param <- list(max_depth = 2, eta = 1, silent = 1, nthread = 2,
|
#' param <- list(max_depth = 2, eta = 1, verbose = 0, nthread = 2,
|
||||||
#' objective = logregobj, eval_metric = evalerror)
|
#' objective = logregobj, eval_metric = evalerror)
|
||||||
#' bst <- xgb.train(param, dtrain, nrounds = 2, watchlist)
|
#' bst <- xgb.train(param, dtrain, nrounds = 2, watchlist)
|
||||||
#'
|
#'
|
||||||
#' # or through the ... arguments:
|
#' # or through the ... arguments:
|
||||||
#' param <- list(max_depth = 2, eta = 1, silent = 1, nthread = 2)
|
#' param <- list(max_depth = 2, eta = 1, verbose = 0, nthread = 2)
|
||||||
#' bst <- xgb.train(param, dtrain, nrounds = 2, watchlist,
|
#' bst <- xgb.train(param, dtrain, nrounds = 2, watchlist,
|
||||||
#' objective = logregobj, eval_metric = evalerror)
|
#' objective = logregobj, eval_metric = evalerror)
|
||||||
#'
|
#'
|
||||||
@@ -222,7 +222,7 @@
|
|||||||
#'
|
#'
|
||||||
#'
|
#'
|
||||||
#' ## An xgb.train example of using variable learning rates at each iteration:
|
#' ## An xgb.train example of using variable learning rates at each iteration:
|
||||||
#' param <- list(max_depth = 2, eta = 1, silent = 1, nthread = 2,
|
#' param <- list(max_depth = 2, eta = 1, verbose = 0, nthread = 2,
|
||||||
#' objective = "binary:logistic", eval_metric = "auc")
|
#' objective = "binary:logistic", eval_metric = "auc")
|
||||||
#' my_etas <- list(eta = c(0.5, 0.1))
|
#' my_etas <- list(eta = c(0.5, 0.1))
|
||||||
#' bst <- xgb.train(param, dtrain, nrounds = 2, watchlist,
|
#' bst <- xgb.train(param, dtrain, nrounds = 2, watchlist,
|
||||||
|
|||||||
@@ -30,4 +30,4 @@ Examples
|
|||||||
Development
|
Development
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
* See the [R Package section](https://xgboost.readthedocs.io/en/latest/how_to/contribute.html#r-package) of the contributors guide.
|
* See the [R Package section](https://xgboost.readthedocs.io/en/latest/contribute.html#r-package) of the contributors guide.
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ create.new.tree.features <- function(model, original.features){
|
|||||||
# Convert previous features to one hot encoding
|
# Convert previous features to one hot encoding
|
||||||
new.features.train <- create.new.tree.features(bst, agaricus.train$data)
|
new.features.train <- create.new.tree.features(bst, agaricus.train$data)
|
||||||
new.features.test <- create.new.tree.features(bst, agaricus.test$data)
|
new.features.test <- create.new.tree.features(bst, agaricus.test$data)
|
||||||
|
colnames(new.features.test) <- colnames(new.features.train)
|
||||||
|
|
||||||
# learning with new features
|
# learning with new features
|
||||||
new.dtrain <- xgb.DMatrix(data = new.features.train, label = agaricus.train$label)
|
new.dtrain <- xgb.DMatrix(data = new.features.train, label = agaricus.train$label)
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ the boosting is completed.
|
|||||||
WARNING: side-effects!!! Be aware that these callback functions access and modify things in
|
WARNING: side-effects!!! Be aware that these callback functions access and modify things in
|
||||||
the environment from which they are called from, which is a fairly uncommon thing to do in R.
|
the environment from which they are called from, which is a fairly uncommon thing to do in R.
|
||||||
|
|
||||||
To write a custom callback closure, make sure you first understand the main concepts about R envoronments.
|
To write a custom callback closure, make sure you first understand the main concepts about R environments.
|
||||||
Check either R documentation on \code{\link[base]{environment}} or the
|
Check either R documentation on \code{\link[base]{environment}} or the
|
||||||
\href{http://adv-r.had.co.nz/Environments.html}{Environments chapter} from the "Advanced R"
|
\href{http://adv-r.had.co.nz/Environments.html}{Environments chapter} from the "Advanced R"
|
||||||
book by Hadley Wickham. Further, the best option is to read the code of some of the existing callbacks -
|
book by Hadley Wickham. Further, the best option is to read the code of some of the existing callbacks -
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ depending on the number of prediction outputs per data row. The order of predict
|
|||||||
to the order of rows in the original dataset. Note that when a custom \code{folds} list is
|
to the order of rows in the original dataset. Note that when a custom \code{folds} list is
|
||||||
provided in \code{xgb.cv}, the predictions would only be returned properly when this list is a
|
provided in \code{xgb.cv}, the predictions would only be returned properly when this list is a
|
||||||
non-overlapping list of k sets of indices, as in a standard k-fold CV. The predictions would not be
|
non-overlapping list of k sets of indices, as in a standard k-fold CV. The predictions would not be
|
||||||
meaningful when user-profided folds have overlapping indices as in, e.g., random sampling splits.
|
meaningful when user-provided folds have overlapping indices as in, e.g., random sampling splits.
|
||||||
When some of the indices in the training dataset are not included into user-provided \code{folds},
|
When some of the indices in the training dataset are not included into user-provided \code{folds},
|
||||||
their prediction value would be \code{NA}.
|
their prediction value would be \code{NA}.
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
% Please edit documentation in R/callbacks.R
|
% Please edit documentation in R/callbacks.R
|
||||||
\name{cb.reset.parameters}
|
\name{cb.reset.parameters}
|
||||||
\alias{cb.reset.parameters}
|
\alias{cb.reset.parameters}
|
||||||
\title{Callback closure for restetting the booster's parameters at each iteration.}
|
\title{Callback closure for resetting the booster's parameters at each iteration.}
|
||||||
\usage{
|
\usage{
|
||||||
cb.reset.parameters(new_params)
|
cb.reset.parameters(new_params)
|
||||||
}
|
}
|
||||||
@@ -15,7 +15,7 @@ which returns a new parameter value by using the current iteration number
|
|||||||
and the total number of boosting rounds.}
|
and the total number of boosting rounds.}
|
||||||
}
|
}
|
||||||
\description{
|
\description{
|
||||||
Callback closure for restetting the booster's parameters at each iteration.
|
Callback closure for resetting the booster's parameters at each iteration.
|
||||||
}
|
}
|
||||||
\details{
|
\details{
|
||||||
This is a "pre-iteration" callback function used to reset booster's parameters
|
This is a "pre-iteration" callback function used to reset booster's parameters
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ and the second one is column names}
|
|||||||
}
|
}
|
||||||
\description{
|
\description{
|
||||||
Only column names are supported for \code{xgb.DMatrix}, thus setting of
|
Only column names are supported for \code{xgb.DMatrix}, thus setting of
|
||||||
row names would have no effect and returnten row names would be NULL.
|
row names would have no effect and returned row names would be NULL.
|
||||||
}
|
}
|
||||||
\details{
|
\details{
|
||||||
Generic \code{dimnames} methods are used by \code{colnames}.
|
Generic \code{dimnames} methods are used by \code{colnames}.
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ in \url{http://blog.datadive.net/interpreting-random-forests/}.
|
|||||||
|
|
||||||
With \code{predinteraction = TRUE}, SHAP values of contributions of interaction of each pair of features
|
With \code{predinteraction = TRUE}, SHAP values of contributions of interaction of each pair of features
|
||||||
are computed. Note that this operation might be rather expensive in terms of compute and memory.
|
are computed. Note that this operation might be rather expensive in terms of compute and memory.
|
||||||
Since it quadratically depends on the number of features, it is recommended to perfom selection
|
Since it quadratically depends on the number of features, it is recommended to perform selection
|
||||||
of the most important features first. See below about the format of the returned results.
|
of the most important features first. See below about the format of the returned results.
|
||||||
}
|
}
|
||||||
\examples{
|
\examples{
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
\alias{slice.xgb.DMatrix}
|
\alias{slice.xgb.DMatrix}
|
||||||
\alias{[.xgb.DMatrix}
|
\alias{[.xgb.DMatrix}
|
||||||
\title{Get a new DMatrix containing the specified rows of
|
\title{Get a new DMatrix containing the specified rows of
|
||||||
orginal xgb.DMatrix object}
|
original xgb.DMatrix object}
|
||||||
\usage{
|
\usage{
|
||||||
slice(object, ...)
|
slice(object, ...)
|
||||||
|
|
||||||
@@ -24,7 +24,7 @@ slice(object, ...)
|
|||||||
}
|
}
|
||||||
\description{
|
\description{
|
||||||
Get a new DMatrix containing the specified rows of
|
Get a new DMatrix containing the specified rows of
|
||||||
orginal xgb.DMatrix object
|
original xgb.DMatrix object
|
||||||
}
|
}
|
||||||
\examples{
|
\examples{
|
||||||
data(agaricus.train, package='xgboost')
|
data(agaricus.train, package='xgboost')
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ E.g., when an \code{xgb.Booster} model is saved as an R object and then is loade
|
|||||||
its handle (pointer) to an internal xgboost model would be invalid. The majority of xgboost methods
|
its handle (pointer) to an internal xgboost model would be invalid. The majority of xgboost methods
|
||||||
should still work for such a model object since those methods would be using
|
should still work for such a model object since those methods would be using
|
||||||
\code{xgb.Booster.complete} internally. However, one might find it to be more efficient to call the
|
\code{xgb.Booster.complete} internally. However, one might find it to be more efficient to call the
|
||||||
\code{xgb.Booster.complete} function explicitely once after loading a model as an R-object.
|
\code{xgb.Booster.complete} function explicitly once after loading a model as an R-object.
|
||||||
That would prevent further repeated implicit reconstruction of an internal booster model.
|
That would prevent further repeated implicit reconstruction of an internal booster model.
|
||||||
}
|
}
|
||||||
\examples{
|
\examples{
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ xgb.cv(params = list(), data, nrounds, nfold, label = NULL,
|
|||||||
\itemize{
|
\itemize{
|
||||||
\item \code{objective} objective function, common ones are
|
\item \code{objective} objective function, common ones are
|
||||||
\itemize{
|
\itemize{
|
||||||
\item \code{reg:linear} linear regression
|
\item \code{reg:squarederror} Regression with squared loss
|
||||||
\item \code{binary:logistic} logistic regression for classification
|
\item \code{binary:logistic} logistic regression for classification
|
||||||
}
|
}
|
||||||
\item \code{eta} step size of each boosting step
|
\item \code{eta} step size of each boosting step
|
||||||
@@ -59,7 +59,7 @@ from each CV model. This parameter engages the \code{\link{cb.cv.predict}} callb
|
|||||||
\item{obj}{customized objective function. Returns gradient and second order
|
\item{obj}{customized objective function. Returns gradient and second order
|
||||||
gradient with given prediction and dtrain.}
|
gradient with given prediction and dtrain.}
|
||||||
|
|
||||||
\item{feval}{custimized evaluation function. Returns
|
\item{feval}{customized evaluation function. Returns
|
||||||
\code{list(metric='metric-name', value='metric-value')} with given
|
\code{list(metric='metric-name', value='metric-value')} with given
|
||||||
prediction and dtrain.}
|
prediction and dtrain.}
|
||||||
|
|
||||||
@@ -101,7 +101,7 @@ An object of class \code{xgb.cv.synchronous} with the following elements:
|
|||||||
capture parameters changed by the \code{\link{cb.reset.parameters}} callback.
|
capture parameters changed by the \code{\link{cb.reset.parameters}} callback.
|
||||||
\item \code{callbacks} callback functions that were either automatically assigned or
|
\item \code{callbacks} callback functions that were either automatically assigned or
|
||||||
explicitly passed.
|
explicitly passed.
|
||||||
\item \code{evaluation_log} evaluation history storead as a \code{data.table} with the
|
\item \code{evaluation_log} evaluation history stored as a \code{data.table} with the
|
||||||
first column corresponding to iteration number and the rest corresponding to the
|
first column corresponding to iteration number and the rest corresponding to the
|
||||||
CV-based evaluation means and standard deviations for the training and test CV-sets.
|
CV-based evaluation means and standard deviations for the training and test CV-sets.
|
||||||
It is created by the \code{\link{cb.evaluation.log}} callback.
|
It is created by the \code{\link{cb.evaluation.log}} callback.
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ using the \code{cb.gblinear.history()} callback.}
|
|||||||
|
|
||||||
\item{class_index}{zero-based class index to extract the coefficients for only that
|
\item{class_index}{zero-based class index to extract the coefficients for only that
|
||||||
specific class in a multinomial multiclass model. When it is NULL, all the
|
specific class in a multinomial multiclass model. When it is NULL, all the
|
||||||
coeffients are returned. Has no effect in non-multiclass models.}
|
coefficients are returned. Has no effect in non-multiclass models.}
|
||||||
}
|
}
|
||||||
\value{
|
\value{
|
||||||
For an \code{xgb.train} result, a matrix (either dense or sparse) with the columns
|
For an \code{xgb.train} result, a matrix (either dense or sparse) with the columns
|
||||||
|
|||||||
@@ -59,8 +59,8 @@ For linear models, \code{rel_to_first = FALSE} would show actual values of the c
|
|||||||
Setting \code{rel_to_first = TRUE} allows to see the picture from the perspective of
|
Setting \code{rel_to_first = TRUE} allows to see the picture from the perspective of
|
||||||
"what is feature's importance contribution relative to the most important feature?"
|
"what is feature's importance contribution relative to the most important feature?"
|
||||||
|
|
||||||
The ggplot-backend method also performs 1-D custering of the importance values,
|
The ggplot-backend method also performs 1-D clustering of the importance values,
|
||||||
with bar colors coresponding to different clusters that have somewhat similar importance values.
|
with bar colors corresponding to different clusters that have somewhat similar importance values.
|
||||||
}
|
}
|
||||||
\examples{
|
\examples{
|
||||||
data(agaricus.train)
|
data(agaricus.train)
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ more than 5 distinct values.}
|
|||||||
|
|
||||||
\item{col_loess}{a color to use for the loess curves.}
|
\item{col_loess}{a color to use for the loess curves.}
|
||||||
|
|
||||||
\item{span_loess}{the \code{span} paramerer in \code{\link[stats]{loess}}'s call.}
|
\item{span_loess}{the \code{span} parameter in \code{\link[stats]{loess}}'s call.}
|
||||||
|
|
||||||
\item{which}{whether to do univariate or bivariate plotting. NOTE: only 1D is implemented so far.}
|
\item{which}{whether to do univariate or bivariate plotting. NOTE: only 1D is implemented so far.}
|
||||||
|
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ xgboost(data = NULL, label = NULL, missing = NA, weight = NULL,
|
|||||||
\item \code{colsample_bytree} subsample ratio of columns when constructing each tree. Default: 1
|
\item \code{colsample_bytree} subsample ratio of columns when constructing each tree. Default: 1
|
||||||
\item \code{num_parallel_tree} Experimental parameter. number of trees to grow per round. Useful to test Random Forest through Xgboost (set \code{colsample_bytree < 1}, \code{subsample < 1} and \code{round = 1}) accordingly. Default: 1
|
\item \code{num_parallel_tree} Experimental parameter. number of trees to grow per round. Useful to test Random Forest through Xgboost (set \code{colsample_bytree < 1}, \code{subsample < 1} and \code{round = 1}) accordingly. Default: 1
|
||||||
\item \code{monotone_constraints} A numerical vector consists of \code{1}, \code{0} and \code{-1} with its length equals to the number of features in the training data. \code{1} is increasing, \code{-1} is decreasing and \code{0} is no constraint.
|
\item \code{monotone_constraints} A numerical vector consists of \code{1}, \code{0} and \code{-1} with its length equals to the number of features in the training data. \code{1} is increasing, \code{-1} is decreasing and \code{0} is no constraint.
|
||||||
|
\item \code{interaction_constraints} A list of vectors specifying feature indices of permitted interactions. Each item of the list represents one permitted interaction where specified features are allowed to interact with each other. Feature index values should start from \code{0} (\code{0} references the first column). Leave argument unspecified for no interaction constraints.
|
||||||
}
|
}
|
||||||
|
|
||||||
2.2. Parameter for Linear Booster
|
2.2. Parameter for Linear Booster
|
||||||
@@ -56,7 +57,7 @@ xgboost(data = NULL, label = NULL, missing = NA, weight = NULL,
|
|||||||
\itemize{
|
\itemize{
|
||||||
\item \code{objective} specify the learning task and the corresponding learning objective, users can pass a self-defined function to it. The default objective options are below:
|
\item \code{objective} specify the learning task and the corresponding learning objective, users can pass a self-defined function to it. The default objective options are below:
|
||||||
\itemize{
|
\itemize{
|
||||||
\item \code{reg:linear} linear regression (Default).
|
\item \code{reg:squarederror} Regression with squared loss (Default).
|
||||||
\item \code{reg:logistic} logistic regression.
|
\item \code{reg:logistic} logistic regression.
|
||||||
\item \code{binary:logistic} logistic regression for binary classification. Output probability.
|
\item \code{binary:logistic} logistic regression for binary classification. Output probability.
|
||||||
\item \code{binary:logitraw} logistic regression for binary classification, output score before logistic transformation.
|
\item \code{binary:logitraw} logistic regression for binary classification, output score before logistic transformation.
|
||||||
@@ -86,7 +87,7 @@ the performance of each round's model on mat1 and mat2.}
|
|||||||
\item{obj}{customized objective function. Returns gradient and second order
|
\item{obj}{customized objective function. Returns gradient and second order
|
||||||
gradient with given prediction and dtrain.}
|
gradient with given prediction and dtrain.}
|
||||||
|
|
||||||
\item{feval}{custimized evaluation function. Returns
|
\item{feval}{customized evaluation function. Returns
|
||||||
\code{list(metric='metric-name', value='metric-value')} with given
|
\code{list(metric='metric-name', value='metric-value')} with given
|
||||||
prediction and dtrain.}
|
prediction and dtrain.}
|
||||||
|
|
||||||
@@ -140,14 +141,14 @@ An object of class \code{xgb.Booster} with the following elements:
|
|||||||
\item \code{handle} a handle (pointer) to the xgboost model in memory.
|
\item \code{handle} a handle (pointer) to the xgboost model in memory.
|
||||||
\item \code{raw} a cached memory dump of the xgboost model saved as R's \code{raw} type.
|
\item \code{raw} a cached memory dump of the xgboost model saved as R's \code{raw} type.
|
||||||
\item \code{niter} number of boosting iterations.
|
\item \code{niter} number of boosting iterations.
|
||||||
\item \code{evaluation_log} evaluation history storead as a \code{data.table} with the
|
\item \code{evaluation_log} evaluation history stored as a \code{data.table} with the
|
||||||
first column corresponding to iteration number and the rest corresponding to evaluation
|
first column corresponding to iteration number and the rest corresponding to evaluation
|
||||||
metrics' values. It is created by the \code{\link{cb.evaluation.log}} callback.
|
metrics' values. It is created by the \code{\link{cb.evaluation.log}} callback.
|
||||||
\item \code{call} a function call.
|
\item \code{call} a function call.
|
||||||
\item \code{params} parameters that were passed to the xgboost library. Note that it does not
|
\item \code{params} parameters that were passed to the xgboost library. Note that it does not
|
||||||
capture parameters changed by the \code{\link{cb.reset.parameters}} callback.
|
capture parameters changed by the \code{\link{cb.reset.parameters}} callback.
|
||||||
\item \code{callbacks} callback functions that were either automatically assigned or
|
\item \code{callbacks} callback functions that were either automatically assigned or
|
||||||
explicitely passed.
|
explicitly passed.
|
||||||
\item \code{best_iteration} iteration number with the best evaluation metric value
|
\item \code{best_iteration} iteration number with the best evaluation metric value
|
||||||
(only available with early stopping).
|
(only available with early stopping).
|
||||||
\item \code{best_ntreelimit} the \code{ntreelimit} value corresponding to the best iteration,
|
\item \code{best_ntreelimit} the \code{ntreelimit} value corresponding to the best iteration,
|
||||||
@@ -156,7 +157,7 @@ An object of class \code{xgb.Booster} with the following elements:
|
|||||||
\item \code{best_score} the best evaluation metric value during early stopping.
|
\item \code{best_score} the best evaluation metric value during early stopping.
|
||||||
(only available with early stopping).
|
(only available with early stopping).
|
||||||
\item \code{feature_names} names of the training dataset features
|
\item \code{feature_names} names of the training dataset features
|
||||||
(only when comun names were defined in training data).
|
(only when column names were defined in training data).
|
||||||
\item \code{nfeatures} number of features in training data.
|
\item \code{nfeatures} number of features in training data.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -178,7 +179,7 @@ The evaluation metric is chosen automatically by Xgboost (according to the objec
|
|||||||
when the \code{eval_metric} parameter is not provided.
|
when the \code{eval_metric} parameter is not provided.
|
||||||
User may set one or several \code{eval_metric} parameters.
|
User may set one or several \code{eval_metric} parameters.
|
||||||
Note that when using a customized metric, only this single metric can be used.
|
Note that when using a customized metric, only this single metric can be used.
|
||||||
The folloiwing is the list of built-in metrics for which Xgboost provides optimized implementation:
|
The following is the list of built-in metrics for which Xgboost provides optimized implementation:
|
||||||
\itemize{
|
\itemize{
|
||||||
\item \code{rmse} root mean square error. \url{http://en.wikipedia.org/wiki/Root_mean_square_error}
|
\item \code{rmse} root mean square error. \url{http://en.wikipedia.org/wiki/Root_mean_square_error}
|
||||||
\item \code{logloss} negative log-likelihood. \url{http://en.wikipedia.org/wiki/Log-likelihood}
|
\item \code{logloss} negative log-likelihood. \url{http://en.wikipedia.org/wiki/Log-likelihood}
|
||||||
@@ -210,7 +211,7 @@ dtest <- xgb.DMatrix(agaricus.test$data, label = agaricus.test$label)
|
|||||||
watchlist <- list(train = dtrain, eval = dtest)
|
watchlist <- list(train = dtrain, eval = dtest)
|
||||||
|
|
||||||
## A simple xgb.train example:
|
## A simple xgb.train example:
|
||||||
param <- list(max_depth = 2, eta = 1, silent = 1, nthread = 2,
|
param <- list(max_depth = 2, eta = 1, verbose = 0, nthread = 2,
|
||||||
objective = "binary:logistic", eval_metric = "auc")
|
objective = "binary:logistic", eval_metric = "auc")
|
||||||
bst <- xgb.train(param, dtrain, nrounds = 2, watchlist)
|
bst <- xgb.train(param, dtrain, nrounds = 2, watchlist)
|
||||||
|
|
||||||
@@ -231,12 +232,12 @@ evalerror <- function(preds, dtrain) {
|
|||||||
|
|
||||||
# These functions could be used by passing them either:
|
# These functions could be used by passing them either:
|
||||||
# as 'objective' and 'eval_metric' parameters in the params list:
|
# as 'objective' and 'eval_metric' parameters in the params list:
|
||||||
param <- list(max_depth = 2, eta = 1, silent = 1, nthread = 2,
|
param <- list(max_depth = 2, eta = 1, verbose = 0, nthread = 2,
|
||||||
objective = logregobj, eval_metric = evalerror)
|
objective = logregobj, eval_metric = evalerror)
|
||||||
bst <- xgb.train(param, dtrain, nrounds = 2, watchlist)
|
bst <- xgb.train(param, dtrain, nrounds = 2, watchlist)
|
||||||
|
|
||||||
# or through the ... arguments:
|
# or through the ... arguments:
|
||||||
param <- list(max_depth = 2, eta = 1, silent = 1, nthread = 2)
|
param <- list(max_depth = 2, eta = 1, verbose = 0, nthread = 2)
|
||||||
bst <- xgb.train(param, dtrain, nrounds = 2, watchlist,
|
bst <- xgb.train(param, dtrain, nrounds = 2, watchlist,
|
||||||
objective = logregobj, eval_metric = evalerror)
|
objective = logregobj, eval_metric = evalerror)
|
||||||
|
|
||||||
@@ -246,7 +247,7 @@ bst <- xgb.train(param, dtrain, nrounds = 2, watchlist,
|
|||||||
|
|
||||||
|
|
||||||
## An xgb.train example of using variable learning rates at each iteration:
|
## An xgb.train example of using variable learning rates at each iteration:
|
||||||
param <- list(max_depth = 2, eta = 1, silent = 1, nthread = 2,
|
param <- list(max_depth = 2, eta = 1, verbose = 0, nthread = 2,
|
||||||
objective = "binary:logistic", eval_metric = "auc")
|
objective = "binary:logistic", eval_metric = "auc")
|
||||||
my_etas <- list(eta = c(0.5, 0.1))
|
my_etas <- list(eta = c(0.5, 0.1))
|
||||||
bst <- xgb.train(param, dtrain, nrounds = 2, watchlist,
|
bst <- xgb.train(param, dtrain, nrounds = 2, watchlist,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*!
|
/*!
|
||||||
* Copyright 2014 (c) by Contributors
|
* Copyright 2014 (c) by Contributors
|
||||||
* \file xgboost_wrapper_R.h
|
* \file xgboost_R.h
|
||||||
* \author Tianqi Chen
|
* \author Tianqi Chen
|
||||||
* \brief R wrapper of xgboost
|
* \brief R wrapper of xgboost
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
// to change behavior of libxgboost
|
// to change behavior of libxgboost
|
||||||
|
|
||||||
#include <xgboost/logging.h>
|
#include <xgboost/logging.h>
|
||||||
#include "src/common/random.h"
|
#include "../../src/common/random.h"
|
||||||
#include "./xgboost_R.h"
|
#include "./xgboost_R.h"
|
||||||
|
|
||||||
// redirect the messages to R's console.
|
// redirect the messages to R's console.
|
||||||
|
|||||||
@@ -182,7 +182,7 @@ test_that("xgb.cv works", {
|
|||||||
expect_is(cv, 'xgb.cv.synchronous')
|
expect_is(cv, 'xgb.cv.synchronous')
|
||||||
expect_false(is.null(cv$evaluation_log))
|
expect_false(is.null(cv$evaluation_log))
|
||||||
expect_lt(cv$evaluation_log[, min(test_error_mean)], 0.03)
|
expect_lt(cv$evaluation_log[, min(test_error_mean)], 0.03)
|
||||||
expect_lt(cv$evaluation_log[, min(test_error_std)], 0.004)
|
expect_lt(cv$evaluation_log[, min(test_error_std)], 0.008)
|
||||||
expect_equal(cv$niter, 2)
|
expect_equal(cv$niter, 2)
|
||||||
expect_false(is.null(cv$folds) && is.list(cv$folds))
|
expect_false(is.null(cv$folds) && is.list(cv$folds))
|
||||||
expect_length(cv$folds, 5)
|
expect_length(cv$folds, 5)
|
||||||
|
|||||||
@@ -282,7 +282,7 @@ test_that("prediction in xgb.cv works for gblinear too", {
|
|||||||
})
|
})
|
||||||
|
|
||||||
test_that("prediction in early-stopping xgb.cv works", {
|
test_that("prediction in early-stopping xgb.cv works", {
|
||||||
set.seed(1)
|
set.seed(11)
|
||||||
expect_output(
|
expect_output(
|
||||||
cv <- xgb.cv(param, dtrain, nfold = 5, eta = 0.1, nrounds = 20,
|
cv <- xgb.cv(param, dtrain, nfold = 5, eta = 0.1, nrounds = 20,
|
||||||
early_stopping_rounds = 5, maximize = FALSE, prediction = TRUE)
|
early_stopping_rounds = 5, maximize = FALSE, prediction = TRUE)
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ num_round <- 2
|
|||||||
test_that("custom objective works", {
|
test_that("custom objective works", {
|
||||||
bst <- xgb.train(param, dtrain, num_round, watchlist)
|
bst <- xgb.train(param, dtrain, num_round, watchlist)
|
||||||
expect_equal(class(bst), "xgb.Booster")
|
expect_equal(class(bst), "xgb.Booster")
|
||||||
expect_equal(length(bst$raw), 1094)
|
expect_equal(length(bst$raw), 1100)
|
||||||
expect_false(is.null(bst$evaluation_log))
|
expect_false(is.null(bst$evaluation_log))
|
||||||
expect_false(is.null(bst$evaluation_log$eval_error))
|
expect_false(is.null(bst$evaluation_log$eval_error))
|
||||||
expect_lt(bst$evaluation_log[num_round, eval_error], 0.03)
|
expect_lt(bst$evaluation_log[num_round, eval_error], 0.03)
|
||||||
@@ -58,5 +58,5 @@ test_that("custom objective using DMatrix attr works", {
|
|||||||
param$objective = logregobjattr
|
param$objective = logregobjattr
|
||||||
bst <- xgb.train(param, dtrain, num_round, watchlist)
|
bst <- xgb.train(param, dtrain, num_round, watchlist)
|
||||||
expect_equal(class(bst), "xgb.Booster")
|
expect_equal(class(bst), "xgb.Booster")
|
||||||
expect_equal(length(bst$raw), 1094)
|
expect_equal(length(bst$raw), 1100)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ test_that("SHAP contribution values are not NAN", {
|
|||||||
fit <- xgboost(
|
fit <- xgboost(
|
||||||
verbose = 0,
|
verbose = 0,
|
||||||
params = list(
|
params = list(
|
||||||
objective = "reg:linear",
|
objective = "reg:squarederror",
|
||||||
eval_metric = "rmse"),
|
eval_metric = "rmse"),
|
||||||
data = as.matrix(subset(d, fold == 2)[, ivs]),
|
data = as.matrix(subset(d, fold == 2)[, ivs]),
|
||||||
label = subset(d, fold == 2)$y,
|
label = subset(d, fold == 2)$y,
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ levels(df[,Treatment])
|
|||||||
|
|
||||||
Next step, we will transform the categorical data to dummy variables.
|
Next step, we will transform the categorical data to dummy variables.
|
||||||
Several encoding methods exist, e.g., [one-hot encoding](http://en.wikipedia.org/wiki/One-hot) is a common approach.
|
Several encoding methods exist, e.g., [one-hot encoding](http://en.wikipedia.org/wiki/One-hot) is a common approach.
|
||||||
We will use the [dummy contrast coding](http://www.ats.ucla.edu/stat/r/library/contrast_coding.htm#dummy) which is popular because it producess "full rank" encoding (also see [this blog post by Max Kuhn](http://appliedpredictivemodeling.com/blog/2013/10/23/the-basics-of-encoding-categorical-data-for-predictive-models)).
|
We will use the [dummy contrast coding](http://www.ats.ucla.edu/stat/r/library/contrast_coding.htm#dummy) which is popular because it produces "full rank" encoding (also see [this blog post by Max Kuhn](http://appliedpredictivemodeling.com/blog/2013/10/23/the-basics-of-encoding-categorical-data-for-predictive-models)).
|
||||||
|
|
||||||
The purpose is to transform each value of each *categorical* feature into a *binary* feature `{0, 1}`.
|
The purpose is to transform each value of each *categorical* feature into a *binary* feature `{0, 1}`.
|
||||||
|
|
||||||
@@ -268,7 +268,7 @@ c2 <- chisq.test(df$Age, output_vector)
|
|||||||
print(c2)
|
print(c2)
|
||||||
```
|
```
|
||||||
|
|
||||||
Pearson correlation between Age and illness disapearing is **`r round(c2$statistic, 2 )`**.
|
Pearson correlation between Age and illness disappearing is **`r round(c2$statistic, 2 )`**.
|
||||||
|
|
||||||
```{r, warning=FALSE, message=FALSE}
|
```{r, warning=FALSE, message=FALSE}
|
||||||
c2 <- chisq.test(df$AgeDiscret, output_vector)
|
c2 <- chisq.test(df$AgeDiscret, output_vector)
|
||||||
|
|||||||
@@ -313,7 +313,7 @@ Until now, all the learnings we have performed were based on boosting trees. **X
|
|||||||
bst <- xgb.train(data=dtrain, booster = "gblinear", max_depth=2, nthread = 2, nrounds=2, watchlist=watchlist, eval_metric = "error", eval_metric = "logloss", objective = "binary:logistic")
|
bst <- xgb.train(data=dtrain, booster = "gblinear", max_depth=2, nthread = 2, nrounds=2, watchlist=watchlist, eval_metric = "error", eval_metric = "logloss", objective = "binary:logistic")
|
||||||
```
|
```
|
||||||
|
|
||||||
In this specific case, *linear boosting* gets sligtly better performance metrics than decision trees based algorithm.
|
In this specific case, *linear boosting* gets slightly better performance metrics than decision trees based algorithm.
|
||||||
|
|
||||||
In simple cases, it will happen because there is nothing better than a linear algorithm to catch a linear link. However, decision trees are much better to catch a non linear link between predictors and outcome. Because there is no silver bullet, we advise you to check both algorithms with your own datasets to have an idea of what to use.
|
In simple cases, it will happen because there is nothing better than a linear algorithm to catch a linear link. However, decision trees are much better to catch a non linear link between predictors and outcome. Because there is no silver bullet, we advise you to check both algorithms with your own datasets to have an idea of what to use.
|
||||||
|
|
||||||
|
|||||||
189
R-package/vignettes/xgboostfromJSON.Rmd
Normal file
189
R-package/vignettes/xgboostfromJSON.Rmd
Normal file
@@ -0,0 +1,189 @@
|
|||||||
|
---
|
||||||
|
title: "XGBoost from JSON"
|
||||||
|
output:
|
||||||
|
rmarkdown::html_vignette:
|
||||||
|
number_sections: yes
|
||||||
|
toc: yes
|
||||||
|
author: Roland Stevenson
|
||||||
|
vignette: >
|
||||||
|
%\VignetteIndexEntry{XGBoost from JSON}
|
||||||
|
%\VignetteEngine{knitr::rmarkdown}
|
||||||
|
\usepackage[utf8]{inputenc}
|
||||||
|
---
|
||||||
|
|
||||||
|
XGBoost from JSON
|
||||||
|
=================
|
||||||
|
|
||||||
|
## Introduction
|
||||||
|
|
||||||
|
The purpose of this Vignette is to show you how to correctly load and work with an **Xgboost** model that has been dumped to JSON. **Xgboost** internally converts all data to [32-bit floats](https://en.wikipedia.org/wiki/Single-precision_floating-point_format), and the values dumped to JSON are decimal representations of these values. When working with a model that has been parsed from a JSON file, care must be taken to correctly treat:
|
||||||
|
|
||||||
|
- the input data, which should be converted to 32-bit floats
|
||||||
|
- any 32-bit floats that were stored in JSON as decimal representations
|
||||||
|
- any calculations must be done with 32-bit mathematical operators
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
|
||||||
|
For the purpose of this tutorial we will load the xgboost, jsonlite, and float packages. We'll also set `digits=22` in our options in case we want to inspect many digits of our results.
|
||||||
|
|
||||||
|
```{r}
|
||||||
|
require(xgboost)
|
||||||
|
require(jsonlite)
|
||||||
|
require(float)
|
||||||
|
options(digits=22)
|
||||||
|
```
|
||||||
|
|
||||||
|
We will create a toy binary logistic model based on the example first provided [here](https://github.com/dmlc/xgboost/issues/3960), so that we can easily understand the structure of the dumped JSON model object. This will allow us to understand where discrepancies can occur and how they should be handled.
|
||||||
|
|
||||||
|
```{r}
|
||||||
|
dates <- c(20180130, 20180130, 20180130,
|
||||||
|
20180130, 20180130, 20180130,
|
||||||
|
20180131, 20180131, 20180131,
|
||||||
|
20180131, 20180131, 20180131,
|
||||||
|
20180131, 20180131, 20180131,
|
||||||
|
20180134, 20180134, 20180134)
|
||||||
|
|
||||||
|
labels <- c(1, 1, 1,
|
||||||
|
1, 1, 1,
|
||||||
|
0, 0, 0,
|
||||||
|
0, 0, 0,
|
||||||
|
0, 0, 0,
|
||||||
|
0, 0, 0)
|
||||||
|
|
||||||
|
data <- data.frame(dates = dates, labels=labels)
|
||||||
|
|
||||||
|
bst <- xgboost(
|
||||||
|
data = as.matrix(data$dates),
|
||||||
|
label = labels,
|
||||||
|
nthread = 2,
|
||||||
|
nrounds = 1,
|
||||||
|
objective = "binary:logistic",
|
||||||
|
missing = NA,
|
||||||
|
max_depth = 1
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Comparing results
|
||||||
|
We will now dump the model to JSON and attempt to illustrate a variety of issues that can arise, and how to properly deal with them.
|
||||||
|
|
||||||
|
First let's dump the model to JSON:
|
||||||
|
|
||||||
|
```{r}
|
||||||
|
bst_json <- xgb.dump(bst, with_stats = FALSE, dump_format='json')
|
||||||
|
bst_from_json <- jsonlite::fromJSON(bst_json, simplifyDataFrame = FALSE)
|
||||||
|
node <- bst_from_json[[1]]
|
||||||
|
cat(bst_json)
|
||||||
|
```
|
||||||
|
|
||||||
|
The tree JSON shown by the above code-chunk tells us that if the data is less than 20180132, the tree will output the value in the first leaf. Otherwise it will output the value in the second leaf. Let's try to reproduce this manually with the data we have and confirm that it matches the model predictions we've already calculated.
|
||||||
|
|
||||||
|
```{r}
|
||||||
|
bst_preds_logodds <- predict(bst,as.matrix(data$dates), outputmargin = TRUE)
|
||||||
|
|
||||||
|
# calculate the logodds values using the JSON representation
|
||||||
|
bst_from_json_logodds <- ifelse(data$dates<node$split_condition,
|
||||||
|
node$children[[1]]$leaf,
|
||||||
|
node$children[[2]]$leaf)
|
||||||
|
|
||||||
|
bst_preds_logodds
|
||||||
|
bst_from_json_logodds
|
||||||
|
|
||||||
|
# test that values are equal
|
||||||
|
bst_preds_logodds == bst_from_json_logodds
|
||||||
|
|
||||||
|
```
|
||||||
|
None are equal. What happened?
|
||||||
|
|
||||||
|
At this stage two things happened:
|
||||||
|
|
||||||
|
- input data was not converted to 32-bit floats
|
||||||
|
- the JSON variables were not converted to 32-bit floats
|
||||||
|
|
||||||
|
### Lesson 1: All data is 32-bit floats
|
||||||
|
|
||||||
|
> When working with imported JSON, all data must be converted to 32-bit floats
|
||||||
|
|
||||||
|
To explain this, let's repeat the comparison and round to two decimals:
|
||||||
|
|
||||||
|
```{r}
|
||||||
|
round(bst_preds_logodds,2) == round(bst_from_json_logodds,2)
|
||||||
|
```
|
||||||
|
|
||||||
|
If we round to two decimals, we see that only the elements related to data values of `20180131` don't agree. If we convert the data to floats, they agree:
|
||||||
|
|
||||||
|
```{r}
|
||||||
|
# now convert the dates to floats first
|
||||||
|
bst_from_json_logodds <- ifelse(fl(data$dates)<node$split_condition,
|
||||||
|
node$children[[1]]$leaf,
|
||||||
|
node$children[[2]]$leaf)
|
||||||
|
|
||||||
|
# test that values are equal
|
||||||
|
round(bst_preds_logodds,2) == round(bst_from_json_logodds,2)
|
||||||
|
```
|
||||||
|
|
||||||
|
What's the lesson? If we are going to work with an imported JSON model, any data must be converted to floats first. In this case, since '20180131' cannot be represented as a 32-bit float, it is rounded up to 20180132, as shown here:
|
||||||
|
|
||||||
|
```{r}
|
||||||
|
fl(20180131)
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### Lesson 2: JSON parameters are 32-bit floats
|
||||||
|
|
||||||
|
> All JSON parameters stored as floats must be converted to floats.
|
||||||
|
|
||||||
|
Let's now say we do care about numbers past the first two decimals.
|
||||||
|
|
||||||
|
```{r}
|
||||||
|
# test that values are equal
|
||||||
|
bst_preds_logodds == bst_from_json_logodds
|
||||||
|
```
|
||||||
|
|
||||||
|
None are exactly equal. What happened? Although we've converted the data to 32-bit floats, we also need to convert the JSON parameters to 32-bit floats. Let's do this:
|
||||||
|
|
||||||
|
```{r}
|
||||||
|
# now convert the dates to floats first
|
||||||
|
bst_from_json_logodds <- ifelse(fl(data$dates)<fl(node$split_condition),
|
||||||
|
as.numeric(fl(node$children[[1]]$leaf)),
|
||||||
|
as.numeric(fl(node$children[[2]]$leaf)))
|
||||||
|
|
||||||
|
# test that values are equal
|
||||||
|
bst_preds_logodds == bst_from_json_logodds
|
||||||
|
```
|
||||||
|
All equal. What's the lesson? If we are going to work with an imported JSON model, any JSON parameters that were stored as floats must also be converted to floats first.
|
||||||
|
|
||||||
|
### Lesson 3: Use 32-bit math
|
||||||
|
|
||||||
|
> Always use 32-bit numbers and operators
|
||||||
|
|
||||||
|
We were able to get the log-odds to agree, so now let's manually calculate the sigmoid of the log-odds. This should agree with the xgboost predictions.
|
||||||
|
|
||||||
|
|
||||||
|
```{r}
|
||||||
|
bst_preds <- predict(bst,as.matrix(data$dates))
|
||||||
|
|
||||||
|
# calculate the predictions casting doubles to floats
|
||||||
|
bst_from_json_preds <- ifelse(fl(data$dates)<fl(node$split_condition),
|
||||||
|
as.numeric(1/(1+exp(-1*fl(node$children[[1]]$leaf)))),
|
||||||
|
as.numeric(1/(1+exp(-1*fl(node$children[[2]]$leaf))))
|
||||||
|
)
|
||||||
|
|
||||||
|
# test that values are equal
|
||||||
|
bst_preds == bst_from_json_preds
|
||||||
|
```
|
||||||
|
|
||||||
|
None are exactly equal again. What is going on here? Well, since we are using the value `1` in the calcuations, we have introduced a double into the calculation. Because of this, all float values are promoted to 64-bit doubles and the 64-bit version of the exponentiation operator `exp` is also used. On the other hand, xgboost uses the 32-bit version of the exponentation operator in its [sigmoid function](https://github.com/dmlc/xgboost/blob/54980b8959680a0da06a3fc0ec776e47c8cbb0a1/src/common/math.h#L25-L27).
|
||||||
|
|
||||||
|
How do we fix this? We have to ensure we use the correct datatypes everywhere and the correct operators. If we use only floats, the float library that we have loaded will ensure the 32-bit float exponention operator is applied.
|
||||||
|
```{r}
|
||||||
|
# calculate the predictions casting doubles to floats
|
||||||
|
bst_from_json_preds <- ifelse(fl(data$dates)<fl(node$split_condition),
|
||||||
|
as.numeric(fl(1)/(fl(1)+exp(fl(-1)*fl(node$children[[1]]$leaf)))),
|
||||||
|
as.numeric(fl(1)/(fl(1)+exp(fl(-1)*fl(node$children[[2]]$leaf))))
|
||||||
|
)
|
||||||
|
|
||||||
|
# test that values are equal
|
||||||
|
bst_preds == bst_from_json_preds
|
||||||
|
```
|
||||||
|
|
||||||
|
All equal. What's the lesson? We have to ensure that all calculations are done with 32-bit floating point operators if we want to reproduce the results that we see with xgboost.
|
||||||
34
README.md
34
README.md
@@ -1,7 +1,7 @@
|
|||||||
<img src=https://raw.githubusercontent.com/dmlc/dmlc.github.io/master/img/logo-m/xgboost.png width=135/> eXtreme Gradient Boosting
|
<img src=https://raw.githubusercontent.com/dmlc/dmlc.github.io/master/img/logo-m/xgboost.png width=135/> eXtreme Gradient Boosting
|
||||||
===========
|
===========
|
||||||
[](https://xgboost-ci.net/blue/organizations/jenkins/xgboost/activity)
|
[](https://xgboost-ci.net/blue/organizations/jenkins/xgboost/activity)
|
||||||
[](https://travis-ci.org/dmlc/xgboost)
|
[](https://travis-ci.org/dmlc/xgboost)
|
||||||
[](https://ci.appveyor.com/project/tqchen/xgboost)
|
[](https://ci.appveyor.com/project/tqchen/xgboost)
|
||||||
[](https://xgboost.readthedocs.org)
|
[](https://xgboost.readthedocs.org)
|
||||||
[](./LICENSE)
|
[](./LICENSE)
|
||||||
@@ -32,3 +32,35 @@ Reference
|
|||||||
---------
|
---------
|
||||||
- Tianqi Chen and Carlos Guestrin. [XGBoost: A Scalable Tree Boosting System](http://arxiv.org/abs/1603.02754). In 22nd SIGKDD Conference on Knowledge Discovery and Data Mining, 2016
|
- Tianqi Chen and Carlos Guestrin. [XGBoost: A Scalable Tree Boosting System](http://arxiv.org/abs/1603.02754). In 22nd SIGKDD Conference on Knowledge Discovery and Data Mining, 2016
|
||||||
- XGBoost originates from research project at University of Washington.
|
- XGBoost originates from research project at University of Washington.
|
||||||
|
|
||||||
|
Sponsors
|
||||||
|
--------
|
||||||
|
Become a sponsor and get a logo here. See details at [Sponsoring the XGBoost Project](https://xgboost.ai/sponsors). The funds are used to defray the cost of continuous integration and testing infrastructure (https://xgboost-ci.net).
|
||||||
|
|
||||||
|
## Open Source Collective sponsors
|
||||||
|
[](#backers) [](#sponsors)
|
||||||
|
|
||||||
|
### Sponsors
|
||||||
|
[[Become a sponsor](https://opencollective.com/xgboost#sponsor)]
|
||||||
|
|
||||||
|
<!--<a href="https://opencollective.com/xgboost/sponsor/0/website" target="_blank"><img src="https://opencollective.com/xgboost/sponsor/0/avatar.svg"></a>-->
|
||||||
|
<a href="https://www.nvidia.com/en-us/" target="_blank"><img src="https://raw.githubusercontent.com/xgboost-ai/xgboost-ai.github.io/master/images/sponsors/nvidia.jpg" alt="NVIDIA" width="72" height="72"></a>
|
||||||
|
<a href="https://opencollective.com/xgboost/sponsor/1/website" target="_blank"><img src="https://opencollective.com/xgboost/sponsor/1/avatar.svg"></a>
|
||||||
|
<a href="https://opencollective.com/xgboost/sponsor/2/website" target="_blank"><img src="https://opencollective.com/xgboost/sponsor/2/avatar.svg"></a>
|
||||||
|
<a href="https://opencollective.com/xgboost/sponsor/3/website" target="_blank"><img src="https://opencollective.com/xgboost/sponsor/3/avatar.svg"></a>
|
||||||
|
<a href="https://opencollective.com/xgboost/sponsor/4/website" target="_blank"><img src="https://opencollective.com/xgboost/sponsor/4/avatar.svg"></a>
|
||||||
|
<a href="https://opencollective.com/xgboost/sponsor/5/website" target="_blank"><img src="https://opencollective.com/xgboost/sponsor/5/avatar.svg"></a>
|
||||||
|
<a href="https://opencollective.com/xgboost/sponsor/6/website" target="_blank"><img src="https://opencollective.com/xgboost/sponsor/6/avatar.svg"></a>
|
||||||
|
<a href="https://opencollective.com/xgboost/sponsor/7/website" target="_blank"><img src="https://opencollective.com/xgboost/sponsor/7/avatar.svg"></a>
|
||||||
|
<a href="https://opencollective.com/xgboost/sponsor/8/website" target="_blank"><img src="https://opencollective.com/xgboost/sponsor/8/avatar.svg"></a>
|
||||||
|
<a href="https://opencollective.com/xgboost/sponsor/9/website" target="_blank"><img src="https://opencollective.com/xgboost/sponsor/9/avatar.svg"></a>
|
||||||
|
|
||||||
|
### Backers
|
||||||
|
[[Become a backer](https://opencollective.com/xgboost#backer)]
|
||||||
|
|
||||||
|
<a href="https://opencollective.com/xgboost#backers" target="_blank"><img src="https://opencollective.com/xgboost/backers.svg?width=890"></a>
|
||||||
|
|
||||||
|
## Other sponsors
|
||||||
|
The sponsors in this list are donating cloud hours in lieu of cash donation.
|
||||||
|
|
||||||
|
<a href="https://aws.amazon.com/" target="_blank"><img src="https://raw.githubusercontent.com/xgboost-ai/xgboost-ai.github.io/master/images/sponsors/aws.png" alt="Amazon Web Services" width="72" height="72"></a>
|
||||||
|
|||||||
16
appveyor.yml
16
appveyor.yml
@@ -36,15 +36,21 @@ install:
|
|||||||
- set PATH=C:\msys64\mingw64\bin;C:\msys64\usr\bin;%PATH%
|
- set PATH=C:\msys64\mingw64\bin;C:\msys64\usr\bin;%PATH%
|
||||||
- gcc -v
|
- gcc -v
|
||||||
- ls -l C:\
|
- ls -l C:\
|
||||||
# Miniconda2
|
# Miniconda3
|
||||||
- set PATH=;C:\Miniconda-x64;C:\Miniconda-x64\Scripts;%PATH%
|
- call C:\Miniconda3-x64\Scripts\activate.bat
|
||||||
|
- conda info
|
||||||
- where python
|
- where python
|
||||||
- python --version
|
- python --version
|
||||||
# do python build for mingw and one of the msvc jobs
|
# do python build for mingw and one of the msvc jobs
|
||||||
- set DO_PYTHON=off
|
- set DO_PYTHON=off
|
||||||
- if /i "%target%" == "mingw" set DO_PYTHON=on
|
- if /i "%target%" == "mingw" set DO_PYTHON=on
|
||||||
- if /i "%target%_%ver%_%configuration%" == "msvc_2015_Release" set DO_PYTHON=on
|
- if /i "%target%_%ver%_%configuration%" == "msvc_2015_Release" set DO_PYTHON=on
|
||||||
- if /i "%DO_PYTHON%" == "on" conda install -y numpy scipy pandas matplotlib pytest scikit-learn graphviz python-graphviz
|
- if /i "%DO_PYTHON%" == "on" (
|
||||||
|
conda config --set always_yes true &&
|
||||||
|
conda update -q conda &&
|
||||||
|
conda install -y numpy scipy pandas matplotlib pytest scikit-learn graphviz python-graphviz
|
||||||
|
)
|
||||||
|
- set PATH=C:\Miniconda3-x64\Library\bin\graphviz;%PATH%
|
||||||
# R: based on https://github.com/krlmlr/r-appveyor
|
# R: based on https://github.com/krlmlr/r-appveyor
|
||||||
- ps: |
|
- ps: |
|
||||||
if($env:target -eq 'rmingw' -or $env:target -eq 'rmsvc') {
|
if($env:target -eq 'rmingw' -or $env:target -eq 'rmsvc') {
|
||||||
@@ -52,10 +58,10 @@ install:
|
|||||||
Invoke-WebRequest https://raw.githubusercontent.com/krlmlr/r-appveyor/master/scripts/appveyor-tool.ps1 -OutFile "$Env:TEMP\appveyor-tool.ps1"
|
Invoke-WebRequest https://raw.githubusercontent.com/krlmlr/r-appveyor/master/scripts/appveyor-tool.ps1 -OutFile "$Env:TEMP\appveyor-tool.ps1"
|
||||||
Import-Module "$Env:TEMP\appveyor-tool.ps1"
|
Import-Module "$Env:TEMP\appveyor-tool.ps1"
|
||||||
Bootstrap
|
Bootstrap
|
||||||
$DEPS = "c('data.table','magrittr','stringi','ggplot2','DiagrammeR','Ckmeans.1d.dp','vcd','testthat','lintr','knitr','rmarkdown')"
|
|
||||||
cmd.exe /c "R.exe -q -e ""install.packages($DEPS, repos='$CRAN', type='both')"" 2>&1"
|
|
||||||
$BINARY_DEPS = "c('XML','igraph')"
|
$BINARY_DEPS = "c('XML','igraph')"
|
||||||
cmd.exe /c "R.exe -q -e ""install.packages($BINARY_DEPS, repos='$CRAN', type='win.binary')"" 2>&1"
|
cmd.exe /c "R.exe -q -e ""install.packages($BINARY_DEPS, repos='$CRAN', type='win.binary')"" 2>&1"
|
||||||
|
$DEPS = "c('data.table','magrittr','stringi','ggplot2','DiagrammeR','Ckmeans.1d.dp','vcd','testthat','lintr','knitr','rmarkdown')"
|
||||||
|
cmd.exe /c "R.exe -q -e ""install.packages($DEPS, repos='$CRAN', type='both')"" 2>&1"
|
||||||
}
|
}
|
||||||
|
|
||||||
build_script:
|
build_script:
|
||||||
|
|||||||
51
build.sh
51
build.sh
@@ -1,51 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# This is a simple script to make xgboost in MAC and Linux
|
|
||||||
# Basically, it first try to make with OpenMP, if fails, disable OpenMP and make it again.
|
|
||||||
# This will automatically make xgboost for MAC users who don't have OpenMP support.
|
|
||||||
# In most cases, type make will give what you want.
|
|
||||||
|
|
||||||
# See additional instruction in doc/build.md
|
|
||||||
set -e
|
|
||||||
|
|
||||||
if make; then
|
|
||||||
echo "Successfully build multi-thread xgboost"
|
|
||||||
else
|
|
||||||
|
|
||||||
not_ready=0
|
|
||||||
|
|
||||||
if [[ ! -e ./rabit/Makefile ]]; then
|
|
||||||
echo ""
|
|
||||||
echo "Please init the rabit submodule:"
|
|
||||||
echo "git submodule update --init --recursive -- rabit"
|
|
||||||
not_ready=1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ! -e ./dmlc-core/Makefile ]]; then
|
|
||||||
echo ""
|
|
||||||
echo "Please init the dmlc-core submodule:"
|
|
||||||
echo "git submodule update --init --recursive -- dmlc-core"
|
|
||||||
not_ready=1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ "${not_ready}" == "1" ]]; then
|
|
||||||
echo ""
|
|
||||||
echo "Please fix the errors above and retry the build, or reclone the repository with:"
|
|
||||||
echo "git clone --recursive https://github.com/dmlc/xgboost.git"
|
|
||||||
echo ""
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
echo "-----------------------------"
|
|
||||||
echo "Building multi-thread xgboost failed"
|
|
||||||
echo "Start to build single-thread xgboost"
|
|
||||||
make clean_all
|
|
||||||
make config=make/minimum.mk
|
|
||||||
if [ $? -eq 0 ] ;then
|
|
||||||
echo "Successfully build single-thread xgboost"
|
|
||||||
echo "If you want multi-threaded version"
|
|
||||||
echo "See additional instructions in doc/build.md"
|
|
||||||
else
|
|
||||||
echo "Failed to build single-thread xgboost"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
16
cmake/Doc.cmake
Normal file
16
cmake/Doc.cmake
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
function (run_doxygen)
|
||||||
|
find_package(Doxygen REQUIRED)
|
||||||
|
|
||||||
|
if (NOT DOXYGEN_DOT_FOUND)
|
||||||
|
message(FATAL_ERROR "Command `dot` not found. Please install graphviz.")
|
||||||
|
endif (NOT DOXYGEN_DOT_FOUND)
|
||||||
|
|
||||||
|
configure_file(
|
||||||
|
${PROJECT_SOURCE_DIR}/doc/Doxyfile.in
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/Doxyfile @ONLY)
|
||||||
|
add_custom_target( doc_doxygen ALL
|
||||||
|
COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile
|
||||||
|
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||||
|
COMMENT "Generate C APIs documentation."
|
||||||
|
VERBATIM)
|
||||||
|
endfunction (run_doxygen)
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
# Automatically set source group based on folder
|
# Automatically set source group based on folder
|
||||||
function(auto_source_group SOURCES)
|
function(auto_source_group SOURCES)
|
||||||
|
|
||||||
@@ -18,6 +17,10 @@ endfunction(auto_source_group)
|
|||||||
function(msvc_use_static_runtime)
|
function(msvc_use_static_runtime)
|
||||||
if(MSVC)
|
if(MSVC)
|
||||||
set(variables
|
set(variables
|
||||||
|
CMAKE_C_FLAGS_DEBUG
|
||||||
|
CMAKE_C_FLAGS_MINSIZEREL
|
||||||
|
CMAKE_C_FLAGS_RELEASE
|
||||||
|
CMAKE_C_FLAGS_RELWITHDEBINFO
|
||||||
CMAKE_CXX_FLAGS_DEBUG
|
CMAKE_CXX_FLAGS_DEBUG
|
||||||
CMAKE_CXX_FLAGS_MINSIZEREL
|
CMAKE_CXX_FLAGS_MINSIZEREL
|
||||||
CMAKE_CXX_FLAGS_RELEASE
|
CMAKE_CXX_FLAGS_RELEASE
|
||||||
@@ -29,6 +32,23 @@ function(msvc_use_static_runtime)
|
|||||||
set(${variable} "${${variable}}" PARENT_SCOPE)
|
set(${variable} "${${variable}}" PARENT_SCOPE)
|
||||||
endif()
|
endif()
|
||||||
endforeach()
|
endforeach()
|
||||||
|
set(variables
|
||||||
|
CMAKE_CUDA_FLAGS
|
||||||
|
CMAKE_CUDA_FLAGS_DEBUG
|
||||||
|
CMAKE_CUDA_FLAGS_MINSIZEREL
|
||||||
|
CMAKE_CUDA_FLAGS_RELEASE
|
||||||
|
CMAKE_CUDA_FLAGS_RELWITHDEBINFO
|
||||||
|
)
|
||||||
|
foreach(variable ${variables})
|
||||||
|
if(${variable} MATCHES "-MD")
|
||||||
|
string(REGEX REPLACE "-MD" "-MT" ${variable} "${${variable}}")
|
||||||
|
set(${variable} "${${variable}}" PARENT_SCOPE)
|
||||||
|
endif()
|
||||||
|
if(${variable} MATCHES "/MD")
|
||||||
|
string(REGEX REPLACE "/MD" "/MT" ${variable} "${${variable}}")
|
||||||
|
set(${variable} "${${variable}}" PARENT_SCOPE)
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
endif()
|
endif()
|
||||||
endfunction(msvc_use_static_runtime)
|
endfunction(msvc_use_static_runtime)
|
||||||
|
|
||||||
@@ -57,9 +77,14 @@ endfunction(set_default_configuration_release)
|
|||||||
# Generate nvcc compiler flags given a list of architectures
|
# Generate nvcc compiler flags given a list of architectures
|
||||||
# Also generates PTX for the most recent architecture for forwards compatibility
|
# Also generates PTX for the most recent architecture for forwards compatibility
|
||||||
function(format_gencode_flags flags out)
|
function(format_gencode_flags flags out)
|
||||||
|
if(CMAKE_CUDA_COMPILER_VERSION MATCHES "^([0-9]+\\.[0-9]+)")
|
||||||
|
set(CUDA_VERSION "${CMAKE_MATCH_1}")
|
||||||
|
endif()
|
||||||
# Set up architecture flags
|
# Set up architecture flags
|
||||||
if(NOT flags)
|
if(NOT flags)
|
||||||
if((CUDA_VERSION_MAJOR EQUAL 9) OR (CUDA_VERSION_MAJOR GREATER 9))
|
if(CUDA_VERSION VERSION_GREATER_EQUAL "10.0")
|
||||||
|
set(flags "35;50;52;60;61;70;75")
|
||||||
|
elseif(CUDA_VERSION VERSION_GREATER_EQUAL "9.0")
|
||||||
set(flags "35;50;52;60;61;70")
|
set(flags "35;50;52;60;61;70")
|
||||||
else()
|
else()
|
||||||
set(flags "35;50;52;60;61")
|
set(flags "35;50;52;60;61")
|
||||||
@@ -67,11 +92,11 @@ function(format_gencode_flags flags out)
|
|||||||
endif()
|
endif()
|
||||||
# Generate SASS
|
# Generate SASS
|
||||||
foreach(ver ${flags})
|
foreach(ver ${flags})
|
||||||
set(${out} "${${out}}-gencode arch=compute_${ver},code=sm_${ver};")
|
set(${out} "${${out}}--generate-code=arch=compute_${ver},code=sm_${ver};")
|
||||||
endforeach()
|
endforeach()
|
||||||
# Generate PTX for last architecture
|
# Generate PTX for last architecture
|
||||||
list(GET flags -1 ver)
|
list(GET flags -1 ver)
|
||||||
set(${out} "${${out}}-gencode arch=compute_${ver},code=compute_${ver};")
|
set(${out} "${${out}}--generate-code=arch=compute_${ver},code=compute_${ver};")
|
||||||
|
|
||||||
set(${out} "${${out}}" PARENT_SCOPE)
|
set(${out} "${${out}}" PARENT_SCOPE)
|
||||||
endfunction(format_gencode_flags flags)
|
endfunction(format_gencode_flags flags)
|
||||||
@@ -80,6 +105,10 @@ endfunction(format_gencode_flags flags)
|
|||||||
# if necessary, installs the main R package dependencies;
|
# if necessary, installs the main R package dependencies;
|
||||||
# runs R CMD INSTALL.
|
# runs R CMD INSTALL.
|
||||||
function(setup_rpackage_install_target rlib_target build_dir)
|
function(setup_rpackage_install_target rlib_target build_dir)
|
||||||
|
# backup cmake_install.cmake
|
||||||
|
install(CODE "file(COPY \"${build_dir}/R-package/cmake_install.cmake\"
|
||||||
|
DESTINATION \"${build_dir}/bak\")")
|
||||||
|
|
||||||
install(CODE "file(REMOVE_RECURSE \"${build_dir}/R-package\")")
|
install(CODE "file(REMOVE_RECURSE \"${build_dir}/R-package\")")
|
||||||
install(
|
install(
|
||||||
DIRECTORY "${PROJECT_SOURCE_DIR}/R-package"
|
DIRECTORY "${PROJECT_SOURCE_DIR}/R-package"
|
||||||
@@ -98,4 +127,8 @@ function(setup_rpackage_install_target rlib_target build_dir)
|
|||||||
install(CODE "execute_process(COMMAND \"${LIBR_EXECUTABLE}\" \"-q\" \"-e\" \"${XGB_DEPS_SCRIPT}\")")
|
install(CODE "execute_process(COMMAND \"${LIBR_EXECUTABLE}\" \"-q\" \"-e\" \"${XGB_DEPS_SCRIPT}\")")
|
||||||
install(CODE "execute_process(COMMAND \"${LIBR_EXECUTABLE}\" CMD INSTALL\
|
install(CODE "execute_process(COMMAND \"${LIBR_EXECUTABLE}\" CMD INSTALL\
|
||||||
\"--no-multiarch\" \"--build\" \"${build_dir}/R-package\")")
|
\"--no-multiarch\" \"--build\" \"${build_dir}/R-package\")")
|
||||||
|
|
||||||
|
# restore cmake_install.cmake
|
||||||
|
install(CODE "file(RENAME \"${build_dir}/bak/cmake_install.cmake\"
|
||||||
|
\"${build_dir}/R-package/cmake_install.cmake\")")
|
||||||
endfunction(setup_rpackage_install_target)
|
endfunction(setup_rpackage_install_target)
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
/*!
|
|
||||||
* Copyright 2019 by Contributors
|
|
||||||
* \file build_config.h
|
|
||||||
*/
|
|
||||||
#ifndef XGBOOST_BUILD_CONFIG_H_
|
|
||||||
#define XGBOOST_BUILD_CONFIG_H_
|
|
||||||
|
|
||||||
#cmakedefine XGBOOST_MM_PREFETCH_PRESENT
|
|
||||||
#cmakedefine XGBOOST_BUILTIN_PREFETCH_PRESENT
|
|
||||||
|
|
||||||
#endif // XGBOOST_BUILD_CONFIG_H_
|
|
||||||
@@ -32,20 +32,28 @@
|
|||||||
#
|
#
|
||||||
# This module assumes that the user has already called find_package(CUDA)
|
# This module assumes that the user has already called find_package(CUDA)
|
||||||
|
|
||||||
|
if (NCCL_LIBRARY)
|
||||||
|
# Don't cache NCCL_LIBRARY to enable switching between static and shared.
|
||||||
|
unset(NCCL_LIBRARY CACHE)
|
||||||
|
endif()
|
||||||
|
|
||||||
set(NCCL_LIB_NAME nccl_static)
|
if (BUILD_WITH_SHARED_NCCL)
|
||||||
|
# libnccl.so
|
||||||
|
set(NCCL_LIB_NAME nccl)
|
||||||
|
else ()
|
||||||
|
# libnccl_static.a
|
||||||
|
set(NCCL_LIB_NAME nccl_static)
|
||||||
|
endif (BUILD_WITH_SHARED_NCCL)
|
||||||
|
|
||||||
find_path(NCCL_INCLUDE_DIR
|
find_path(NCCL_INCLUDE_DIR
|
||||||
NAMES nccl.h
|
NAMES nccl.h
|
||||||
PATHS $ENV{NCCL_ROOT}/include ${NCCL_ROOT}/include ${CUDA_INCLUDE_DIRS} /usr/include)
|
PATHS $ENV{NCCL_ROOT}/include ${NCCL_ROOT}/include)
|
||||||
|
|
||||||
find_library(NCCL_LIBRARY
|
find_library(NCCL_LIBRARY
|
||||||
NAMES ${NCCL_LIB_NAME}
|
NAMES ${NCCL_LIB_NAME}
|
||||||
PATHS $ENV{NCCL_ROOT}/lib ${NCCL_ROOT}/lib ${CUDA_INCLUDE_DIRS}/../lib /usr/lib)
|
PATHS $ENV{NCCL_ROOT}/lib/ ${NCCL_ROOT}/lib)
|
||||||
|
|
||||||
if (NCCL_INCLUDE_DIR AND NCCL_LIBRARY)
|
message(STATUS "Using nccl library: ${NCCL_LIBRARY}")
|
||||||
get_filename_component(NCCL_LIBRARY ${NCCL_LIBRARY} PATH)
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
include(FindPackageHandleStandardArgs)
|
include(FindPackageHandleStandardArgs)
|
||||||
find_package_handle_standard_args(Nccl DEFAULT_MSG
|
find_package_handle_standard_args(Nccl DEFAULT_MSG
|
||||||
@@ -54,5 +62,4 @@ find_package_handle_standard_args(Nccl DEFAULT_MSG
|
|||||||
mark_as_advanced(
|
mark_as_advanced(
|
||||||
NCCL_INCLUDE_DIR
|
NCCL_INCLUDE_DIR
|
||||||
NCCL_LIBRARY
|
NCCL_LIBRARY
|
||||||
NCCL_LIB_NAME
|
|
||||||
)
|
)
|
||||||
|
|||||||
5
cmake/xgboost-config.cmake.in
Normal file
5
cmake/xgboost-config.cmake.in
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
@PACKAGE_INIT@
|
||||||
|
|
||||||
|
if(NOT TARGET xgboost::xgboost)
|
||||||
|
include(${CMAKE_CURRENT_LIST_DIR}/XGBoostTargets.cmake)
|
||||||
|
endif()
|
||||||
@@ -119,6 +119,7 @@ If you have particular usecase of xgboost that you would like to highlight.
|
|||||||
Send a PR to add a one sentence description:)
|
Send a PR to add a one sentence description:)
|
||||||
|
|
||||||
- XGBoost is used in [Kaggle Script](https://www.kaggle.com/scripts) to solve data science challenges.
|
- XGBoost is used in [Kaggle Script](https://www.kaggle.com/scripts) to solve data science challenges.
|
||||||
|
- Distribute XGBoost as Rest API server from Jupyter notebook with [BentoML](https://github.com/bentoml/bentoml). [Link to notebook](https://github.com/bentoml/BentoML/blob/master/examples/xgboost-predict-titanic-survival/XGBoost-titanic-survival-prediction.ipynb)
|
||||||
- [Seldon predictive service powered by XGBoost](http://docs.seldon.io/iris-demo.html)
|
- [Seldon predictive service powered by XGBoost](http://docs.seldon.io/iris-demo.html)
|
||||||
- XGBoost Distributed is used in [ODPS Cloud Service by Alibaba](https://yq.aliyun.com/articles/6355) (in Chinese)
|
- XGBoost Distributed is used in [ODPS Cloud Service by Alibaba](https://yq.aliyun.com/articles/6355) (in Chinese)
|
||||||
- XGBoost is incoporated as part of [Graphlab Create](https://dato.com/products/create/) for scalable machine learning.
|
- XGBoost is incoporated as part of [Graphlab Create](https://dato.com/products/create/) for scalable machine learning.
|
||||||
|
|||||||
19
demo/c-api/Makefile
Normal file
19
demo/c-api/Makefile
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
SRC=c-api-demo.c
|
||||||
|
TGT=c-api-demo
|
||||||
|
|
||||||
|
cc=cc
|
||||||
|
CFLAGS ?=-O3
|
||||||
|
XGBOOST_ROOT ?=../..
|
||||||
|
INCLUDE_DIR=-I$(XGBOOST_ROOT)/include -I$(XGBOOST_ROOT)/dmlc-core/include -I$(XGBOOST_ROOT)/rabit/include
|
||||||
|
LIB_DIR=-L$(XGBOOST_ROOT)/lib
|
||||||
|
|
||||||
|
build: $(TGT)
|
||||||
|
|
||||||
|
$(TGT): $(SRC) Makefile
|
||||||
|
$(cc) $(CFLAGS) $(INCLUDE_DIR) $(LIB_DIR) -o $(TGT) $(SRC) -lxgboost
|
||||||
|
|
||||||
|
run: $(TGT)
|
||||||
|
LD_LIBRARY_PATH=$(XGBOOST_ROOT)/lib ./$(TGT)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f $(TGT)
|
||||||
30
demo/c-api/README.md
Normal file
30
demo/c-api/README.md
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
C-APIs
|
||||||
|
===
|
||||||
|
|
||||||
|
**XGBoost** implements a C API originally designed for various language
|
||||||
|
bindings. For detailed reference, please check xgboost/c_api.h. Here is a
|
||||||
|
demonstration of using the API.
|
||||||
|
|
||||||
|
# CMake
|
||||||
|
If you use **CMake** for your project, you can either install **XGBoost**
|
||||||
|
somewhere in your system and tell CMake to find it by calling
|
||||||
|
`find_package(xgboost)`, or put **XGBoost** inside your project's source tree
|
||||||
|
and call **CMake** command: `add_subdirectory(xgboost)`. To use
|
||||||
|
`find_package()`, put the following in your **CMakeLists.txt**:
|
||||||
|
|
||||||
|
``` CMake
|
||||||
|
find_package(xgboost REQUIRED)
|
||||||
|
add_executable(api-demo c-api-demo.c)
|
||||||
|
target_link_libraries(api-demo xgboost::xgboost)
|
||||||
|
```
|
||||||
|
|
||||||
|
If you want to put XGBoost inside your project (like git submodule), use this
|
||||||
|
instead:
|
||||||
|
``` CMake
|
||||||
|
add_subdirectory(xgboost)
|
||||||
|
add_executable(api-demo c-api-demo.c)
|
||||||
|
target_link_libraries(api-demo xgboost)
|
||||||
|
```
|
||||||
|
|
||||||
|
# make
|
||||||
|
You can start by modifying the makefile in this directory to fit your need.
|
||||||
89
demo/c-api/c-api-demo.c
Normal file
89
demo/c-api/c-api-demo.c
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
/*!
|
||||||
|
* Copyright 2019 XGBoost contributors
|
||||||
|
*
|
||||||
|
* \file c-api-demo.c
|
||||||
|
* \brief A simple example of using xgboost C API.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <xgboost/c_api.h>
|
||||||
|
|
||||||
|
#define safe_xgboost(call) { \
|
||||||
|
int err = (call); \
|
||||||
|
if (err != 0) { \
|
||||||
|
fprintf(stderr, "%s:%d: error in %s: %s\n", __FILE__, __LINE__, #call, XGBGetLastError()); \
|
||||||
|
exit(1); \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
int silent = 0;
|
||||||
|
int use_gpu = 0; // set to 1 to use the GPU for training
|
||||||
|
|
||||||
|
// load the data
|
||||||
|
DMatrixHandle dtrain, dtest;
|
||||||
|
safe_xgboost(XGDMatrixCreateFromFile("../data/agaricus.txt.train", silent, &dtrain));
|
||||||
|
safe_xgboost(XGDMatrixCreateFromFile("../data/agaricus.txt.test", silent, &dtest));
|
||||||
|
|
||||||
|
// create the booster
|
||||||
|
BoosterHandle booster;
|
||||||
|
DMatrixHandle eval_dmats[2] = {dtrain, dtest};
|
||||||
|
safe_xgboost(XGBoosterCreate(eval_dmats, 2, &booster));
|
||||||
|
|
||||||
|
// configure the training
|
||||||
|
// available parameters are described here:
|
||||||
|
// https://xgboost.readthedocs.io/en/latest/parameter.html
|
||||||
|
safe_xgboost(XGBoosterSetParam(booster, "tree_method", use_gpu ? "gpu_hist" : "hist"));
|
||||||
|
if (use_gpu) {
|
||||||
|
// set the number of GPUs and the first GPU to use;
|
||||||
|
// this is not necessary, but provided here as an illustration
|
||||||
|
safe_xgboost(XGBoosterSetParam(booster, "n_gpus", "1"));
|
||||||
|
safe_xgboost(XGBoosterSetParam(booster, "gpu_id", "0"));
|
||||||
|
} else {
|
||||||
|
// avoid evaluating objective and metric on a GPU
|
||||||
|
safe_xgboost(XGBoosterSetParam(booster, "n_gpus", "0"));
|
||||||
|
}
|
||||||
|
|
||||||
|
safe_xgboost(XGBoosterSetParam(booster, "objective", "binary:logistic"));
|
||||||
|
safe_xgboost(XGBoosterSetParam(booster, "min_child_weight", "1"));
|
||||||
|
safe_xgboost(XGBoosterSetParam(booster, "gamma", "0.1"));
|
||||||
|
safe_xgboost(XGBoosterSetParam(booster, "max_depth", "3"));
|
||||||
|
safe_xgboost(XGBoosterSetParam(booster, "verbosity", silent ? "0" : "1"));
|
||||||
|
|
||||||
|
// train and evaluate for 10 iterations
|
||||||
|
int n_trees = 10;
|
||||||
|
const char* eval_names[2] = {"train", "test"};
|
||||||
|
const char* eval_result = NULL;
|
||||||
|
for (int i = 0; i < n_trees; ++i) {
|
||||||
|
safe_xgboost(XGBoosterUpdateOneIter(booster, i, dtrain));
|
||||||
|
safe_xgboost(XGBoosterEvalOneIter(booster, i, eval_dmats, eval_names, 2, &eval_result));
|
||||||
|
printf("%s\n", eval_result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// predict
|
||||||
|
bst_ulong out_len = 0;
|
||||||
|
const float* out_result = NULL;
|
||||||
|
int n_print = 10;
|
||||||
|
|
||||||
|
safe_xgboost(XGBoosterPredict(booster, dtest, 0, 0, &out_len, &out_result));
|
||||||
|
printf("y_pred: ");
|
||||||
|
for (int i = 0; i < n_print; ++i) {
|
||||||
|
printf("%1.4f ", out_result[i]);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
// print true labels
|
||||||
|
safe_xgboost(XGDMatrixGetFloatInfo(dtest, "label", &out_len, &out_result));
|
||||||
|
printf("y_test: ");
|
||||||
|
for (int i = 0; i < n_print; ++i) {
|
||||||
|
printf("%1.4f ", out_result[i]);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
// free everything
|
||||||
|
safe_xgboost(XGBoosterFree(booster));
|
||||||
|
safe_xgboost(XGDMatrixFree(dtrain));
|
||||||
|
safe_xgboost(XGDMatrixFree(dtest));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -6,9 +6,9 @@ Using XGBoost for regression is very similar to using it for binary classificati
|
|||||||
The dataset we used is the [computer hardware dataset from UCI repository](https://archive.ics.uci.edu/ml/datasets/Computer+Hardware). The demo for regression is almost the same as the [binary classification demo](../binary_classification), except a little difference in general parameter:
|
The dataset we used is the [computer hardware dataset from UCI repository](https://archive.ics.uci.edu/ml/datasets/Computer+Hardware). The demo for regression is almost the same as the [binary classification demo](../binary_classification), except a little difference in general parameter:
|
||||||
```
|
```
|
||||||
# General parameter
|
# General parameter
|
||||||
# this is the only difference with classification, use reg:linear to do linear regression
|
# this is the only difference with classification, use reg:squarederror to do linear regression
|
||||||
# when labels are in [0,1] we can also use reg:logistic
|
# when labels are in [0,1] we can also use reg:logistic
|
||||||
objective = reg:linear
|
objective = reg:squarederror
|
||||||
...
|
...
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
# General Parameters, see comment for each definition
|
# General Parameters, see comment for each definition
|
||||||
# choose the tree booster, can also change to gblinear
|
# choose the tree booster, can also change to gblinear
|
||||||
booster = gbtree
|
booster = gbtree
|
||||||
# this is the only difference with classification, use reg:linear to do linear classification
|
# this is the only difference with classification, use reg:squarederror to do linear classification
|
||||||
# when labels are in [0,1] we can also use reg:logistic
|
# when labels are in [0,1] we can also use reg:logistic
|
||||||
objective = reg:linear
|
objective = reg:squarederror
|
||||||
|
|
||||||
# Tree Booster Parameters
|
# Tree Booster Parameters
|
||||||
# step size shrinkage
|
# step size shrinkage
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
# General Parameters, see comment for each definition
|
# General Parameters, see comment for each definition
|
||||||
# choose the tree booster, can also change to gblinear
|
# choose the tree booster, can also change to gblinear
|
||||||
booster = gbtree
|
booster = gbtree
|
||||||
# this is the only difference with classification, use reg:linear to do linear classification
|
# this is the only difference with classification, use reg:squarederror to do linear classification
|
||||||
# when labels are in [0,1] we can also use reg:logistic
|
# when labels are in [0,1] we can also use reg:logistic
|
||||||
objective = reg:linear
|
objective = reg:squarederror
|
||||||
|
|
||||||
# Tree Booster Parameters
|
# Tree Booster Parameters
|
||||||
# step size shrinkage
|
# step size shrinkage
|
||||||
@@ -27,4 +27,3 @@ data = "yearpredMSD.libsvm.train"
|
|||||||
eval[test] = "yearpredMSD.libsvm.test"
|
eval[test] = "yearpredMSD.libsvm.test"
|
||||||
# The path of test data
|
# The path of test data
|
||||||
#test:data = "yearpredMSD.libsvm.test"
|
#test:data = "yearpredMSD.libsvm.test"
|
||||||
|
|
||||||
|
|||||||
63
dev/query_contributors.py
Normal file
63
dev/query_contributors.py
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
"""Query list of all contributors and reviewers in a release"""
|
||||||
|
|
||||||
|
from sh.contrib import git
|
||||||
|
import sys
|
||||||
|
import re
|
||||||
|
import requests
|
||||||
|
import json
|
||||||
|
|
||||||
|
if len(sys.argv) != 5:
|
||||||
|
print(f'Usage: {sys.argv[0]} [starting commit/tag] [ending commit/tag] [GitHub username] [GitHub password]')
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
from_commit = sys.argv[1]
|
||||||
|
to_commit = sys.argv[2]
|
||||||
|
username = sys.argv[3]
|
||||||
|
password = sys.argv[4]
|
||||||
|
|
||||||
|
contributors = set()
|
||||||
|
reviewers = set()
|
||||||
|
|
||||||
|
for line in git.log(f'{from_commit}..{to_commit}', '--pretty=format:%s', '--reverse'):
|
||||||
|
m = re.search('\(#([0-9]+)\)', line.rstrip())
|
||||||
|
if m:
|
||||||
|
pr_id = m.group(1)
|
||||||
|
print(f'PR #{pr_id}')
|
||||||
|
|
||||||
|
r = requests.get(f'https://api.github.com/repos/dmlc/xgboost/pulls/{pr_id}/commits', auth=(username, password))
|
||||||
|
assert r.status_code == requests.codes.ok, f'Code: {r.status_code}, Text: {r.text}'
|
||||||
|
commit_list = json.loads(r.text)
|
||||||
|
try:
|
||||||
|
contributors.update([commit['author']['login'] for commit in commit_list])
|
||||||
|
except TypeError:
|
||||||
|
contributors.update(str(input(f'Error fetching contributors for PR #{pr_id}. Enter it manually, as a space-separated list:')).split(' '))
|
||||||
|
|
||||||
|
r = requests.get(f'https://api.github.com/repos/dmlc/xgboost/pulls/{pr_id}/reviews', auth=(username, password))
|
||||||
|
assert r.status_code == requests.codes.ok, f'Code: {r.status_code}, Text: {r.text}'
|
||||||
|
review_list = json.loads(r.text)
|
||||||
|
reviewers.update([x['user']['login'] for x in review_list])
|
||||||
|
|
||||||
|
r = requests.get(f'https://api.github.com/repos/dmlc/xgboost/issues/{pr_id}/comments', auth=(username, password))
|
||||||
|
assert r.status_code == requests.codes.ok, f'Code: {r.status_code}, Text: {r.text}'
|
||||||
|
comment_list = json.loads(r.text)
|
||||||
|
reviewers.update([x['user']['login'] for x in comment_list])
|
||||||
|
|
||||||
|
print('Contributors:', end='')
|
||||||
|
for x in sorted(contributors):
|
||||||
|
r = requests.get(f'https://api.github.com/users/{x}', auth=(username, password))
|
||||||
|
assert r.status_code == requests.codes.ok, f'Code: {r.status_code}, Text: {r.text}'
|
||||||
|
user_info = json.loads(r.text)
|
||||||
|
if user_info['name'] is None:
|
||||||
|
print(f"@{x}, ", end='')
|
||||||
|
else:
|
||||||
|
print(f"{user_info['name']} (@{x}), ", end='')
|
||||||
|
|
||||||
|
print('Reviewers:', end='')
|
||||||
|
for x in sorted(reviewers):
|
||||||
|
r = requests.get(f'https://api.github.com/users/{x}', auth=(username, password))
|
||||||
|
assert r.status_code == requests.codes.ok, f'Code: {r.status_code}, Text: {r.text}'
|
||||||
|
user_info = json.loads(r.text)
|
||||||
|
if user_info['name'] is None:
|
||||||
|
print(f"@{x}, ", end='')
|
||||||
|
else:
|
||||||
|
print(f"{user_info['name']} (@{x}), ", end='')
|
||||||
Submodule dmlc-core updated: ac983092ee...3943914eed
@@ -38,7 +38,7 @@ PROJECT_NAME = "xgboost"
|
|||||||
# could be handy for archiving the generated documentation or if some version
|
# could be handy for archiving the generated documentation or if some version
|
||||||
# control system is used.
|
# control system is used.
|
||||||
|
|
||||||
PROJECT_NUMBER =
|
PROJECT_NUMBER = @XGBOOST_VERSION@
|
||||||
|
|
||||||
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
||||||
# for a project that appears at the top of each page and should give viewer a
|
# for a project that appears at the top of each page and should give viewer a
|
||||||
@@ -58,7 +58,7 @@ PROJECT_LOGO =
|
|||||||
# entered, it will be relative to the location where doxygen was started. If
|
# entered, it will be relative to the location where doxygen was started. If
|
||||||
# left blank the current directory will be used.
|
# left blank the current directory will be used.
|
||||||
|
|
||||||
OUTPUT_DIRECTORY = doc/doxygen
|
OUTPUT_DIRECTORY = @PROJECT_BINARY_DIR@/doc_doxygen
|
||||||
|
|
||||||
# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub-
|
# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub-
|
||||||
# directories (in 2 levels) under the output directory of each output format and
|
# directories (in 2 levels) under the output directory of each output format and
|
||||||
@@ -753,7 +753,7 @@ WARN_LOGFILE =
|
|||||||
# spaces.
|
# spaces.
|
||||||
# Note: If this tag is empty the current directory is searched.
|
# Note: If this tag is empty the current directory is searched.
|
||||||
|
|
||||||
INPUT = include src/common
|
INPUT = @PROJECT_SOURCE_DIR@/include @PROJECT_SOURCE_DIR@/src/common
|
||||||
|
|
||||||
# This tag can be used to specify the character encoding of the source files
|
# This tag can be used to specify the character encoding of the source files
|
||||||
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
|
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
|
||||||
123
doc/build.rst
123
doc/build.rst
@@ -13,7 +13,7 @@ Installation Guide
|
|||||||
# * xgboost-{version}-py2.py3-none-win_amd64.whl
|
# * xgboost-{version}-py2.py3-none-win_amd64.whl
|
||||||
pip3 install xgboost
|
pip3 install xgboost
|
||||||
|
|
||||||
* The binary wheel will support GPU algorithms (`gpu_exact`, `gpu_hist`) on machines with NVIDIA GPUs. **However, it will not support multi-GPU training; only single GPU will be used.** To enable multi-GPU training, download and install the binary wheel from `this page <https://s3-us-west-2.amazonaws.com/xgboost-wheels/list.html>`_.
|
* The binary wheel will support GPU algorithms (`gpu_exact`, `gpu_hist`) on machines with NVIDIA GPUs. Please note that **training with multiple GPUs is only supported for Linux platform**. See :doc:`gpu/index`.
|
||||||
* Currently, we provide binary wheels for 64-bit Linux and Windows.
|
* Currently, we provide binary wheels for 64-bit Linux and Windows.
|
||||||
|
|
||||||
****************************
|
****************************
|
||||||
@@ -70,19 +70,21 @@ Our goal is to build the shared library:
|
|||||||
The minimal building requirement is
|
The minimal building requirement is
|
||||||
|
|
||||||
- A recent C++ compiler supporting C++11 (g++-4.8 or higher)
|
- A recent C++ compiler supporting C++11 (g++-4.8 or higher)
|
||||||
|
- CMake 3.2 or higher
|
||||||
We can edit ``make/config.mk`` to change the compile options, and then build by
|
|
||||||
``make``. If everything goes well, we can go to the specific language installation section.
|
|
||||||
|
|
||||||
Building on Ubuntu/Debian
|
Building on Ubuntu/Debian
|
||||||
=========================
|
=========================
|
||||||
|
|
||||||
On Ubuntu, one builds XGBoost by running
|
On Ubuntu, one builds XGBoost by running CMake:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
git clone --recursive https://github.com/dmlc/xgboost
|
git clone --recursive https://github.com/dmlc/xgboost
|
||||||
cd xgboost; make -j4
|
cd xgboost
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
cmake ..
|
||||||
|
make -j4
|
||||||
|
|
||||||
Building on OSX
|
Building on OSX
|
||||||
===============
|
===============
|
||||||
@@ -90,11 +92,11 @@ Building on OSX
|
|||||||
Install with pip: simple method
|
Install with pip: simple method
|
||||||
--------------------------------
|
--------------------------------
|
||||||
|
|
||||||
First, obtain ``gcc-7`` with Homebrew (https://brew.sh/) to enable multi-threading (i.e. using multiple CPU threads for training). The default Apple Clang compiler does not support OpenMP, so using the default compiler would have disabled multi-threading.
|
First, obtain ``gcc-8`` with Homebrew (https://brew.sh/) to enable multi-threading (i.e. using multiple CPU threads for training). The default Apple Clang compiler does not support OpenMP, so using the default compiler would have disabled multi-threading.
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
brew install gcc@7
|
brew install gcc@8
|
||||||
|
|
||||||
Then install XGBoost with ``pip``:
|
Then install XGBoost with ``pip``:
|
||||||
|
|
||||||
@@ -107,11 +109,11 @@ You might need to run the command with ``--user`` flag if you run into permissio
|
|||||||
Build from the source code - advanced method
|
Build from the source code - advanced method
|
||||||
--------------------------------------------
|
--------------------------------------------
|
||||||
|
|
||||||
Obtain ``gcc-7`` from Homebrew:
|
Obtain ``gcc-8`` from Homebrew:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
brew install gcc@7
|
brew install gcc@8
|
||||||
|
|
||||||
Now clone the repository:
|
Now clone the repository:
|
||||||
|
|
||||||
@@ -119,13 +121,13 @@ Now clone the repository:
|
|||||||
|
|
||||||
git clone --recursive https://github.com/dmlc/xgboost
|
git clone --recursive https://github.com/dmlc/xgboost
|
||||||
|
|
||||||
Create the ``build/`` directory and invoke CMake. Make sure to add ``CC=gcc-7 CXX=g++-7`` so that Homebrew GCC is selected. After invoking CMake, you can build XGBoost with ``make``:
|
Create the ``build/`` directory and invoke CMake. Make sure to add ``CC=gcc-8 CXX=g++-8`` so that Homebrew GCC is selected. After invoking CMake, you can build XGBoost with ``make``:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
mkdir build
|
mkdir build
|
||||||
cd build
|
cd build
|
||||||
CC=gcc-7 CXX=g++-7 cmake ..
|
CC=gcc-8 CXX=g++-8 cmake ..
|
||||||
make -j4
|
make -j4
|
||||||
|
|
||||||
You may now continue to `Python Package Installation`_.
|
You may now continue to `Python Package Installation`_.
|
||||||
@@ -142,6 +144,20 @@ We recommend you use `Git for Windows <https://git-for-windows.github.io/>`_, as
|
|||||||
|
|
||||||
XGBoost support compilation with Microsoft Visual Studio and MinGW.
|
XGBoost support compilation with Microsoft Visual Studio and MinGW.
|
||||||
|
|
||||||
|
Compile XGBoost with Microsoft Visual Studio
|
||||||
|
--------------------------------------------
|
||||||
|
To build with Visual Studio, we will need CMake. Make sure to install a recent version of CMake. Then run the following from the root of the XGBoost directory:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
cmake .. -G"Visual Studio 14 2015 Win64"
|
||||||
|
|
||||||
|
This specifies an out of source build using the Visual Studio 64 bit generator. (Change the ``-G`` option appropriately if you have a different version of Visual Studio installed.) Open the ``.sln`` file in the build directory and build with Visual Studio.
|
||||||
|
|
||||||
|
After the build process successfully ends, you will find a ``xgboost.dll`` library file inside ``./lib/`` folder.
|
||||||
|
|
||||||
Compile XGBoost using MinGW
|
Compile XGBoost using MinGW
|
||||||
---------------------------
|
---------------------------
|
||||||
After installing `Git for Windows <https://git-for-windows.github.io/>`_, you should have a shortcut named ``Git Bash``. You should run all subsequent steps in ``Git Bash``.
|
After installing `Git for Windows <https://git-for-windows.github.io/>`_, you should have a shortcut named ``Git Bash``. You should run all subsequent steps in ``Git Bash``.
|
||||||
@@ -163,29 +179,15 @@ To build with MinGW, type:
|
|||||||
|
|
||||||
See :ref:`mingw_python` for buildilng XGBoost for Python.
|
See :ref:`mingw_python` for buildilng XGBoost for Python.
|
||||||
|
|
||||||
Compile XGBoost with Microsoft Visual Studio
|
|
||||||
--------------------------------------------
|
|
||||||
To build with Visual Studio, we will need CMake. Make sure to install a recent version of CMake. Then run the following from the root of the XGBoost directory:
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
mkdir build
|
|
||||||
cd build
|
|
||||||
cmake .. -G"Visual Studio 12 2013 Win64"
|
|
||||||
|
|
||||||
This specifies an out of source build using the MSVC 12 64 bit generator. Open the ``.sln`` file in the build directory and build with Visual Studio. To use the Python module you can copy ``xgboost.dll`` into ``python-package/xgboost``.
|
|
||||||
|
|
||||||
After the build process successfully ends, you will find a ``xgboost.dll`` library file inside ``./lib/`` folder, copy this file to the the API package folder like ``python-package/xgboost`` if you are using Python API.
|
|
||||||
|
|
||||||
Unofficial windows binaries and instructions on how to use them are hosted on `Guido Tapia's blog <http://www.picnet.com.au/blogs/guido/post/2016/09/22/xgboost-windows-x64-binaries-for-download/>`_.
|
|
||||||
|
|
||||||
.. _build_gpu_support:
|
.. _build_gpu_support:
|
||||||
|
|
||||||
Building with GPU support
|
Building with GPU support
|
||||||
=========================
|
=========================
|
||||||
XGBoost can be built with GPU support for both Linux and Windows using CMake. GPU support works with the Python package as well as the CLI version. See `Installing R package with GPU support`_ for special instructions for R.
|
XGBoost can be built with GPU support for both Linux and Windows using CMake. GPU support works with the Python package as well as the CLI version. See `Installing R package with GPU support`_ for special instructions for R.
|
||||||
|
|
||||||
An up-to-date version of the CUDA toolkit is required.
|
An up-to-date version of the CUDA toolkit is required. Please note that we
|
||||||
|
skipped the support for compiling XGBoost with NVCC 10.1 due a small bug in its
|
||||||
|
spliter, see `#4264 <https://github.com/dmlc/xgboost/issues/4264>`_.
|
||||||
|
|
||||||
From the command line on Linux starting from the XGBoost directory:
|
From the command line on Linux starting from the XGBoost directory:
|
||||||
|
|
||||||
@@ -207,13 +209,7 @@ From the command line on Linux starting from the XGBoost directory:
|
|||||||
cmake .. -DUSE_CUDA=ON -DUSE_NCCL=ON -DNCCL_ROOT=/path/to/nccl2
|
cmake .. -DUSE_CUDA=ON -DUSE_NCCL=ON -DNCCL_ROOT=/path/to/nccl2
|
||||||
make -j4
|
make -j4
|
||||||
|
|
||||||
On Windows, see what options for generators you have for CMake, and choose one with ``[arch]`` replaced with Win64:
|
On Windows, run CMake as follows:
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
cmake -help
|
|
||||||
|
|
||||||
Then run CMake as follows:
|
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
@@ -221,13 +217,15 @@ Then run CMake as follows:
|
|||||||
cd build
|
cd build
|
||||||
cmake .. -G"Visual Studio 14 2015 Win64" -DUSE_CUDA=ON
|
cmake .. -G"Visual Studio 14 2015 Win64" -DUSE_CUDA=ON
|
||||||
|
|
||||||
|
(Change the ``-G`` option appropriately if you have a different version of Visual Studio installed.)
|
||||||
|
|
||||||
.. note:: Visual Studio 2017 Win64 Generator may not work
|
.. note:: Visual Studio 2017 Win64 Generator may not work
|
||||||
|
|
||||||
Choosing the Visual Studio 2017 generator may cause compilation failure. When it happens, specify the 2015 compiler by adding the ``-T`` option:
|
Choosing the Visual Studio 2017 generator may cause compilation failure. When it happens, specify the 2015 compiler by adding the ``-T`` option:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
make .. -G"Visual Studio 15 2017 Win64" -T v140,cuda=8.0 -DR_LIB=ON -DUSE_CUDA=ON
|
make .. -G"Visual Studio 15 2017 Win64" -T v140,cuda=8.0 -DUSE_CUDA=ON
|
||||||
|
|
||||||
To speed up compilation, the compute version specific to your GPU could be passed to cmake as, e.g., ``-DGPU_COMPUTE_VER=50``.
|
To speed up compilation, the compute version specific to your GPU could be passed to cmake as, e.g., ``-DGPU_COMPUTE_VER=50``.
|
||||||
The above cmake configuration run will create an ``xgboost.sln`` solution file in the build directory. Build this solution in release mode as a x64 build, either from Visual studio or from command line:
|
The above cmake configuration run will create an ``xgboost.sln`` solution file in the build directory. Build this solution in release mode as a x64 build, either from Visual studio or from command line:
|
||||||
@@ -241,15 +239,15 @@ To speed up compilation, run multiple jobs in parallel by appending option ``--
|
|||||||
Customized Building
|
Customized Building
|
||||||
===================
|
===================
|
||||||
|
|
||||||
The configuration file ``config.mk`` modifies several compilation flags:
|
We recommend the use of CMake for most use cases. See the full range of building options in CMakeLists.txt.
|
||||||
|
|
||||||
|
Alternatively, you may use Makefile. The Makefile uses a configuration file ``config.mk``, which lets you modify several compilation flags:
|
||||||
- Whether to enable support for various distributed filesystems such as HDFS and Amazon S3
|
- Whether to enable support for various distributed filesystems such as HDFS and Amazon S3
|
||||||
- Which compiler to use
|
- Which compiler to use
|
||||||
- And some more
|
- And some more
|
||||||
|
|
||||||
To customize, first copy ``make/config.mk`` to the project root and then modify the copy.
|
To customize, first copy ``make/config.mk`` to the project root and then modify the copy.
|
||||||
|
|
||||||
Alternatively, use CMake.
|
|
||||||
|
|
||||||
Python Package Installation
|
Python Package Installation
|
||||||
===========================
|
===========================
|
||||||
|
|
||||||
@@ -275,9 +273,9 @@ package manager, e.g. in Debian use
|
|||||||
If you recompiled XGBoost, then you need to reinstall it again to make the new library take effect.
|
If you recompiled XGBoost, then you need to reinstall it again to make the new library take effect.
|
||||||
|
|
||||||
2. Only set the environment variable ``PYTHONPATH`` to tell Python where to find
|
2. Only set the environment variable ``PYTHONPATH`` to tell Python where to find
|
||||||
the library. For example, assume we cloned `xgboost` on the home directory
|
the library. For example, assume we cloned ``xgboost`` on the home directory
|
||||||
`~`. then we can added the following line in `~/.bashrc`.
|
``~``. then we can added the following line in ``~/.bashrc``.
|
||||||
This option is **recommended for developers** who change the code frequently. The changes will be immediately reflected once you pulled the code and rebuild the project (no need to call ``setup`` again)
|
This option is **recommended for developers** who change the code frequently. The changes will be immediately reflected once you pulled the code and rebuild the project (no need to call ``setup`` again).
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
@@ -289,30 +287,22 @@ package manager, e.g. in Debian use
|
|||||||
|
|
||||||
cd python-package; python setup.py develop --user
|
cd python-package; python setup.py develop --user
|
||||||
|
|
||||||
4. If you are installing the latest XGBoost version which requires compilation, add MinGW to the system PATH:
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
import os
|
|
||||||
os.environ['PATH'] = os.environ['PATH'] + ';C:\\Program Files\\mingw-w64\\x86_64-5.3.0-posix-seh-rt_v4-rev0\\mingw64\\bin'
|
|
||||||
|
|
||||||
.. _mingw_python:
|
.. _mingw_python:
|
||||||
|
|
||||||
Building XGBoost library for Python for Windows with MinGW-w64
|
Building XGBoost library for Python for Windows with MinGW-w64 (Advanced)
|
||||||
--------------------------------------------------------------
|
-------------------------------------------------------------------------
|
||||||
|
|
||||||
Windows versions of Python are built with Microsoft Visual Studio. Usually Python binary modules are built with the same compiler the interpreter is built with, raising several potential concerns.
|
Windows versions of Python are built with Microsoft Visual Studio. Usually Python binary modules are built with the same compiler the interpreter is built with. However, you may not be able to use Visual Studio, for following reasons:
|
||||||
|
|
||||||
1. VS is proprietary and commercial software. Microsoft provides a freeware "Community" edition, but its licensing terms are unsuitable for many organizations.
|
1. VS is proprietary and commercial software. Microsoft provides a freeware "Community" edition, but its licensing terms impose restrictions as to where and how it can be used.
|
||||||
2. Visual Studio contains telemetry, as documented in `Microsoft Visual Studio Licensing Terms <https://visualstudio.microsoft.com/license-terms/mt736442/>`_. It `has been inserting telemetry <https://old.reddit.com/r/cpp/comments/4ibauu/visual_studio_adding_telemetry_function_calls_to/>`_ into apps for some time. In order to download VS distribution from MS servers one has to run the application containing telemetry. These facts have raised privacy and security concerns among some users and system administrators. Running software with telemetry may be against the policy of your organization.
|
2. Visual Studio contains telemetry, as documented in `Microsoft Visual Studio Licensing Terms <https://visualstudio.microsoft.com/license-terms/mt736442/>`_. Running software with telemetry may be against the policy of your organization.
|
||||||
3. g++ usually generates faster code on ``-O3``.
|
|
||||||
|
|
||||||
So you may want to build XGBoost with g++ own your own risk. This opens a can of worms, because MSVC uses Microsoft runtime and MinGW-w64 uses own runtime, and the runtimes have different incompatible memory allocators. But in fact this setup is usable if you know how to deal with it. Here is some experience.
|
So you may want to build XGBoost with GCC own your own risk. This presents some difficulties because MSVC uses Microsoft runtime and MinGW-w64 uses own runtime, and the runtimes have different incompatible memory allocators. But in fact this setup is usable if you know how to deal with it. Here is some experience.
|
||||||
|
|
||||||
1. The Python interpreter will crash on exit if XGBoost was used. This is usually not a big issue.
|
1. The Python interpreter will crash on exit if XGBoost was used. This is usually not a big issue.
|
||||||
2. ``-O3`` is OK.
|
2. ``-O3`` is OK.
|
||||||
3. ``-mtune=native`` is also OK.
|
3. ``-mtune=native`` is also OK.
|
||||||
4. Don't use ``-march=native`` gcc flag. Using it causes the Python interpreter to crash if the dll was actually used.
|
4. Don't use ``-march=native`` gcc flag. Using it causes the Python interpreter to crash if the DLL was actually used.
|
||||||
5. You may need to provide the lib with the runtime libs. If ``mingw32/bin`` is not in ``PATH``, build a wheel (``python setup.py bdist_wheel``), open it with an archiver and put the needed dlls to the directory where ``xgboost.dll`` is situated. Then you can install the wheel with ``pip``.
|
5. You may need to provide the lib with the runtime libs. If ``mingw32/bin`` is not in ``PATH``, build a wheel (``python setup.py bdist_wheel``), open it with an archiver and put the needed dlls to the directory where ``xgboost.dll`` is situated. Then you can install the wheel with ``pip``.
|
||||||
|
|
||||||
R Package Installation
|
R Package Installation
|
||||||
@@ -355,7 +345,7 @@ In this case, just start R as you would normally do and run the following:
|
|||||||
setwd('wherever/you/cloned/it/xgboost/R-package/')
|
setwd('wherever/you/cloned/it/xgboost/R-package/')
|
||||||
install.packages('.', repos = NULL, type="source")
|
install.packages('.', repos = NULL, type="source")
|
||||||
|
|
||||||
The package could also be built and installed with cmake (and Visual C++ 2015 on Windows) using instructions from the next section, but without GPU support (omit the ``-DUSE_CUDA=ON`` cmake parameter).
|
The package could also be built and installed with CMake (and Visual C++ 2015 on Windows) using instructions from :ref:`r_gpu_support`, but without GPU support (omit the ``-DUSE_CUDA=ON`` cmake parameter).
|
||||||
|
|
||||||
If all fails, try `Building the shared library`_ to see whether a problem is specific to R package or not.
|
If all fails, try `Building the shared library`_ to see whether a problem is specific to R package or not.
|
||||||
|
|
||||||
@@ -364,11 +354,11 @@ If all fails, try `Building the shared library`_ to see whether a problem is spe
|
|||||||
Installing R package on Mac OSX with multi-threading
|
Installing R package on Mac OSX with multi-threading
|
||||||
----------------------------------------------------
|
----------------------------------------------------
|
||||||
|
|
||||||
First, obtain ``gcc-7`` with Homebrew (https://brew.sh/) to enable multi-threading (i.e. using multiple CPU threads for training). The default Apple Clang compiler does not support OpenMP, so using the default compiler would have disabled multi-threading.
|
First, obtain ``gcc-8`` with Homebrew (https://brew.sh/) to enable multi-threading (i.e. using multiple CPU threads for training). The default Apple Clang compiler does not support OpenMP, so using the default compiler would have disabled multi-threading.
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
brew install gcc@7
|
brew install gcc@8
|
||||||
|
|
||||||
Now, clone the repository:
|
Now, clone the repository:
|
||||||
|
|
||||||
@@ -376,7 +366,7 @@ Now, clone the repository:
|
|||||||
|
|
||||||
git clone --recursive https://github.com/dmlc/xgboost
|
git clone --recursive https://github.com/dmlc/xgboost
|
||||||
|
|
||||||
Create the ``build/`` directory and invoke CMake with option ``R_LIB=ON``. Make sure to add ``CC=gcc-7 CXX=g++-7`` so that Homebrew GCC is selected. After invoking CMake, you can install the R package by running ``make`` and ``make install``:
|
Create the ``build/`` directory and invoke CMake with option ``R_LIB=ON``. Make sure to add ``CC=gcc-8 CXX=g++-8`` so that Homebrew GCC is selected. After invoking CMake, you can install the R package by running ``make`` and ``make install``:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
@@ -386,6 +376,8 @@ Create the ``build/`` directory and invoke CMake with option ``R_LIB=ON``. Make
|
|||||||
make -j4
|
make -j4
|
||||||
make install
|
make install
|
||||||
|
|
||||||
|
.. _r_gpu_support:
|
||||||
|
|
||||||
Installing R package with GPU support
|
Installing R package with GPU support
|
||||||
-------------------------------------
|
-------------------------------------
|
||||||
|
|
||||||
@@ -401,7 +393,7 @@ On Linux, starting from the XGBoost directory type:
|
|||||||
make install -j
|
make install -j
|
||||||
|
|
||||||
When default target is used, an R package shared library would be built in the ``build`` area.
|
When default target is used, an R package shared library would be built in the ``build`` area.
|
||||||
The ``install`` target, in addition, assembles the package files with this shared library under ``build/R-package``, and runs ``R CMD INSTALL``.
|
The ``install`` target, in addition, assembles the package files with this shared library under ``build/R-package`` and runs ``R CMD INSTALL``.
|
||||||
|
|
||||||
On Windows, CMake with Visual C++ Build Tools (or Visual Studio) has to be used to build an R package with GPU support. Rtools must also be installed (perhaps, some other MinGW distributions with ``gendef.exe`` and ``dlltool.exe`` would work, but that was not tested).
|
On Windows, CMake with Visual C++ Build Tools (or Visual Studio) has to be used to build an R package with GPU support. Rtools must also be installed (perhaps, some other MinGW distributions with ``gendef.exe`` and ``dlltool.exe`` would work, but that was not tested).
|
||||||
|
|
||||||
@@ -412,8 +404,8 @@ On Windows, CMake with Visual C++ Build Tools (or Visual Studio) has to be used
|
|||||||
cmake .. -G"Visual Studio 14 2015 Win64" -DUSE_CUDA=ON -DR_LIB=ON
|
cmake .. -G"Visual Studio 14 2015 Win64" -DUSE_CUDA=ON -DR_LIB=ON
|
||||||
cmake --build . --target install --config Release
|
cmake --build . --target install --config Release
|
||||||
|
|
||||||
When ``--target xgboost`` is used, an R package dll would be built under ``build/Release``.
|
When ``--target xgboost`` is used, an R package DLL would be built under ``build/Release``.
|
||||||
The ``--target install``, in addition, assembles the package files with this dll under ``build/R-package``, and runs ``R CMD INSTALL``.
|
The ``--target install``, in addition, assembles the package files with this dll under ``build/R-package`` and runs ``R CMD INSTALL``.
|
||||||
|
|
||||||
If cmake can't find your R during the configuration step, you might provide the location of its executable to cmake like this: ``-DLIBR_EXECUTABLE="C:/Program Files/R/R-3.4.1/bin/x64/R.exe"``.
|
If cmake can't find your R during the configuration step, you might provide the location of its executable to cmake like this: ``-DLIBR_EXECUTABLE="C:/Program Files/R/R-3.4.1/bin/x64/R.exe"``.
|
||||||
|
|
||||||
@@ -458,4 +450,3 @@ Trouble Shooting
|
|||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
git clone https://github.com/dmlc/xgboost --recursive
|
git clone https://github.com/dmlc/xgboost --recursive
|
||||||
|
|
||||||
|
|||||||
12
doc/conf.py
12
doc/conf.py
@@ -22,14 +22,22 @@ import os, subprocess
|
|||||||
import shlex
|
import shlex
|
||||||
import guzzle_sphinx_theme
|
import guzzle_sphinx_theme
|
||||||
|
|
||||||
git_branch = [re.sub(r'origin/', '', x.lstrip(' ')) for x in str(git.branch('-r', '--contains', 'HEAD')).rstrip('\n').split('\n')]
|
git_branch = os.getenv('SPHINX_GIT_BRANCH', default=None)
|
||||||
git_branch = [x for x in git_branch if 'HEAD' not in x]
|
if git_branch is None:
|
||||||
|
# If SPHINX_GIT_BRANCH environment variable is not given, run git to determine branch name
|
||||||
|
git_branch = [re.sub(r'origin/', '', x.lstrip(' ')) for x in str(git.branch('-r', '--contains', 'HEAD')).rstrip('\n').split('\n')]
|
||||||
|
git_branch = [x for x in git_branch if 'HEAD' not in x]
|
||||||
print('git_branch = {}'.format(git_branch[0]))
|
print('git_branch = {}'.format(git_branch[0]))
|
||||||
try:
|
try:
|
||||||
filename, _ = urllib.request.urlretrieve('https://s3-us-west-2.amazonaws.com/xgboost-docs/{}.tar.bz2'.format(git_branch[0]))
|
filename, _ = urllib.request.urlretrieve('https://s3-us-west-2.amazonaws.com/xgboost-docs/{}.tar.bz2'.format(git_branch[0]))
|
||||||
call('if [ -d tmp ]; then rm -rf tmp; fi; mkdir -p tmp/jvm; cd tmp/jvm; tar xvf {}'.format(filename), shell=True)
|
call('if [ -d tmp ]; then rm -rf tmp; fi; mkdir -p tmp/jvm; cd tmp/jvm; tar xvf {}'.format(filename), shell=True)
|
||||||
except HTTPError:
|
except HTTPError:
|
||||||
print('JVM doc not found. Skipping...')
|
print('JVM doc not found. Skipping...')
|
||||||
|
try:
|
||||||
|
filename, _ = urllib.request.urlretrieve('https://s3-us-west-2.amazonaws.com/xgboost-docs/doxygen/{}.tar.bz2'.format(git_branch[0]))
|
||||||
|
call('mkdir -p tmp/dev; cd tmp/dev; tar xvf {}; mv doc_doxygen/html/* .; rm -rf doc_doxygen'.format(filename), shell=True)
|
||||||
|
except HTTPError:
|
||||||
|
print('C API doc not found. Skipping...')
|
||||||
|
|
||||||
# If extensions (or modules to document with autodoc) are in another directory,
|
# If extensions (or modules to document with autodoc) are in another directory,
|
||||||
# add these directories to sys.path here. If the directory is relative to the
|
# add these directories to sys.path here. If the directory is relative to the
|
||||||
|
|||||||
@@ -166,7 +166,7 @@ environment variable:
|
|||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
ASAN_OPTIONS=protect_shadow_gap=0 ../testxgboost
|
ASAN_OPTIONS=protect_shadow_gap=0 ${BUILD_DIR}/testxgboost
|
||||||
|
|
||||||
For details, please consult `official documentation <https://github.com/google/sanitizers/wiki>`_ for sanitizers.
|
For details, please consult `official documentation <https://github.com/google/sanitizers/wiki>`_ for sanitizers.
|
||||||
|
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ Most of the objective functions implemented in XGBoost can be run on GPU. Follo
|
|||||||
+-----------------+-------------+
|
+-----------------+-------------+
|
||||||
| Objectives | GPU support |
|
| Objectives | GPU support |
|
||||||
+-----------------+-------------+
|
+-----------------+-------------+
|
||||||
| reg:linear | |tick| |
|
| reg:squarederror| |tick| |
|
||||||
+-----------------+-------------+
|
+-----------------+-------------+
|
||||||
| reg:logistic | |tick| |
|
| reg:logistic | |tick| |
|
||||||
+-----------------+-------------+
|
+-----------------+-------------+
|
||||||
@@ -195,6 +195,10 @@ Training time time on 1,000,000 rows x 50 columns with 500 boosting iterations a
|
|||||||
|
|
||||||
See `GPU Accelerated XGBoost <https://xgboost.ai/2016/12/14/GPU-accelerated-xgboost.html>`_ and `Updates to the XGBoost GPU algorithms <https://xgboost.ai/2018/07/04/gpu-xgboost-update.html>`_ for additional performance benchmarks of the ``gpu_exact`` and ``gpu_hist`` tree methods.
|
See `GPU Accelerated XGBoost <https://xgboost.ai/2016/12/14/GPU-accelerated-xgboost.html>`_ and `Updates to the XGBoost GPU algorithms <https://xgboost.ai/2018/07/04/gpu-xgboost-update.html>`_ for additional performance benchmarks of the ``gpu_exact`` and ``gpu_hist`` tree methods.
|
||||||
|
|
||||||
|
Developer notes
|
||||||
|
==========
|
||||||
|
The application may be profiled with annotations by specifying USE_NTVX to cmake and providing the path to the stand-alone nvtx header via NVTX_HEADER_DIR. Regions covered by the 'Monitor' class in cuda code will automatically appear in the nsight profiler.
|
||||||
|
|
||||||
**********
|
**********
|
||||||
References
|
References
|
||||||
**********
|
**********
|
||||||
|
|||||||
@@ -61,9 +61,9 @@ and then refer to the snapshot dependency by adding:
|
|||||||
<version>next_version_num-SNAPSHOT</version>
|
<version>next_version_num-SNAPSHOT</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
.. note:: XGBoost4J-Spark requires Apache Spark 2.3+
|
.. note:: XGBoost4J-Spark requires Apache Spark 2.4+
|
||||||
|
|
||||||
XGBoost4J-Spark now requires **Apache Spark 2.3+**. Latest versions of XGBoost4J-Spark uses facilities of `org.apache.spark.ml.param.shared` extensively to provide for a tight integration with Spark MLLIB framework, and these facilities are not fully available on earlier versions of Spark.
|
XGBoost4J-Spark now requires **Apache Spark 2.4+**. Latest versions of XGBoost4J-Spark uses facilities of `org.apache.spark.ml.param.shared` extensively to provide for a tight integration with Spark MLLIB framework, and these facilities are not fully available on earlier versions of Spark.
|
||||||
|
|
||||||
Also, make sure to install Spark directly from `Apache website <https://spark.apache.org/>`_. **Upstream XGBoost is not guaranteed to work with third-party distributions of Spark, such as Cloudera Spark.** Consult appropriate third parties to obtain their distribution of XGBoost.
|
Also, make sure to install Spark directly from `Apache website <https://spark.apache.org/>`_. **Upstream XGBoost is not guaranteed to work with third-party distributions of Spark, such as Cloudera Spark.** Consult appropriate third parties to obtain their distribution of XGBoost.
|
||||||
|
|
||||||
@@ -153,6 +153,49 @@ Now, we have a DataFrame containing only two columns, "features" which contains
|
|||||||
"sepal length", "sepal width", "petal length" and "petal width" and "classIndex" which has Double-typed
|
"sepal length", "sepal width", "petal length" and "petal width" and "classIndex" which has Double-typed
|
||||||
labels. A DataFrame like this (containing vector-represented features and numeric labels) can be fed to XGBoost4J-Spark's training engine directly.
|
labels. A DataFrame like this (containing vector-represented features and numeric labels) can be fed to XGBoost4J-Spark's training engine directly.
|
||||||
|
|
||||||
|
Dealing with missing values
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Strategies to handle missing values (and therefore overcome issues as above):
|
||||||
|
|
||||||
|
In the case that a feature column contains missing values for any reason (could be related to business logic / wrong data ingestion process / etc.), the user should decide on a strategy of how to handle it.
|
||||||
|
The choice of approach depends on the value representing 'missing' which fall into four different categories:
|
||||||
|
|
||||||
|
1. 0
|
||||||
|
2. NaN
|
||||||
|
3. Null
|
||||||
|
4. Any other value which is not mentioned in (1) / (2) / (3)
|
||||||
|
|
||||||
|
We introduce the following approaches dealing with missing value and their fitting scenarios:
|
||||||
|
|
||||||
|
1. Skip VectorAssembler (using setHandleInvalid = "skip") directly. Used in (2), (3).
|
||||||
|
2. Keep it (using setHandleInvalid = "keep"), and set the "missing" parameter in XGBClassifier/XGBRegressor as the value representing missing. Used in (2) and (4).
|
||||||
|
3. Keep it (using setHandleInvalid = "keep") and transform to other irregular values. Used in (3).
|
||||||
|
4. Nothing to be done, used in (1).
|
||||||
|
|
||||||
|
Then, XGBoost will automatically learn what's the ideal direction to go when a value is missing, based on that value and strategy.
|
||||||
|
|
||||||
|
Example of setting a missing value (e.g. -999) to the "missing" parameter in XGBoostClassifier:
|
||||||
|
|
||||||
|
.. code-block:: scala
|
||||||
|
|
||||||
|
import ml.dmlc.xgboost4j.scala.spark.XGBoostClassifier
|
||||||
|
val xgbParam = Map("eta" -> 0.1f,
|
||||||
|
"missing" -> -999,
|
||||||
|
"objective" -> "multi:softprob",
|
||||||
|
"num_class" -> 3,
|
||||||
|
"num_round" -> 100,
|
||||||
|
"num_workers" -> 2)
|
||||||
|
val xgbClassifier = new XGBoostClassifier(xgbParam).
|
||||||
|
setFeaturesCol("features").
|
||||||
|
setLabelCol("classIndex")
|
||||||
|
|
||||||
|
.. note:: Using 0 to represent meaningful value
|
||||||
|
|
||||||
|
Due to the fact that Spark's VectorAssembler transformer only accepts 0 as a missing values, this one creates a problem when the user has 0 as meaningful value plus there are enough 0's to use SparseVector (However, In case the dataset is represented by a DenseVector, the 0 is kept)
|
||||||
|
|
||||||
|
In this case, users are also supposed to transform 0 to some other values to avoid the issue.
|
||||||
|
|
||||||
Training
|
Training
|
||||||
========
|
========
|
||||||
|
|
||||||
@@ -196,7 +239,7 @@ Early Stopping
|
|||||||
|
|
||||||
Early stopping is a feature to prevent the unnecessary training iterations. By specifying ``num_early_stopping_rounds`` or directly call ``setNumEarlyStoppingRounds`` over a XGBoostClassifier or XGBoostRegressor, we can define number of rounds if the evaluation metric going away from the best iteration and early stop training iterations.
|
Early stopping is a feature to prevent the unnecessary training iterations. By specifying ``num_early_stopping_rounds`` or directly call ``setNumEarlyStoppingRounds`` over a XGBoostClassifier or XGBoostRegressor, we can define number of rounds if the evaluation metric going away from the best iteration and early stop training iterations.
|
||||||
|
|
||||||
In additional to ``num_early_stopping_rounds``, you also need to define ``maximize_evaluation_metrics`` or call ``setMaximizeEvaluationMetrics`` to specify whether you want to maximize or minimize the metrics in training.
|
When it comes to custom eval metrics, in additional to ``num_early_stopping_rounds``, you also need to define ``maximize_evaluation_metrics`` or call ``setMaximizeEvaluationMetrics`` to specify whether you want to maximize or minimize the metrics in training. For built-in eval metrics, XGBoost4J-Spark will automatically select the direction.
|
||||||
|
|
||||||
For example, we need to maximize the evaluation metrics (set ``maximize_evaluation_metrics`` with true), and set ``num_early_stopping_rounds`` with 5. The evaluation metric of 10th iteration is the maximum one until now. In the following iterations, if there is no evaluation metric greater than the 10th iteration's (best one), the traning would be early stopped at 15th iteration.
|
For example, we need to maximize the evaluation metrics (set ``maximize_evaluation_metrics`` with true), and set ``num_early_stopping_rounds`` with 5. The evaluation metric of 10th iteration is the maximum one until now. In the following iterations, if there is no evaluation metric greater than the 10th iteration's (best one), the traning would be early stopped at 15th iteration.
|
||||||
|
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ Parameters for Tree Booster
|
|||||||
subsampled from the set of columns chosen for the current level.
|
subsampled from the set of columns chosen for the current level.
|
||||||
- ``colsample_by*`` parameters work cumulatively. For instance,
|
- ``colsample_by*`` parameters work cumulatively. For instance,
|
||||||
the combination ``{'colsample_bytree':0.5, 'colsample_bylevel':0.5,
|
the combination ``{'colsample_bytree':0.5, 'colsample_bylevel':0.5,
|
||||||
'colsample_bynode':0.5}`` with 64 features will leave 4 features to choose from at
|
'colsample_bynode':0.5}`` with 64 features will leave 8 features to choose from at
|
||||||
each split.
|
each split.
|
||||||
|
|
||||||
* ``lambda`` [default=1, alias: ``reg_lambda``]
|
* ``lambda`` [default=1, alias: ``reg_lambda``]
|
||||||
@@ -193,8 +193,7 @@ Parameters for Tree Booster
|
|||||||
- ``gpu_predictor``: Prediction using GPU. Default when ``tree_method`` is ``gpu_exact`` or ``gpu_hist``.
|
- ``gpu_predictor``: Prediction using GPU. Default when ``tree_method`` is ``gpu_exact`` or ``gpu_hist``.
|
||||||
|
|
||||||
* ``num_parallel_tree``, [default=1]
|
* ``num_parallel_tree``, [default=1]
|
||||||
- Number of parallel trees constructed during each iteration. This
|
- Number of parallel trees constructed during each iteration. This option is used to support boosted random forest.
|
||||||
option is used to support boosted random forest
|
|
||||||
|
|
||||||
Additional parameters for Dart Booster (``booster=dart``)
|
Additional parameters for Dart Booster (``booster=dart``)
|
||||||
=========================================================
|
=========================================================
|
||||||
@@ -294,9 +293,9 @@ Learning Task Parameters
|
|||||||
************************
|
************************
|
||||||
Specify the learning task and the corresponding learning objective. The objective options are below:
|
Specify the learning task and the corresponding learning objective. The objective options are below:
|
||||||
|
|
||||||
* ``objective`` [default=reg:linear]
|
* ``objective`` [default=reg:squarederror]
|
||||||
|
|
||||||
- ``reg:linear``: linear regression
|
- ``reg:squarederror``: regression with squared loss
|
||||||
- ``reg:logistic``: logistic regression
|
- ``reg:logistic``: logistic regression
|
||||||
- ``binary:logistic``: logistic regression for binary classification, output probability
|
- ``binary:logistic``: logistic regression for binary classification, output probability
|
||||||
- ``binary:logitraw``: logistic regression for binary classification, output score before logistic transformation
|
- ``binary:logitraw``: logistic regression for binary classification, output score before logistic transformation
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ See `Awesome XGBoost <https://github.com/dmlc/xgboost/tree/master/demo>`_ for mo
|
|||||||
Distributed XGBoost with XGBoost4J-Spark <https://xgboost.readthedocs.io/en/latest/jvm/xgboost4j_spark_tutorial.html>
|
Distributed XGBoost with XGBoost4J-Spark <https://xgboost.readthedocs.io/en/latest/jvm/xgboost4j_spark_tutorial.html>
|
||||||
dart
|
dart
|
||||||
monotonic
|
monotonic
|
||||||
|
rf
|
||||||
feature_interaction_constraint
|
feature_interaction_constraint
|
||||||
input_format
|
input_format
|
||||||
param_tuning
|
param_tuning
|
||||||
|
|||||||
@@ -72,8 +72,7 @@ Decision Tree Ensembles
|
|||||||
***********************
|
***********************
|
||||||
Now that we have introduced the elements of supervised learning, let us get started with real trees.
|
Now that we have introduced the elements of supervised learning, let us get started with real trees.
|
||||||
To begin with, let us first learn about the model choice of XGBoost: **decision tree ensembles**.
|
To begin with, let us first learn about the model choice of XGBoost: **decision tree ensembles**.
|
||||||
The tree ensemble model consists of a set of classification and regression trees (CART). Here's a simple example of a CART
|
The tree ensemble model consists of a set of classification and regression trees (CART). Here's a simple example of a CART that classifies whether someone will like a hypothetical computer game X.
|
||||||
that classifies whether someone will like computer games.
|
|
||||||
|
|
||||||
.. image:: https://raw.githubusercontent.com/dmlc/web-data/master/xgboost/model/cart.png
|
.. image:: https://raw.githubusercontent.com/dmlc/web-data/master/xgboost/model/cart.png
|
||||||
:width: 100%
|
:width: 100%
|
||||||
@@ -82,7 +81,7 @@ that classifies whether someone will like computer games.
|
|||||||
We classify the members of a family into different leaves, and assign them the score on the corresponding leaf.
|
We classify the members of a family into different leaves, and assign them the score on the corresponding leaf.
|
||||||
A CART is a bit different from decision trees, in which the leaf only contains decision values. In CART, a real score
|
A CART is a bit different from decision trees, in which the leaf only contains decision values. In CART, a real score
|
||||||
is associated with each of the leaves, which gives us richer interpretations that go beyond classification.
|
is associated with each of the leaves, which gives us richer interpretations that go beyond classification.
|
||||||
This also allows for a pricipled, unified approach to optimization, as we will see in a later part of this tutorial.
|
This also allows for a principled, unified approach to optimization, as we will see in a later part of this tutorial.
|
||||||
|
|
||||||
Usually, a single tree is not strong enough to be used in practice. What is actually used is the ensemble model,
|
Usually, a single tree is not strong enough to be used in practice. What is actually used is the ensemble model,
|
||||||
which sums the prediction of multiple trees together.
|
which sums the prediction of multiple trees together.
|
||||||
@@ -255,6 +254,10 @@ For real valued data, we usually want to search for an optimal split. To efficie
|
|||||||
|
|
||||||
A left to right scan is sufficient to calculate the structure score of all possible split solutions, and we can find the best split efficiently.
|
A left to right scan is sufficient to calculate the structure score of all possible split solutions, and we can find the best split efficiently.
|
||||||
|
|
||||||
|
.. note:: Limitation of additive tree learning
|
||||||
|
|
||||||
|
Since it is intractable to enumerate all possible tree structures, we add one split at a time. This approach works well most of the time, but there are some edge cases that fail due to this approach. For those edge cases, training results in a degenerate model because we consider only one feature dimension at a time. See `Can Gradient Boosting Learn Simple Arithmetic? <http://mariofilho.com/can-gradient-boosting-learn-simple-arithmetic/>`_ for an example.
|
||||||
|
|
||||||
**********************
|
**********************
|
||||||
Final words on XGBoost
|
Final words on XGBoost
|
||||||
**********************
|
**********************
|
||||||
|
|||||||
106
doc/tutorials/rf.rst
Normal file
106
doc/tutorials/rf.rst
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
#########################
|
||||||
|
Random Forests in XGBoost
|
||||||
|
#########################
|
||||||
|
|
||||||
|
XGBoost is normally used to train gradient-boosted decision trees and other gradient
|
||||||
|
boosted models. Random forests use the same model representation and inference, as
|
||||||
|
gradient-boosted decision trees, but a different training algorithm. One can use XGBoost
|
||||||
|
to train a standalone random forest or use random forest as a base model for gradient
|
||||||
|
boosting. Here we focus on training standalone random forest.
|
||||||
|
|
||||||
|
We have native APIs for training random forests since the early days, and a new
|
||||||
|
Scikit-Learn wrapper after 0.82 (not included in 0.82). Please note that the new
|
||||||
|
Scikit-Learn wrapper is still **experimental**, which means we might change the interface
|
||||||
|
whenever needed.
|
||||||
|
|
||||||
|
****************
|
||||||
|
Standalone Random Forest With XGBoost API
|
||||||
|
****************
|
||||||
|
|
||||||
|
The following parameters must be set to enable random forest training.
|
||||||
|
|
||||||
|
* ``booster`` should be set to ``gbtree``, as we are training forests. Note that as this
|
||||||
|
is the default, this parameter needn't be set explicitly.
|
||||||
|
* ``subsample`` must be set to a value less than 1 to enable random selection of training
|
||||||
|
cases (rows).
|
||||||
|
* One of ``colsample_by*`` parameters must be set to a value less than 1 to enable random
|
||||||
|
selection of columns. Normally, ``colsample_bynode`` would be set to a value less than 1
|
||||||
|
to randomly sample columns at each tree split.
|
||||||
|
* ``num_parallel_tree`` should be set to the size of the forest being trained.
|
||||||
|
* ``num_boost_round`` should be set to 1 to prevent XGBoost from boosting multiple random
|
||||||
|
forests. Note that this is a keyword argument to ``train()``, and is not part of the
|
||||||
|
parameter dictionary.
|
||||||
|
* ``eta`` (alias: ``learning_rate``) must be set to 1 when training random forest
|
||||||
|
regression.
|
||||||
|
* ``random_state`` can be used to seed the random number generator.
|
||||||
|
|
||||||
|
|
||||||
|
Other parameters should be set in a similar way they are set for gradient boosting. For
|
||||||
|
instance, ``objective`` will typically be ``reg:squarederror`` for regression and
|
||||||
|
``binary:logistic`` for classification, ``lambda`` should be set according to a desired
|
||||||
|
regularization weight, etc.
|
||||||
|
|
||||||
|
If both ``num_parallel_tree`` and ``num_boost_round`` are greater than 1, training will
|
||||||
|
use a combination of random forest and gradient boosting strategy. It will perform
|
||||||
|
``num_boost_round`` rounds, boosting a random forest of ``num_parallel_tree`` trees at
|
||||||
|
each round. If early stopping is not enabled, the final model will consist of
|
||||||
|
``num_parallel_tree`` * ``num_boost_round`` trees.
|
||||||
|
|
||||||
|
Here is a sample parameter dictionary for training a random forest on a GPU using
|
||||||
|
xgboost::
|
||||||
|
|
||||||
|
params = {
|
||||||
|
'colsample_bynode': 0.8,
|
||||||
|
'learning_rate': 1,
|
||||||
|
'max_depth': 5,
|
||||||
|
'num_parallel_tree': 100,
|
||||||
|
'objective': 'binary:logistic',
|
||||||
|
'subsample': 0.8,
|
||||||
|
'tree_method': 'gpu_hist'
|
||||||
|
}
|
||||||
|
|
||||||
|
A random forest model can then be trained as follows::
|
||||||
|
|
||||||
|
bst = train(params, dmatrix, num_boost_round=1)
|
||||||
|
|
||||||
|
|
||||||
|
**************************
|
||||||
|
Standalone Random Forest With Scikit-Learn-Like API
|
||||||
|
**************************
|
||||||
|
|
||||||
|
``XGBRFClassifier`` and ``XGBRFRegressor`` are SKL-like classes that provide random forest
|
||||||
|
functionality. They are basically versions of ``XGBClassifier`` and ``XGBRegressor`` that
|
||||||
|
train random forest instead of gradient boosting, and have default values and meaning of
|
||||||
|
some of the parameters adjusted accordingly. In particular:
|
||||||
|
|
||||||
|
* ``n_estimators`` specifies the size of the forest to be trained; it is converted to
|
||||||
|
``num_parallel_tree``, instead of the number of boosting rounds
|
||||||
|
* ``learning_rate`` is set to 1 by default
|
||||||
|
* ``colsample_bynode`` and ``subsample`` are set to 0.8 by default
|
||||||
|
* ``booster`` is always ``gbtree``
|
||||||
|
|
||||||
|
For a simple example, you can train a random forest regressor with::
|
||||||
|
|
||||||
|
from sklearn.model_selection import KFold
|
||||||
|
|
||||||
|
# Your code ...
|
||||||
|
|
||||||
|
kf = KFold(n_splits=2)
|
||||||
|
for train_index, test_index in kf.split(X, y):
|
||||||
|
xgb_model = xgb.XGBRFRegressor(random_state=42).fit(
|
||||||
|
X[train_index], y[train_index])
|
||||||
|
|
||||||
|
Note that these classes have a smaller selection of parameters compared to using
|
||||||
|
``train()``. In particular, it is impossible to combine random forests with gradient
|
||||||
|
boosting using this API.
|
||||||
|
|
||||||
|
|
||||||
|
*******
|
||||||
|
Caveats
|
||||||
|
*******
|
||||||
|
|
||||||
|
* XGBoost uses 2nd order approximation to the objective function. This can lead to results
|
||||||
|
that differ from a random forest implementation that uses the exact value of the
|
||||||
|
objective function.
|
||||||
|
* XGBoost does not perform replacement when subsampling training cases. Each training case
|
||||||
|
can occur in a subsampled set either 0 or 1 time.
|
||||||
@@ -5,6 +5,8 @@
|
|||||||
#ifndef XGBOOST_BUILD_CONFIG_H_
|
#ifndef XGBOOST_BUILD_CONFIG_H_
|
||||||
#define XGBOOST_BUILD_CONFIG_H_
|
#define XGBOOST_BUILD_CONFIG_H_
|
||||||
|
|
||||||
|
// These check are for Makefile.
|
||||||
|
#if !defined(XGBOOST_MM_PREFETCH_PRESENT) && !defined(XGBOOST_BUILTIN_PREFETCH_PRESENT)
|
||||||
/* default logic for software pre-fetching */
|
/* default logic for software pre-fetching */
|
||||||
#if (defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_AMD64))) || defined(__INTEL_COMPILER)
|
#if (defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_AMD64))) || defined(__INTEL_COMPILER)
|
||||||
// Enable _mm_prefetch for Intel compiler and MSVC+x86
|
// Enable _mm_prefetch for Intel compiler and MSVC+x86
|
||||||
@@ -15,4 +17,6 @@
|
|||||||
#define XGBOOST_BUILTIN_PREFETCH_PRESENT
|
#define XGBOOST_BUILTIN_PREFETCH_PRESENT
|
||||||
#endif // GUARDS
|
#endif // GUARDS
|
||||||
|
|
||||||
|
#endif // !defined(XGBOOST_MM_PREFETCH_PRESENT) && !defined()
|
||||||
|
|
||||||
#endif // XGBOOST_BUILD_CONFIG_H_
|
#endif // XGBOOST_BUILD_CONFIG_H_
|
||||||
|
|||||||
@@ -17,9 +17,6 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#endif // __cplusplus
|
#endif // __cplusplus
|
||||||
|
|
||||||
// XGBoost C API will include APIs in Rabit C API
|
|
||||||
#include <rabit/c_api.h>
|
|
||||||
|
|
||||||
#if defined(_MSC_VER) || defined(_WIN32)
|
#if defined(_MSC_VER) || defined(_WIN32)
|
||||||
#define XGB_DLL XGB_EXTERN_C __declspec(dllexport)
|
#define XGB_DLL XGB_EXTERN_C __declspec(dllexport)
|
||||||
#else
|
#else
|
||||||
@@ -149,23 +146,6 @@ XGB_DLL int XGDMatrixCreateFromCSREx(const size_t* indptr,
|
|||||||
size_t nelem,
|
size_t nelem,
|
||||||
size_t num_col,
|
size_t num_col,
|
||||||
DMatrixHandle* out);
|
DMatrixHandle* out);
|
||||||
/*!
|
|
||||||
* \deprecated
|
|
||||||
* \brief create a matrix content from CSR format
|
|
||||||
* \param indptr pointer to row headers
|
|
||||||
* \param indices findex
|
|
||||||
* \param data fvalue
|
|
||||||
* \param nindptr number of rows in the matrix + 1
|
|
||||||
* \param nelem number of nonzero elements in the matrix
|
|
||||||
* \param out created dmatrix
|
|
||||||
* \return 0 when success, -1 when failure happens
|
|
||||||
*/
|
|
||||||
XGB_DLL int XGDMatrixCreateFromCSR(const bst_ulong *indptr,
|
|
||||||
const unsigned *indices,
|
|
||||||
const float *data,
|
|
||||||
bst_ulong nindptr,
|
|
||||||
bst_ulong nelem,
|
|
||||||
DMatrixHandle *out);
|
|
||||||
/*!
|
/*!
|
||||||
* \brief create a matrix content from CSC format
|
* \brief create a matrix content from CSC format
|
||||||
* \param col_ptr pointer to col headers
|
* \param col_ptr pointer to col headers
|
||||||
@@ -184,23 +164,7 @@ XGB_DLL int XGDMatrixCreateFromCSCEx(const size_t* col_ptr,
|
|||||||
size_t nelem,
|
size_t nelem,
|
||||||
size_t num_row,
|
size_t num_row,
|
||||||
DMatrixHandle* out);
|
DMatrixHandle* out);
|
||||||
/*!
|
|
||||||
* \deprecated
|
|
||||||
* \brief create a matrix content from CSC format
|
|
||||||
* \param col_ptr pointer to col headers
|
|
||||||
* \param indices findex
|
|
||||||
* \param data fvalue
|
|
||||||
* \param nindptr number of rows in the matrix + 1
|
|
||||||
* \param nelem number of nonzero elements in the matrix
|
|
||||||
* \param out created dmatrix
|
|
||||||
* \return 0 when success, -1 when failure happens
|
|
||||||
*/
|
|
||||||
XGB_DLL int XGDMatrixCreateFromCSC(const bst_ulong *col_ptr,
|
|
||||||
const unsigned *indices,
|
|
||||||
const float *data,
|
|
||||||
bst_ulong nindptr,
|
|
||||||
bst_ulong nelem,
|
|
||||||
DMatrixHandle *out);
|
|
||||||
/*!
|
/*!
|
||||||
* \brief create matrix content from dense matrix
|
* \brief create matrix content from dense matrix
|
||||||
* \param data pointer to the data space
|
* \param data pointer to the data space
|
||||||
|
|||||||
@@ -284,6 +284,7 @@ class BatchIteratorImpl {
|
|||||||
public:
|
public:
|
||||||
virtual ~BatchIteratorImpl() {}
|
virtual ~BatchIteratorImpl() {}
|
||||||
virtual BatchIteratorImpl* Clone() = 0;
|
virtual BatchIteratorImpl* Clone() = 0;
|
||||||
|
virtual SparsePage& operator*() = 0;
|
||||||
virtual const SparsePage& operator*() const = 0;
|
virtual const SparsePage& operator*() const = 0;
|
||||||
virtual void operator++() = 0;
|
virtual void operator++() = 0;
|
||||||
virtual bool AtEnd() const = 0;
|
virtual bool AtEnd() const = 0;
|
||||||
@@ -307,6 +308,11 @@ class BatchIterator {
|
|||||||
++(*impl_);
|
++(*impl_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SparsePage& operator*() {
|
||||||
|
CHECK(impl_ != nullptr);
|
||||||
|
return *(*impl_);
|
||||||
|
}
|
||||||
|
|
||||||
const SparsePage& operator*() const {
|
const SparsePage& operator*() const {
|
||||||
CHECK(impl_ != nullptr);
|
CHECK(impl_ != nullptr);
|
||||||
return *(*impl_);
|
return *(*impl_);
|
||||||
@@ -433,12 +439,14 @@ class DMatrix {
|
|||||||
* \param load_row_split Flag to read in part of rows, divided among the workers in distributed mode.
|
* \param load_row_split Flag to read in part of rows, divided among the workers in distributed mode.
|
||||||
* \param file_format The format type of the file, used for dmlc::Parser::Create.
|
* \param file_format The format type of the file, used for dmlc::Parser::Create.
|
||||||
* By default "auto" will be able to load in both local binary file.
|
* By default "auto" will be able to load in both local binary file.
|
||||||
|
* \param page_size Page size for external memory.
|
||||||
* \return The created DMatrix.
|
* \return The created DMatrix.
|
||||||
*/
|
*/
|
||||||
static DMatrix* Load(const std::string& uri,
|
static DMatrix* Load(const std::string& uri,
|
||||||
bool silent,
|
bool silent,
|
||||||
bool load_row_split,
|
bool load_row_split,
|
||||||
const std::string& file_format = "auto");
|
const std::string& file_format = "auto",
|
||||||
|
const size_t page_size = kPageSize);
|
||||||
/*!
|
/*!
|
||||||
* \brief create a new DMatrix, by wrapping a row_iterator, and meta info.
|
* \brief create a new DMatrix, by wrapping a row_iterator, and meta info.
|
||||||
* \param source The source iterator of the data, the create function takes ownership of the source.
|
* \param source The source iterator of the data, the create function takes ownership of the source.
|
||||||
@@ -454,6 +462,7 @@ class DMatrix {
|
|||||||
* \param parser The input data parser
|
* \param parser The input data parser
|
||||||
* \param cache_prefix The path to prefix of temporary cache file of the DMatrix when used in external memory mode.
|
* \param cache_prefix The path to prefix of temporary cache file of the DMatrix when used in external memory mode.
|
||||||
* This can be nullptr for common cases, and in-memory mode will be used.
|
* This can be nullptr for common cases, and in-memory mode will be used.
|
||||||
|
* \param page_size Page size for external memory.
|
||||||
* \sa dmlc::Parser
|
* \sa dmlc::Parser
|
||||||
* \note dmlc-core provides efficient distributed data parser for libsvm format.
|
* \note dmlc-core provides efficient distributed data parser for libsvm format.
|
||||||
* User can create and register customized parser to load their own format using DMLC_REGISTER_DATA_PARSER.
|
* User can create and register customized parser to load their own format using DMLC_REGISTER_DATA_PARSER.
|
||||||
@@ -461,7 +470,11 @@ class DMatrix {
|
|||||||
* \return A created DMatrix.
|
* \return A created DMatrix.
|
||||||
*/
|
*/
|
||||||
static DMatrix* Create(dmlc::Parser<uint32_t>* parser,
|
static DMatrix* Create(dmlc::Parser<uint32_t>* parser,
|
||||||
const std::string& cache_prefix = "");
|
const std::string& cache_prefix = "",
|
||||||
|
const size_t page_size = kPageSize);
|
||||||
|
|
||||||
|
/*! \brief page size 32 MB */
|
||||||
|
static const size_t kPageSize = 32UL << 20UL;
|
||||||
};
|
};
|
||||||
|
|
||||||
// implementation of inline functions
|
// implementation of inline functions
|
||||||
|
|||||||
@@ -62,6 +62,13 @@ struct TreeParam : public dmlc::Parameter<TreeParam> {
|
|||||||
DMLC_DECLARE_FIELD(size_leaf_vector).set_lower_bound(0).set_default(0)
|
DMLC_DECLARE_FIELD(size_leaf_vector).set_lower_bound(0).set_default(0)
|
||||||
.describe("Size of leaf vector, reserved for vector tree");
|
.describe("Size of leaf vector, reserved for vector tree");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool operator==(const TreeParam& b) const {
|
||||||
|
return num_roots == b.num_roots && num_nodes == b.num_nodes &&
|
||||||
|
num_deleted == b.num_deleted && max_depth == b.max_depth &&
|
||||||
|
num_feature == b.num_feature &&
|
||||||
|
size_leaf_vector == b.size_leaf_vector;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/*! \brief node statistics used in regression tree */
|
/*! \brief node statistics used in regression tree */
|
||||||
@@ -74,6 +81,10 @@ struct RTreeNodeStat {
|
|||||||
bst_float base_weight;
|
bst_float base_weight;
|
||||||
/*! \brief number of child that is leaf node known up to now */
|
/*! \brief number of child that is leaf node known up to now */
|
||||||
int leaf_child_cnt;
|
int leaf_child_cnt;
|
||||||
|
bool operator==(const RTreeNodeStat& b) const {
|
||||||
|
return loss_chg == b.loss_chg && sum_hess == b.sum_hess &&
|
||||||
|
base_weight == b.base_weight && leaf_child_cnt == b.leaf_child_cnt;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -93,65 +104,63 @@ class RegTree {
|
|||||||
"Node: 64 bit align");
|
"Node: 64 bit align");
|
||||||
}
|
}
|
||||||
/*! \brief index of left child */
|
/*! \brief index of left child */
|
||||||
int LeftChild() const {
|
XGBOOST_DEVICE int LeftChild() const {
|
||||||
return this->cleft_;
|
return this->cleft_;
|
||||||
}
|
}
|
||||||
/*! \brief index of right child */
|
/*! \brief index of right child */
|
||||||
int RightChild() const {
|
XGBOOST_DEVICE int RightChild() const {
|
||||||
return this->cright_;
|
return this->cright_;
|
||||||
}
|
}
|
||||||
/*! \brief index of default child when feature is missing */
|
/*! \brief index of default child when feature is missing */
|
||||||
int DefaultChild() const {
|
XGBOOST_DEVICE int DefaultChild() const {
|
||||||
return this->DefaultLeft() ? this->LeftChild() : this->RightChild();
|
return this->DefaultLeft() ? this->LeftChild() : this->RightChild();
|
||||||
}
|
}
|
||||||
/*! \brief feature index of split condition */
|
/*! \brief feature index of split condition */
|
||||||
unsigned SplitIndex() const {
|
XGBOOST_DEVICE unsigned SplitIndex() const {
|
||||||
return sindex_ & ((1U << 31) - 1U);
|
return sindex_ & ((1U << 31) - 1U);
|
||||||
}
|
}
|
||||||
/*! \brief when feature is unknown, whether goes to left child */
|
/*! \brief when feature is unknown, whether goes to left child */
|
||||||
bool DefaultLeft() const {
|
XGBOOST_DEVICE bool DefaultLeft() const {
|
||||||
return (sindex_ >> 31) != 0;
|
return (sindex_ >> 31) != 0;
|
||||||
}
|
}
|
||||||
/*! \brief whether current node is leaf node */
|
/*! \brief whether current node is leaf node */
|
||||||
bool IsLeaf() const {
|
XGBOOST_DEVICE bool IsLeaf() const {
|
||||||
return cleft_ == -1;
|
return cleft_ == -1;
|
||||||
}
|
}
|
||||||
/*! \return get leaf value of leaf node */
|
/*! \return get leaf value of leaf node */
|
||||||
bst_float LeafValue() const {
|
XGBOOST_DEVICE bst_float LeafValue() const {
|
||||||
return (this->info_).leaf_value;
|
return (this->info_).leaf_value;
|
||||||
}
|
}
|
||||||
/*! \return get split condition of the node */
|
/*! \return get split condition of the node */
|
||||||
SplitCondT SplitCond() const {
|
XGBOOST_DEVICE SplitCondT SplitCond() const {
|
||||||
return (this->info_).split_cond;
|
return (this->info_).split_cond;
|
||||||
}
|
}
|
||||||
/*! \brief get parent of the node */
|
/*! \brief get parent of the node */
|
||||||
int Parent() const {
|
XGBOOST_DEVICE int Parent() const {
|
||||||
return parent_ & ((1U << 31) - 1);
|
return parent_ & ((1U << 31) - 1);
|
||||||
}
|
}
|
||||||
/*! \brief whether current node is left child */
|
/*! \brief whether current node is left child */
|
||||||
bool IsLeftChild() const {
|
XGBOOST_DEVICE bool IsLeftChild() const {
|
||||||
return (parent_ & (1U << 31)) != 0;
|
return (parent_ & (1U << 31)) != 0;
|
||||||
}
|
}
|
||||||
/*! \brief whether this node is deleted */
|
/*! \brief whether this node is deleted */
|
||||||
bool IsDeleted() const {
|
XGBOOST_DEVICE bool IsDeleted() const {
|
||||||
return sindex_ == std::numeric_limits<unsigned>::max();
|
return sindex_ == std::numeric_limits<unsigned>::max();
|
||||||
}
|
}
|
||||||
/*! \brief whether current node is root */
|
/*! \brief whether current node is root */
|
||||||
bool IsRoot() const {
|
XGBOOST_DEVICE bool IsRoot() const { return parent_ == -1; }
|
||||||
return parent_ == -1;
|
|
||||||
}
|
|
||||||
/*!
|
/*!
|
||||||
* \brief set the left child
|
* \brief set the left child
|
||||||
* \param nid node id to right child
|
* \param nid node id to right child
|
||||||
*/
|
*/
|
||||||
void SetLeftChild(int nid) {
|
XGBOOST_DEVICE void SetLeftChild(int nid) {
|
||||||
this->cleft_ = nid;
|
this->cleft_ = nid;
|
||||||
}
|
}
|
||||||
/*!
|
/*!
|
||||||
* \brief set the right child
|
* \brief set the right child
|
||||||
* \param nid node id to right child
|
* \param nid node id to right child
|
||||||
*/
|
*/
|
||||||
void SetRightChild(int nid) {
|
XGBOOST_DEVICE void SetRightChild(int nid) {
|
||||||
this->cright_ = nid;
|
this->cright_ = nid;
|
||||||
}
|
}
|
||||||
/*!
|
/*!
|
||||||
@@ -160,7 +169,7 @@ class RegTree {
|
|||||||
* \param split_cond split condition
|
* \param split_cond split condition
|
||||||
* \param default_left the default direction when feature is unknown
|
* \param default_left the default direction when feature is unknown
|
||||||
*/
|
*/
|
||||||
void SetSplit(unsigned split_index, SplitCondT split_cond,
|
XGBOOST_DEVICE void SetSplit(unsigned split_index, SplitCondT split_cond,
|
||||||
bool default_left = false) {
|
bool default_left = false) {
|
||||||
if (default_left) split_index |= (1U << 31);
|
if (default_left) split_index |= (1U << 31);
|
||||||
this->sindex_ = split_index;
|
this->sindex_ = split_index;
|
||||||
@@ -172,20 +181,29 @@ class RegTree {
|
|||||||
* \param right right index, could be used to store
|
* \param right right index, could be used to store
|
||||||
* additional information
|
* additional information
|
||||||
*/
|
*/
|
||||||
void SetLeaf(bst_float value, int right = -1) {
|
XGBOOST_DEVICE void SetLeaf(bst_float value, int right = -1) {
|
||||||
(this->info_).leaf_value = value;
|
(this->info_).leaf_value = value;
|
||||||
this->cleft_ = -1;
|
this->cleft_ = -1;
|
||||||
this->cright_ = right;
|
this->cright_ = right;
|
||||||
}
|
}
|
||||||
/*! \brief mark that this node is deleted */
|
/*! \brief mark that this node is deleted */
|
||||||
void MarkDelete() {
|
XGBOOST_DEVICE void MarkDelete() {
|
||||||
this->sindex_ = std::numeric_limits<unsigned>::max();
|
this->sindex_ = std::numeric_limits<unsigned>::max();
|
||||||
}
|
}
|
||||||
|
/*! \brief Reuse this deleted node. */
|
||||||
|
XGBOOST_DEVICE void Reuse() {
|
||||||
|
this->sindex_ = 0;
|
||||||
|
}
|
||||||
// set parent
|
// set parent
|
||||||
void SetParent(int pidx, bool is_left_child = true) {
|
XGBOOST_DEVICE void SetParent(int pidx, bool is_left_child = true) {
|
||||||
if (is_left_child) pidx |= (1U << 31);
|
if (is_left_child) pidx |= (1U << 31);
|
||||||
this->parent_ = pidx;
|
this->parent_ = pidx;
|
||||||
}
|
}
|
||||||
|
bool operator==(const Node& b) const {
|
||||||
|
return parent_ == b.parent_ && cleft_ == b.cleft_ &&
|
||||||
|
cright_ == b.cright_ && sindex_ == b.sindex_ &&
|
||||||
|
info_.leaf_value == b.info_.leaf_value;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/*!
|
/*!
|
||||||
@@ -302,6 +320,11 @@ class RegTree {
|
|||||||
fo->Write(dmlc::BeginPtr(stats_), sizeof(RTreeNodeStat) * nodes_.size());
|
fo->Write(dmlc::BeginPtr(stats_), sizeof(RTreeNodeStat) * nodes_.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool operator==(const RegTree& b) const {
|
||||||
|
return nodes_ == b.nodes_ && stats_ == b.stats_ &&
|
||||||
|
deleted_nodes_ == b.deleted_nodes_ && param == b.param;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Expands a leaf node into two additional leaf nodes.
|
* \brief Expands a leaf node into two additional leaf nodes.
|
||||||
*
|
*
|
||||||
@@ -505,10 +528,11 @@ class RegTree {
|
|||||||
// !!!!!! NOTE: may cause BUG here, nodes.resize
|
// !!!!!! NOTE: may cause BUG here, nodes.resize
|
||||||
int AllocNode() {
|
int AllocNode() {
|
||||||
if (param.num_deleted != 0) {
|
if (param.num_deleted != 0) {
|
||||||
int nd = deleted_nodes_.back();
|
int nid = deleted_nodes_.back();
|
||||||
deleted_nodes_.pop_back();
|
deleted_nodes_.pop_back();
|
||||||
|
nodes_[nid].Reuse();
|
||||||
--param.num_deleted;
|
--param.num_deleted;
|
||||||
return nd;
|
return nid;
|
||||||
}
|
}
|
||||||
int nd = param.num_nodes++;
|
int nd = param.num_nodes++;
|
||||||
CHECK_LT(param.num_nodes, std::numeric_limits<int>::max())
|
CHECK_LT(param.num_nodes, std::numeric_limits<int>::max())
|
||||||
|
|||||||
22
jvm-packages/CMakeLists.txt
Normal file
22
jvm-packages/CMakeLists.txt
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
find_package(JNI REQUIRED)
|
||||||
|
|
||||||
|
add_library(xgboost4j SHARED
|
||||||
|
${PROJECT_SOURCE_DIR}/jvm-packages/xgboost4j/src/native/xgboost4j.cpp
|
||||||
|
${XGBOOST_OBJ_SOURCES})
|
||||||
|
target_include_directories(xgboost4j
|
||||||
|
PRIVATE
|
||||||
|
${JNI_INCLUDE_DIRS}
|
||||||
|
${PROJECT_SOURCE_DIR}/jvm-packages/xgboost4j/src/native
|
||||||
|
${PROJECT_SOURCE_DIR}/include
|
||||||
|
${PROJECT_SOURCE_DIR}/dmlc-core/include
|
||||||
|
${PROJECT_SOURCE_DIR}/rabit/include)
|
||||||
|
|
||||||
|
set_output_directory(xgboost4j ${PROJECT_SOURCE_DIR}/lib)
|
||||||
|
set_target_properties(
|
||||||
|
xgboost4j PROPERTIES
|
||||||
|
CXX_STANDARD 11
|
||||||
|
CXX_STANDARD_REQUIRED ON)
|
||||||
|
target_link_libraries(xgboost4j
|
||||||
|
PRIVATE
|
||||||
|
${LINKED_LIBRARIES_PRIVATE}
|
||||||
|
${JAVA_JVM_LIBRARY})
|
||||||
@@ -83,10 +83,14 @@ if __name__ == "__main__":
|
|||||||
maybe_generator = ' -G"Visual Studio 14 Win64"'
|
maybe_generator = ' -G"Visual Studio 14 Win64"'
|
||||||
else:
|
else:
|
||||||
maybe_generator = ""
|
maybe_generator = ""
|
||||||
|
if sys.platform == "linux":
|
||||||
|
maybe_parallel_build = " -- -j $(nproc)"
|
||||||
|
else:
|
||||||
|
maybe_parallel_build = ""
|
||||||
|
|
||||||
args = ["-D{0}:BOOL={1}".format(k, v) for k, v in CONFIG.items()]
|
args = ["-D{0}:BOOL={1}".format(k, v) for k, v in CONFIG.items()]
|
||||||
run("cmake .. " + " ".join(args) + maybe_generator)
|
run("cmake .. " + " ".join(args) + maybe_generator)
|
||||||
run("cmake --build . --config Release")
|
run("cmake --build . --config Release" + maybe_parallel_build)
|
||||||
|
|
||||||
with cd("demo/regression"):
|
with cd("demo/regression"):
|
||||||
run(sys.executable + " mapfeat.py")
|
run(sys.executable + " mapfeat.py")
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
<groupId>ml.dmlc</groupId>
|
<groupId>ml.dmlc</groupId>
|
||||||
<artifactId>xgboost-jvm</artifactId>
|
<artifactId>xgboost-jvm</artifactId>
|
||||||
<version>0.82-SNAPSHOT</version>
|
<version>0.90</version>
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
<name>XGBoost JVM Package</name>
|
<name>XGBoost JVM Package</name>
|
||||||
<description>JVM Package for XGBoost</description>
|
<description>JVM Package for XGBoost</description>
|
||||||
@@ -34,7 +34,7 @@
|
|||||||
<maven.compiler.source>1.7</maven.compiler.source>
|
<maven.compiler.source>1.7</maven.compiler.source>
|
||||||
<maven.compiler.target>1.7</maven.compiler.target>
|
<maven.compiler.target>1.7</maven.compiler.target>
|
||||||
<flink.version>1.5.0</flink.version>
|
<flink.version>1.5.0</flink.version>
|
||||||
<spark.version>2.3.3</spark.version>
|
<spark.version>2.4.3</spark.version>
|
||||||
<scala.version>2.11.12</scala.version>
|
<scala.version>2.11.12</scala.version>
|
||||||
<scala.binary.version>2.11</scala.binary.version>
|
<scala.binary.version>2.11</scala.binary.version>
|
||||||
</properties>
|
</properties>
|
||||||
@@ -212,6 +212,12 @@
|
|||||||
</snapshotRepository>
|
</snapshotRepository>
|
||||||
</distributionManagement>
|
</distributionManagement>
|
||||||
<build>
|
<build>
|
||||||
|
<resources>
|
||||||
|
<resource>
|
||||||
|
<directory>src/main/resources</directory>
|
||||||
|
<filtering>true</filtering>
|
||||||
|
</resource>
|
||||||
|
</resources>
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.scalastyle</groupId>
|
<groupId>org.scalastyle</groupId>
|
||||||
|
|||||||
@@ -6,10 +6,10 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>ml.dmlc</groupId>
|
<groupId>ml.dmlc</groupId>
|
||||||
<artifactId>xgboost-jvm</artifactId>
|
<artifactId>xgboost-jvm</artifactId>
|
||||||
<version>0.82-SNAPSHOT</version>
|
<version>0.90</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>xgboost4j-example</artifactId>
|
<artifactId>xgboost4j-example</artifactId>
|
||||||
<version>0.82-SNAPSHOT</version>
|
<version>0.90</version>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>ml.dmlc</groupId>
|
<groupId>ml.dmlc</groupId>
|
||||||
<artifactId>xgboost4j-spark</artifactId>
|
<artifactId>xgboost4j-spark</artifactId>
|
||||||
<version>0.82-SNAPSHOT</version>
|
<version>0.90</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.spark</groupId>
|
<groupId>org.apache.spark</groupId>
|
||||||
@@ -37,7 +37,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>ml.dmlc</groupId>
|
<groupId>ml.dmlc</groupId>
|
||||||
<artifactId>xgboost4j-flink</artifactId>
|
<artifactId>xgboost4j-flink</artifactId>
|
||||||
<version>0.82-SNAPSHOT</version>
|
<version>0.90</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.commons</groupId>
|
<groupId>org.apache.commons</groupId>
|
||||||
|
|||||||
@@ -32,8 +32,8 @@ public class ExternalMemory {
|
|||||||
//this is the only difference, add a # followed by a cache prefix name
|
//this is the only difference, add a # followed by a cache prefix name
|
||||||
//several cache file with the prefix will be generated
|
//several cache file with the prefix will be generated
|
||||||
//currently only support convert from libsvm file
|
//currently only support convert from libsvm file
|
||||||
DMatrix trainMat = new DMatrix("../demo/data/agaricus.txt.train#dtrain.cache");
|
DMatrix trainMat = new DMatrix("../../demo/data/agaricus.txt.train#dtrain.cache");
|
||||||
DMatrix testMat = new DMatrix("../demo/data/agaricus.txt.test#dtest.cache");
|
DMatrix testMat = new DMatrix("../../demo/data/agaricus.txt.test#dtest.cache");
|
||||||
|
|
||||||
//specify parameters
|
//specify parameters
|
||||||
HashMap<String, Object> params = new HashMap<String, Object>();
|
HashMap<String, Object> params = new HashMap<String, Object>();
|
||||||
|
|||||||
@@ -6,10 +6,10 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>ml.dmlc</groupId>
|
<groupId>ml.dmlc</groupId>
|
||||||
<artifactId>xgboost-jvm</artifactId>
|
<artifactId>xgboost-jvm</artifactId>
|
||||||
<version>0.82-SNAPSHOT</version>
|
<version>0.90</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>xgboost4j-flink</artifactId>
|
<artifactId>xgboost4j-flink</artifactId>
|
||||||
<version>0.82-SNAPSHOT</version>
|
<version>0.90</version>
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>ml.dmlc</groupId>
|
<groupId>ml.dmlc</groupId>
|
||||||
<artifactId>xgboost4j</artifactId>
|
<artifactId>xgboost4j</artifactId>
|
||||||
<version>0.82-SNAPSHOT</version>
|
<version>0.90</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.commons</groupId>
|
<groupId>org.apache.commons</groupId>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>ml.dmlc</groupId>
|
<groupId>ml.dmlc</groupId>
|
||||||
<artifactId>xgboost-jvm</artifactId>
|
<artifactId>xgboost-jvm</artifactId>
|
||||||
<version>0.82-SNAPSHOT</version>
|
<version>0.90</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>xgboost4j-spark</artifactId>
|
<artifactId>xgboost4j-spark</artifactId>
|
||||||
<build>
|
<build>
|
||||||
@@ -24,7 +24,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>ml.dmlc</groupId>
|
<groupId>ml.dmlc</groupId>
|
||||||
<artifactId>xgboost4j</artifactId>
|
<artifactId>xgboost4j</artifactId>
|
||||||
<version>0.82-SNAPSHOT</version>
|
<version>0.90</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.spark</groupId>
|
<groupId>org.apache.spark</groupId>
|
||||||
|
|||||||
@@ -19,12 +19,12 @@ package ml.dmlc.xgboost4j.scala.spark
|
|||||||
import java.io.File
|
import java.io.File
|
||||||
import java.nio.file.Files
|
import java.nio.file.Files
|
||||||
|
|
||||||
import scala.collection.mutable.ListBuffer
|
|
||||||
import scala.collection.{AbstractIterator, mutable}
|
import scala.collection.{AbstractIterator, mutable}
|
||||||
import scala.util.Random
|
import scala.util.Random
|
||||||
|
|
||||||
import ml.dmlc.xgboost4j.java.{IRabitTracker, Rabit, XGBoostError, RabitTracker => PyRabitTracker}
|
import ml.dmlc.xgboost4j.java.{IRabitTracker, Rabit, XGBoostError, RabitTracker => PyRabitTracker}
|
||||||
import ml.dmlc.xgboost4j.scala.rabit.RabitTracker
|
import ml.dmlc.xgboost4j.scala.rabit.RabitTracker
|
||||||
|
import ml.dmlc.xgboost4j.scala.spark.params.LearningTaskParams
|
||||||
import ml.dmlc.xgboost4j.scala.{XGBoost => SXGBoost, _}
|
import ml.dmlc.xgboost4j.scala.{XGBoost => SXGBoost, _}
|
||||||
import ml.dmlc.xgboost4j.{LabeledPoint => XGBLabeledPoint}
|
import ml.dmlc.xgboost4j.{LabeledPoint => XGBLabeledPoint}
|
||||||
import org.apache.commons.io.FileUtils
|
import org.apache.commons.io.FileUtils
|
||||||
@@ -32,7 +32,8 @@ import org.apache.commons.logging.LogFactory
|
|||||||
|
|
||||||
import org.apache.spark.rdd.RDD
|
import org.apache.spark.rdd.RDD
|
||||||
import org.apache.spark.{SparkContext, SparkParallelismTracker, TaskContext}
|
import org.apache.spark.{SparkContext, SparkParallelismTracker, TaskContext}
|
||||||
import org.apache.spark.sql.{DataFrame, SparkSession}
|
import org.apache.spark.sql.SparkSession
|
||||||
|
import org.apache.spark.storage.StorageLevel
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -68,30 +69,55 @@ private[spark] case class XGBLabeledPointGroup(
|
|||||||
object XGBoost extends Serializable {
|
object XGBoost extends Serializable {
|
||||||
private val logger = LogFactory.getLog("XGBoostSpark")
|
private val logger = LogFactory.getLog("XGBoostSpark")
|
||||||
|
|
||||||
private[spark] def removeMissingValues(
|
private def verifyMissingSetting(xgbLabelPoints: Iterator[XGBLabeledPoint], missing: Float):
|
||||||
xgbLabelPoints: Iterator[XGBLabeledPoint],
|
Iterator[XGBLabeledPoint] = {
|
||||||
missing: Float): Iterator[XGBLabeledPoint] = {
|
if (missing != 0.0f) {
|
||||||
if (!missing.isNaN) {
|
xgbLabelPoints.map(labeledPoint => {
|
||||||
xgbLabelPoints.map { labeledPoint =>
|
if (labeledPoint.indices != null) {
|
||||||
val indicesBuilder = new mutable.ArrayBuilder.ofInt()
|
throw new RuntimeException(s"you can only specify missing value as 0.0 (the currently" +
|
||||||
val valuesBuilder = new mutable.ArrayBuilder.ofFloat()
|
s" set value $missing) when you have SparseVector or Empty vector as your feature" +
|
||||||
for ((value, i) <- labeledPoint.values.zipWithIndex if value != missing) {
|
" format")
|
||||||
indicesBuilder += (if (labeledPoint.indices == null) i else labeledPoint.indices(i))
|
|
||||||
valuesBuilder += value
|
|
||||||
}
|
}
|
||||||
labeledPoint.copy(indices = indicesBuilder.result(), values = valuesBuilder.result())
|
labeledPoint
|
||||||
}
|
})
|
||||||
} else {
|
} else {
|
||||||
xgbLabelPoints
|
xgbLabelPoints
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private def removeMissingValuesWithGroup(
|
private def removeMissingValues(
|
||||||
|
xgbLabelPoints: Iterator[XGBLabeledPoint],
|
||||||
|
missing: Float,
|
||||||
|
keepCondition: Float => Boolean): Iterator[XGBLabeledPoint] = {
|
||||||
|
xgbLabelPoints.map { labeledPoint =>
|
||||||
|
val indicesBuilder = new mutable.ArrayBuilder.ofInt()
|
||||||
|
val valuesBuilder = new mutable.ArrayBuilder.ofFloat()
|
||||||
|
for ((value, i) <- labeledPoint.values.zipWithIndex if keepCondition(value)) {
|
||||||
|
indicesBuilder += (if (labeledPoint.indices == null) i else labeledPoint.indices(i))
|
||||||
|
valuesBuilder += value
|
||||||
|
}
|
||||||
|
labeledPoint.copy(indices = indicesBuilder.result(), values = valuesBuilder.result())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private[spark] def processMissingValues(
|
||||||
|
xgbLabelPoints: Iterator[XGBLabeledPoint],
|
||||||
|
missing: Float): Iterator[XGBLabeledPoint] = {
|
||||||
|
if (!missing.isNaN) {
|
||||||
|
removeMissingValues(verifyMissingSetting(xgbLabelPoints, missing),
|
||||||
|
missing, (v: Float) => v != missing)
|
||||||
|
} else {
|
||||||
|
removeMissingValues(verifyMissingSetting(xgbLabelPoints, missing),
|
||||||
|
missing, (v: Float) => !v.isNaN)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private def processMissingValuesWithGroup(
|
||||||
xgbLabelPointGroups: Iterator[Array[XGBLabeledPoint]],
|
xgbLabelPointGroups: Iterator[Array[XGBLabeledPoint]],
|
||||||
missing: Float): Iterator[Array[XGBLabeledPoint]] = {
|
missing: Float): Iterator[Array[XGBLabeledPoint]] = {
|
||||||
if (!missing.isNaN) {
|
if (!missing.isNaN) {
|
||||||
xgbLabelPointGroups.map {
|
xgbLabelPointGroups.map {
|
||||||
labeledPoints => XGBoost.removeMissingValues(labeledPoints.iterator, missing).toArray
|
labeledPoints => XGBoost.processMissingValues(labeledPoints.iterator, missing).toArray
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
xgbLabelPointGroups
|
xgbLabelPointGroups
|
||||||
@@ -132,13 +158,21 @@ object XGBoost extends Serializable {
|
|||||||
try {
|
try {
|
||||||
val numEarlyStoppingRounds = params.get("num_early_stopping_rounds")
|
val numEarlyStoppingRounds = params.get("num_early_stopping_rounds")
|
||||||
.map(_.toString.toInt).getOrElse(0)
|
.map(_.toString.toInt).getOrElse(0)
|
||||||
if (numEarlyStoppingRounds > 0) {
|
val overridedParams = if (numEarlyStoppingRounds > 0 &&
|
||||||
if (!params.contains("maximize_evaluation_metrics")) {
|
!params.contains("maximize_evaluation_metrics")) {
|
||||||
throw new IllegalArgumentException("maximize_evaluation_metrics has to be specified")
|
if (params.contains("custom_eval")) {
|
||||||
|
throw new IllegalArgumentException("maximize_evaluation_metrics has to be "
|
||||||
|
+ "specified when custom_eval is set")
|
||||||
}
|
}
|
||||||
|
val eval_metric = params("eval_metric").toString
|
||||||
|
val maximize = LearningTaskParams.evalMetricsToMaximize contains eval_metric
|
||||||
|
logger.info("parameter \"maximize_evaluation_metrics\" is set to " + maximize)
|
||||||
|
params + ("maximize_evaluation_metrics" -> maximize)
|
||||||
|
} else {
|
||||||
|
params
|
||||||
}
|
}
|
||||||
val metrics = Array.tabulate(watches.size)(_ => Array.ofDim[Float](round))
|
val metrics = Array.tabulate(watches.size)(_ => Array.ofDim[Float](round))
|
||||||
val booster = SXGBoost.train(watches.toMap("train"), params, round,
|
val booster = SXGBoost.train(watches.toMap("train"), overridedParams, round,
|
||||||
watches.toMap, metrics, obj, eval,
|
watches.toMap, metrics, obj, eval,
|
||||||
earlyStoppingRound = numEarlyStoppingRounds, prevBooster)
|
earlyStoppingRound = numEarlyStoppingRounds, prevBooster)
|
||||||
Iterator(booster -> watches.toMap.keys.zip(metrics).toMap)
|
Iterator(booster -> watches.toMap.keys.zip(metrics).toMap)
|
||||||
@@ -305,21 +339,20 @@ object XGBoost extends Serializable {
|
|||||||
evalSetsMap: Map[String, RDD[XGBLabeledPoint]]): RDD[(Booster, Map[String, Array[Float]])] = {
|
evalSetsMap: Map[String, RDD[XGBLabeledPoint]]): RDD[(Booster, Map[String, Array[Float]])] = {
|
||||||
val (nWorkers, _, useExternalMemory, obj, eval, missing, _, _, _, _) =
|
val (nWorkers, _, useExternalMemory, obj, eval, missing, _, _, _, _) =
|
||||||
parameterFetchAndValidation(params, trainingData.sparkContext)
|
parameterFetchAndValidation(params, trainingData.sparkContext)
|
||||||
val partitionedData = repartitionForTraining(trainingData, nWorkers)
|
|
||||||
if (evalSetsMap.isEmpty) {
|
if (evalSetsMap.isEmpty) {
|
||||||
partitionedData.mapPartitions(labeledPoints => {
|
trainingData.mapPartitions(labeledPoints => {
|
||||||
val watches = Watches.buildWatches(params,
|
val watches = Watches.buildWatches(params,
|
||||||
removeMissingValues(labeledPoints, missing),
|
processMissingValues(labeledPoints, missing),
|
||||||
getCacheDirName(useExternalMemory))
|
getCacheDirName(useExternalMemory))
|
||||||
buildDistributedBooster(watches, params, rabitEnv, checkpointRound,
|
buildDistributedBooster(watches, params, rabitEnv, checkpointRound,
|
||||||
obj, eval, prevBooster)
|
obj, eval, prevBooster)
|
||||||
}).cache()
|
}).cache()
|
||||||
} else {
|
} else {
|
||||||
coPartitionNoGroupSets(partitionedData, evalSetsMap, nWorkers).mapPartitions {
|
coPartitionNoGroupSets(trainingData, evalSetsMap, nWorkers).mapPartitions {
|
||||||
nameAndLabeledPointSets =>
|
nameAndLabeledPointSets =>
|
||||||
val watches = Watches.buildWatches(
|
val watches = Watches.buildWatches(
|
||||||
nameAndLabeledPointSets.map {
|
nameAndLabeledPointSets.map {
|
||||||
case (name, iter) => (name, removeMissingValues(iter, missing))},
|
case (name, iter) => (name, processMissingValues(iter, missing))},
|
||||||
getCacheDirName(useExternalMemory))
|
getCacheDirName(useExternalMemory))
|
||||||
buildDistributedBooster(watches, params, rabitEnv, checkpointRound,
|
buildDistributedBooster(watches, params, rabitEnv, checkpointRound,
|
||||||
obj, eval, prevBooster)
|
obj, eval, prevBooster)
|
||||||
@@ -328,7 +361,7 @@ object XGBoost extends Serializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private def trainForRanking(
|
private def trainForRanking(
|
||||||
trainingData: RDD[XGBLabeledPoint],
|
trainingData: RDD[Array[XGBLabeledPoint]],
|
||||||
params: Map[String, Any],
|
params: Map[String, Any],
|
||||||
rabitEnv: java.util.Map[String, String],
|
rabitEnv: java.util.Map[String, String],
|
||||||
checkpointRound: Int,
|
checkpointRound: Int,
|
||||||
@@ -336,20 +369,19 @@ object XGBoost extends Serializable {
|
|||||||
evalSetsMap: Map[String, RDD[XGBLabeledPoint]]): RDD[(Booster, Map[String, Array[Float]])] = {
|
evalSetsMap: Map[String, RDD[XGBLabeledPoint]]): RDD[(Booster, Map[String, Array[Float]])] = {
|
||||||
val (nWorkers, _, useExternalMemory, obj, eval, missing, _, _, _, _) =
|
val (nWorkers, _, useExternalMemory, obj, eval, missing, _, _, _, _) =
|
||||||
parameterFetchAndValidation(params, trainingData.sparkContext)
|
parameterFetchAndValidation(params, trainingData.sparkContext)
|
||||||
val partitionedTrainingSet = repartitionForTrainingGroup(trainingData, nWorkers)
|
|
||||||
if (evalSetsMap.isEmpty) {
|
if (evalSetsMap.isEmpty) {
|
||||||
partitionedTrainingSet.mapPartitions(labeledPointGroups => {
|
trainingData.mapPartitions(labeledPointGroups => {
|
||||||
val watches = Watches.buildWatchesWithGroup(params,
|
val watches = Watches.buildWatchesWithGroup(params,
|
||||||
removeMissingValuesWithGroup(labeledPointGroups, missing),
|
processMissingValuesWithGroup(labeledPointGroups, missing),
|
||||||
getCacheDirName(useExternalMemory))
|
getCacheDirName(useExternalMemory))
|
||||||
buildDistributedBooster(watches, params, rabitEnv, checkpointRound, obj, eval, prevBooster)
|
buildDistributedBooster(watches, params, rabitEnv, checkpointRound, obj, eval, prevBooster)
|
||||||
}).cache()
|
}).cache()
|
||||||
} else {
|
} else {
|
||||||
coPartitionGroupSets(partitionedTrainingSet, evalSetsMap, nWorkers).mapPartitions(
|
coPartitionGroupSets(trainingData, evalSetsMap, nWorkers).mapPartitions(
|
||||||
labeledPointGroupSets => {
|
labeledPointGroupSets => {
|
||||||
val watches = Watches.buildWatchesWithGroup(
|
val watches = Watches.buildWatchesWithGroup(
|
||||||
labeledPointGroupSets.map {
|
labeledPointGroupSets.map {
|
||||||
case (name, iter) => (name, removeMissingValuesWithGroup(iter, missing))
|
case (name, iter) => (name, processMissingValuesWithGroup(iter, missing))
|
||||||
},
|
},
|
||||||
getCacheDirName(useExternalMemory))
|
getCacheDirName(useExternalMemory))
|
||||||
buildDistributedBooster(watches, params, rabitEnv, checkpointRound, obj, eval,
|
buildDistributedBooster(watches, params, rabitEnv, checkpointRound, obj, eval,
|
||||||
@@ -358,6 +390,25 @@ object XGBoost extends Serializable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private def cacheData(ifCacheDataBoolean: Boolean, input: RDD[_]): RDD[_] = {
|
||||||
|
if (ifCacheDataBoolean) input.persist(StorageLevel.MEMORY_AND_DISK) else input
|
||||||
|
}
|
||||||
|
|
||||||
|
private def composeInputData(
|
||||||
|
trainingData: RDD[XGBLabeledPoint],
|
||||||
|
ifCacheDataBoolean: Boolean,
|
||||||
|
hasGroup: Boolean,
|
||||||
|
nWorkers: Int): Either[RDD[Array[XGBLabeledPoint]], RDD[XGBLabeledPoint]] = {
|
||||||
|
if (hasGroup) {
|
||||||
|
val repartitionedData = repartitionForTrainingGroup(trainingData, nWorkers)
|
||||||
|
Left(cacheData(ifCacheDataBoolean, repartitionedData).
|
||||||
|
asInstanceOf[RDD[Array[XGBLabeledPoint]]])
|
||||||
|
} else {
|
||||||
|
val repartitionedData = repartitionForTraining(trainingData, nWorkers)
|
||||||
|
Right(cacheData(ifCacheDataBoolean, repartitionedData).asInstanceOf[RDD[XGBLabeledPoint]])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return A tuple of the booster and the metrics used to build training summary
|
* @return A tuple of the booster and the metrics used to build training summary
|
||||||
*/
|
*/
|
||||||
@@ -368,50 +419,70 @@ object XGBoost extends Serializable {
|
|||||||
hasGroup: Boolean = false,
|
hasGroup: Boolean = false,
|
||||||
evalSetsMap: Map[String, RDD[XGBLabeledPoint]] = Map()):
|
evalSetsMap: Map[String, RDD[XGBLabeledPoint]] = Map()):
|
||||||
(Booster, Map[String, Array[Float]]) = {
|
(Booster, Map[String, Array[Float]]) = {
|
||||||
logger.info(s"XGBoost training with parameters:\n${params.mkString("\n")}")
|
logger.info(s"Running XGBoost ${spark.VERSION} with parameters:\n${params.mkString("\n")}")
|
||||||
val (nWorkers, round, _, _, _, _, trackerConf, timeoutRequestWorkers,
|
val (nWorkers, round, _, _, _, _, trackerConf, timeoutRequestWorkers,
|
||||||
checkpointPath, checkpointInterval) = parameterFetchAndValidation(params,
|
checkpointPath, checkpointInterval) = parameterFetchAndValidation(params,
|
||||||
trainingData.sparkContext)
|
trainingData.sparkContext)
|
||||||
val sc = trainingData.sparkContext
|
val sc = trainingData.sparkContext
|
||||||
val checkpointManager = new CheckpointManager(sc, checkpointPath)
|
val checkpointManager = new CheckpointManager(sc, checkpointPath)
|
||||||
checkpointManager.cleanUpHigherVersions(round.asInstanceOf[Int])
|
checkpointManager.cleanUpHigherVersions(round.asInstanceOf[Int])
|
||||||
|
val transformedTrainingData = composeInputData(trainingData,
|
||||||
|
params.getOrElse("cacheTrainingSet", false).asInstanceOf[Boolean], hasGroup, nWorkers)
|
||||||
var prevBooster = checkpointManager.loadCheckpointAsBooster
|
var prevBooster = checkpointManager.loadCheckpointAsBooster
|
||||||
// Train for every ${savingRound} rounds and save the partially completed booster
|
try {
|
||||||
checkpointManager.getCheckpointRounds(checkpointInterval, round).map {
|
// Train for every ${savingRound} rounds and save the partially completed booster
|
||||||
checkpointRound: Int =>
|
checkpointManager.getCheckpointRounds(checkpointInterval, round).map {
|
||||||
val tracker = startTracker(nWorkers, trackerConf)
|
checkpointRound: Int =>
|
||||||
try {
|
val tracker = startTracker(nWorkers, trackerConf)
|
||||||
val overriddenParams = overrideParamsAccordingToTaskCPUs(params, sc)
|
try {
|
||||||
val parallelismTracker = new SparkParallelismTracker(sc, timeoutRequestWorkers, nWorkers)
|
val overriddenParams = overrideParamsAccordingToTaskCPUs(params, sc)
|
||||||
val rabitEnv = tracker.getWorkerEnvs
|
val parallelismTracker = new SparkParallelismTracker(sc, timeoutRequestWorkers,
|
||||||
val boostersAndMetrics = if (hasGroup) {
|
nWorkers)
|
||||||
trainForRanking(trainingData, overriddenParams, rabitEnv, checkpointRound,
|
val rabitEnv = tracker.getWorkerEnvs
|
||||||
prevBooster, evalSetsMap)
|
val boostersAndMetrics = if (hasGroup) {
|
||||||
} else {
|
trainForRanking(transformedTrainingData.left.get, overriddenParams, rabitEnv,
|
||||||
trainForNonRanking(trainingData, overriddenParams, rabitEnv, checkpointRound,
|
checkpointRound, prevBooster, evalSetsMap)
|
||||||
prevBooster, evalSetsMap)
|
} else {
|
||||||
}
|
trainForNonRanking(transformedTrainingData.right.get, overriddenParams, rabitEnv,
|
||||||
val sparkJobThread = new Thread() {
|
checkpointRound, prevBooster, evalSetsMap)
|
||||||
override def run() {
|
|
||||||
// force the job
|
|
||||||
boostersAndMetrics.foreachPartition(() => _)
|
|
||||||
}
|
}
|
||||||
|
val sparkJobThread = new Thread() {
|
||||||
|
override def run() {
|
||||||
|
// force the job
|
||||||
|
boostersAndMetrics.foreachPartition(() => _)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sparkJobThread.setUncaughtExceptionHandler(tracker)
|
||||||
|
sparkJobThread.start()
|
||||||
|
val trackerReturnVal = parallelismTracker.execute(tracker.waitFor(0L))
|
||||||
|
logger.info(s"Rabit returns with exit code $trackerReturnVal")
|
||||||
|
val (booster, metrics) = postTrackerReturnProcessing(trackerReturnVal,
|
||||||
|
boostersAndMetrics, sparkJobThread)
|
||||||
|
if (checkpointRound < round) {
|
||||||
|
prevBooster = booster
|
||||||
|
checkpointManager.updateCheckpoint(prevBooster)
|
||||||
|
}
|
||||||
|
(booster, metrics)
|
||||||
|
} finally {
|
||||||
|
tracker.stop()
|
||||||
}
|
}
|
||||||
sparkJobThread.setUncaughtExceptionHandler(tracker)
|
}.last
|
||||||
sparkJobThread.start()
|
} finally {
|
||||||
val trackerReturnVal = parallelismTracker.execute(tracker.waitFor(0L))
|
uncacheTrainingData(params.getOrElse("cacheTrainingSet", false).asInstanceOf[Boolean],
|
||||||
logger.info(s"Rabit returns with exit code $trackerReturnVal")
|
transformedTrainingData)
|
||||||
val (booster, metrics) = postTrackerReturnProcessing(trackerReturnVal, boostersAndMetrics,
|
}
|
||||||
sparkJobThread)
|
}
|
||||||
if (checkpointRound < round) {
|
|
||||||
prevBooster = booster
|
private def uncacheTrainingData(
|
||||||
checkpointManager.updateCheckpoint(prevBooster)
|
cacheTrainingSet: Boolean,
|
||||||
}
|
transformedTrainingData: Either[RDD[Array[XGBLabeledPoint]], RDD[XGBLabeledPoint]]): Unit = {
|
||||||
(booster, metrics)
|
if (cacheTrainingSet) {
|
||||||
} finally {
|
if (transformedTrainingData.isLeft) {
|
||||||
tracker.stop()
|
transformedTrainingData.left.get.unpersist()
|
||||||
}
|
} else {
|
||||||
}.last
|
transformedTrainingData.right.get.unpersist()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private[spark] def repartitionForTraining(trainingData: RDD[XGBLabeledPoint], nWorkers: Int) = {
|
private[spark] def repartitionForTraining(trainingData: RDD[XGBLabeledPoint], nWorkers: Int) = {
|
||||||
|
|||||||
@@ -16,30 +16,26 @@
|
|||||||
|
|
||||||
package ml.dmlc.xgboost4j.scala.spark
|
package ml.dmlc.xgboost4j.scala.spark
|
||||||
|
|
||||||
import scala.collection.Iterator
|
|
||||||
import scala.collection.JavaConverters._
|
|
||||||
import scala.collection.mutable
|
|
||||||
|
|
||||||
import ml.dmlc.xgboost4j.java.Rabit
|
import ml.dmlc.xgboost4j.java.Rabit
|
||||||
import ml.dmlc.xgboost4j.scala.{Booster, DMatrix, XGBoost => SXGBoost}
|
|
||||||
import ml.dmlc.xgboost4j.scala.{EvalTrait, ObjectiveTrait}
|
|
||||||
import ml.dmlc.xgboost4j.scala.spark.params._
|
import ml.dmlc.xgboost4j.scala.spark.params._
|
||||||
|
import ml.dmlc.xgboost4j.scala.{Booster, DMatrix, EvalTrait, ObjectiveTrait, XGBoost => SXGBoost}
|
||||||
import ml.dmlc.xgboost4j.{LabeledPoint => XGBLabeledPoint}
|
import ml.dmlc.xgboost4j.{LabeledPoint => XGBLabeledPoint}
|
||||||
import org.apache.hadoop.fs.Path
|
import org.apache.hadoop.fs.Path
|
||||||
|
|
||||||
import org.apache.spark.TaskContext
|
import org.apache.spark.TaskContext
|
||||||
|
import org.apache.spark.broadcast.Broadcast
|
||||||
import org.apache.spark.ml.classification._
|
import org.apache.spark.ml.classification._
|
||||||
import org.apache.spark.ml.linalg._
|
import org.apache.spark.ml.linalg._
|
||||||
import org.apache.spark.ml.param._
|
import org.apache.spark.ml.param._
|
||||||
import org.apache.spark.ml.param.shared.HasWeightCol
|
import org.apache.spark.ml.param.shared.HasWeightCol
|
||||||
import org.apache.spark.ml.util._
|
import org.apache.spark.ml.util._
|
||||||
import org.apache.spark.rdd.RDD
|
import org.apache.spark.rdd.RDD
|
||||||
|
import org.apache.spark.sql._
|
||||||
import org.apache.spark.sql.functions._
|
import org.apache.spark.sql.functions._
|
||||||
import org.apache.spark.sql.types._
|
import org.apache.spark.sql.types._
|
||||||
import org.apache.spark.sql._
|
|
||||||
import org.json4s.DefaultFormats
|
import org.json4s.DefaultFormats
|
||||||
|
|
||||||
import org.apache.spark.broadcast.Broadcast
|
import scala.collection.JavaConverters._
|
||||||
|
import scala.collection.{AbstractIterator, Iterator, mutable}
|
||||||
|
|
||||||
private[spark] trait XGBoostClassifierParams extends GeneralParams with LearningTaskParams
|
private[spark] trait XGBoostClassifierParams extends GeneralParams with LearningTaskParams
|
||||||
with BoosterParams with HasWeightCol with HasBaseMarginCol with HasNumClass with ParamMapFuncs
|
with BoosterParams with HasWeightCol with HasBaseMarginCol with HasNumClass with ParamMapFuncs
|
||||||
@@ -113,6 +109,8 @@ class XGBoostClassifier (
|
|||||||
|
|
||||||
def setMaxBins(value: Int): this.type = set(maxBins, value)
|
def setMaxBins(value: Int): this.type = set(maxBins, value)
|
||||||
|
|
||||||
|
def setMaxLeaves(value: Int): this.type = set(maxLeaves, value)
|
||||||
|
|
||||||
def setSketchEps(value: Double): this.type = set(sketchEps, value)
|
def setSketchEps(value: Double): this.type = set(sketchEps, value)
|
||||||
|
|
||||||
def setScalePosWeight(value: Double): this.type = set(scalePosWeight, value)
|
def setScalePosWeight(value: Double): this.type = set(scalePosWeight, value)
|
||||||
@@ -214,7 +212,8 @@ class XGBoostClassificationModel private[ml](
|
|||||||
override val numClasses: Int,
|
override val numClasses: Int,
|
||||||
private[spark] val _booster: Booster)
|
private[spark] val _booster: Booster)
|
||||||
extends ProbabilisticClassificationModel[Vector, XGBoostClassificationModel]
|
extends ProbabilisticClassificationModel[Vector, XGBoostClassificationModel]
|
||||||
with XGBoostClassifierParams with MLWritable with Serializable {
|
with XGBoostClassifierParams with InferenceParams
|
||||||
|
with MLWritable with Serializable {
|
||||||
|
|
||||||
import XGBoostClassificationModel._
|
import XGBoostClassificationModel._
|
||||||
|
|
||||||
@@ -248,13 +247,15 @@ class XGBoostClassificationModel private[ml](
|
|||||||
|
|
||||||
def setTreeLimit(value: Int): this.type = set(treeLimit, value)
|
def setTreeLimit(value: Int): this.type = set(treeLimit, value)
|
||||||
|
|
||||||
|
def setInferBatchSize(value: Int): this.type = set(inferBatchSize, value)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Single instance prediction.
|
* Single instance prediction.
|
||||||
* Note: The performance is not ideal, use it carefully!
|
* Note: The performance is not ideal, use it carefully!
|
||||||
*/
|
*/
|
||||||
override def predict(features: Vector): Double = {
|
override def predict(features: Vector): Double = {
|
||||||
import DataUtils._
|
import DataUtils._
|
||||||
val dm = new DMatrix(XGBoost.removeMissingValues(Iterator(features.asXGB), $(missing)))
|
val dm = new DMatrix(XGBoost.processMissingValues(Iterator(features.asXGB), $(missing)))
|
||||||
val probability = _booster.predict(data = dm)(0).map(_.toDouble)
|
val probability = _booster.predict(data = dm)(0).map(_.toDouble)
|
||||||
if (numClasses == 2) {
|
if (numClasses == 2) {
|
||||||
math.round(probability(0))
|
math.round(probability(0))
|
||||||
@@ -285,46 +286,53 @@ class XGBoostClassificationModel private[ml](
|
|||||||
val bBooster = dataset.sparkSession.sparkContext.broadcast(_booster)
|
val bBooster = dataset.sparkSession.sparkContext.broadcast(_booster)
|
||||||
val appName = dataset.sparkSession.sparkContext.appName
|
val appName = dataset.sparkSession.sparkContext.appName
|
||||||
|
|
||||||
val inputRDD = dataset.asInstanceOf[Dataset[Row]].rdd
|
val resultRDD = dataset.asInstanceOf[Dataset[Row]].rdd.mapPartitions { rowIterator =>
|
||||||
val predictionRDD = dataset.asInstanceOf[Dataset[Row]].rdd.mapPartitions { rowIterator =>
|
new AbstractIterator[Row] {
|
||||||
if (rowIterator.hasNext) {
|
private var batchCnt = 0
|
||||||
val rabitEnv = Array("DMLC_TASK_ID" -> TaskContext.getPartitionId().toString).toMap
|
|
||||||
Rabit.init(rabitEnv.asJava)
|
private val batchIterImpl = rowIterator.grouped($(inferBatchSize)).flatMap { batchRow =>
|
||||||
val featuresIterator = rowIterator.map(row => row.getAs[Vector](
|
if (batchCnt == 0) {
|
||||||
$(featuresCol))).toList.iterator
|
val rabitEnv = Array("DMLC_TASK_ID" -> TaskContext.getPartitionId().toString).toMap
|
||||||
import DataUtils._
|
Rabit.init(rabitEnv.asJava)
|
||||||
val cacheInfo = {
|
}
|
||||||
if ($(useExternalMemory)) {
|
|
||||||
s"$appName-${TaskContext.get().stageId()}-dtest_cache-${TaskContext.getPartitionId()}"
|
val features = batchRow.iterator.map(row => row.getAs[Vector]($(featuresCol)))
|
||||||
} else {
|
|
||||||
null
|
import DataUtils._
|
||||||
|
val cacheInfo = {
|
||||||
|
if ($(useExternalMemory)) {
|
||||||
|
s"$appName-${TaskContext.get().stageId()}-dtest_cache-" +
|
||||||
|
s"${TaskContext.getPartitionId()}-batch-$batchCnt"
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val dm = new DMatrix(
|
||||||
|
XGBoost.processMissingValues(features.map(_.asXGB), $(missing)),
|
||||||
|
cacheInfo)
|
||||||
|
try {
|
||||||
|
val Array(rawPredictionItr, probabilityItr, predLeafItr, predContribItr) =
|
||||||
|
producePredictionItrs(bBooster, dm)
|
||||||
|
produceResultIterator(batchRow.iterator,
|
||||||
|
rawPredictionItr, probabilityItr, predLeafItr, predContribItr)
|
||||||
|
} finally {
|
||||||
|
batchCnt += 1
|
||||||
|
dm.delete()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val dm = new DMatrix(
|
|
||||||
XGBoost.removeMissingValues(featuresIterator.map(_.asXGB), $(missing)),
|
override def hasNext: Boolean = batchIterImpl.hasNext
|
||||||
cacheInfo)
|
|
||||||
try {
|
override def next(): Row = {
|
||||||
val Array(rawPredictionItr, probabilityItr, predLeafItr, predContribItr) =
|
val ret = batchIterImpl.next()
|
||||||
producePredictionItrs(bBooster, dm)
|
if (!batchIterImpl.hasNext) {
|
||||||
Rabit.shutdown()
|
Rabit.shutdown()
|
||||||
Iterator(rawPredictionItr, probabilityItr, predLeafItr,
|
}
|
||||||
predContribItr)
|
ret
|
||||||
} finally {
|
|
||||||
dm.delete()
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
Iterator()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val resultRDD = inputRDD.zipPartitions(predictionRDD, preservesPartitioning = true) {
|
|
||||||
case (inputIterator, predictionItr) =>
|
|
||||||
if (inputIterator.hasNext) {
|
|
||||||
produceResultIterator(inputIterator, predictionItr.next(), predictionItr.next(),
|
|
||||||
predictionItr.next(), predictionItr.next())
|
|
||||||
} else {
|
|
||||||
Iterator()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bBooster.unpersist(blocking = false)
|
bBooster.unpersist(blocking = false)
|
||||||
dataset.sparkSession.createDataFrame(resultRDD, generateResultSchema(schema))
|
dataset.sparkSession.createDataFrame(resultRDD, generateResultSchema(schema))
|
||||||
@@ -525,4 +533,3 @@ object XGBoostClassificationModel extends MLReadable[XGBoostClassificationModel]
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,10 +16,10 @@
|
|||||||
|
|
||||||
package ml.dmlc.xgboost4j.scala.spark
|
package ml.dmlc.xgboost4j.scala.spark
|
||||||
|
|
||||||
import scala.collection.Iterator
|
import scala.collection.{AbstractIterator, Iterator, mutable}
|
||||||
import scala.collection.JavaConverters._
|
import scala.collection.JavaConverters._
|
||||||
|
|
||||||
import ml.dmlc.xgboost4j.java.Rabit
|
import ml.dmlc.xgboost4j.java.{Rabit, XGBoost => JXGBoost}
|
||||||
import ml.dmlc.xgboost4j.{LabeledPoint => XGBLabeledPoint}
|
import ml.dmlc.xgboost4j.{LabeledPoint => XGBLabeledPoint}
|
||||||
import ml.dmlc.xgboost4j.scala.spark.params.{DefaultXGBoostParamsReader, _}
|
import ml.dmlc.xgboost4j.scala.spark.params.{DefaultXGBoostParamsReader, _}
|
||||||
import ml.dmlc.xgboost4j.scala.{Booster, DMatrix, XGBoost => SXGBoost}
|
import ml.dmlc.xgboost4j.scala.{Booster, DMatrix, XGBoost => SXGBoost}
|
||||||
@@ -37,7 +37,7 @@ import org.apache.spark.sql._
|
|||||||
import org.apache.spark.sql.functions._
|
import org.apache.spark.sql.functions._
|
||||||
import org.apache.spark.sql.types._
|
import org.apache.spark.sql.types._
|
||||||
import org.json4s.DefaultFormats
|
import org.json4s.DefaultFormats
|
||||||
import scala.collection.mutable
|
import scala.collection.mutable.ListBuffer
|
||||||
|
|
||||||
import org.apache.spark.broadcast.Broadcast
|
import org.apache.spark.broadcast.Broadcast
|
||||||
|
|
||||||
@@ -113,6 +113,8 @@ class XGBoostRegressor (
|
|||||||
|
|
||||||
def setMaxBins(value: Int): this.type = set(maxBins, value)
|
def setMaxBins(value: Int): this.type = set(maxBins, value)
|
||||||
|
|
||||||
|
def setMaxLeaves(value: Int): this.type = set(maxLeaves, value)
|
||||||
|
|
||||||
def setSketchEps(value: Double): this.type = set(sketchEps, value)
|
def setSketchEps(value: Double): this.type = set(sketchEps, value)
|
||||||
|
|
||||||
def setScalePosWeight(value: Double): this.type = set(scalePosWeight, value)
|
def setScalePosWeight(value: Double): this.type = set(scalePosWeight, value)
|
||||||
@@ -205,7 +207,8 @@ class XGBoostRegressionModel private[ml] (
|
|||||||
override val uid: String,
|
override val uid: String,
|
||||||
private[spark] val _booster: Booster)
|
private[spark] val _booster: Booster)
|
||||||
extends PredictionModel[Vector, XGBoostRegressionModel]
|
extends PredictionModel[Vector, XGBoostRegressionModel]
|
||||||
with XGBoostRegressorParams with MLWritable with Serializable {
|
with XGBoostRegressorParams with InferenceParams
|
||||||
|
with MLWritable with Serializable {
|
||||||
|
|
||||||
import XGBoostRegressionModel._
|
import XGBoostRegressionModel._
|
||||||
|
|
||||||
@@ -239,13 +242,15 @@ class XGBoostRegressionModel private[ml] (
|
|||||||
|
|
||||||
def setTreeLimit(value: Int): this.type = set(treeLimit, value)
|
def setTreeLimit(value: Int): this.type = set(treeLimit, value)
|
||||||
|
|
||||||
|
def setInferBatchSize(value: Int): this.type = set(inferBatchSize, value)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Single instance prediction.
|
* Single instance prediction.
|
||||||
* Note: The performance is not ideal, use it carefully!
|
* Note: The performance is not ideal, use it carefully!
|
||||||
*/
|
*/
|
||||||
override def predict(features: Vector): Double = {
|
override def predict(features: Vector): Double = {
|
||||||
import DataUtils._
|
import DataUtils._
|
||||||
val dm = new DMatrix(XGBoost.removeMissingValues(Iterator(features.asXGB), $(missing)))
|
val dm = new DMatrix(XGBoost.processMissingValues(Iterator(features.asXGB), $(missing)))
|
||||||
_booster.predict(data = dm)(0)(0)
|
_booster.predict(data = dm)(0)(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -257,45 +262,53 @@ class XGBoostRegressionModel private[ml] (
|
|||||||
|
|
||||||
val bBooster = dataset.sparkSession.sparkContext.broadcast(_booster)
|
val bBooster = dataset.sparkSession.sparkContext.broadcast(_booster)
|
||||||
val appName = dataset.sparkSession.sparkContext.appName
|
val appName = dataset.sparkSession.sparkContext.appName
|
||||||
val inputRDD = dataset.asInstanceOf[Dataset[Row]].rdd
|
|
||||||
val predictionRDD = dataset.asInstanceOf[Dataset[Row]].rdd.mapPartitions { rowIterator =>
|
val resultRDD = dataset.asInstanceOf[Dataset[Row]].rdd.mapPartitions { rowIterator =>
|
||||||
if (rowIterator.hasNext) {
|
new AbstractIterator[Row] {
|
||||||
val rabitEnv = Array("DMLC_TASK_ID" -> TaskContext.getPartitionId().toString).toMap
|
private var batchCnt = 0
|
||||||
Rabit.init(rabitEnv.asJava)
|
|
||||||
val featuresIterator = rowIterator.map(row => row.getAs[Vector](
|
private val batchIterImpl = rowIterator.grouped($(inferBatchSize)).flatMap { batchRow =>
|
||||||
$(featuresCol))).toList.iterator
|
if (batchCnt == 0) {
|
||||||
import DataUtils._
|
val rabitEnv = Array("DMLC_TASK_ID" -> TaskContext.getPartitionId().toString).toMap
|
||||||
val cacheInfo = {
|
Rabit.init(rabitEnv.asJava)
|
||||||
if ($(useExternalMemory)) {
|
}
|
||||||
s"$appName-${TaskContext.get().stageId()}-dtest_cache-${TaskContext.getPartitionId()}"
|
|
||||||
} else {
|
val features = batchRow.iterator.map(row => row.getAs[Vector]($(featuresCol)))
|
||||||
null
|
|
||||||
|
import DataUtils._
|
||||||
|
val cacheInfo = {
|
||||||
|
if ($(useExternalMemory)) {
|
||||||
|
s"$appName-${TaskContext.get().stageId()}-dtest_cache-" +
|
||||||
|
s"${TaskContext.getPartitionId()}-batch-$batchCnt"
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val dm = new DMatrix(
|
||||||
|
XGBoost.processMissingValues(features.map(_.asXGB), $(missing)),
|
||||||
|
cacheInfo)
|
||||||
|
try {
|
||||||
|
val Array(rawPredictionItr, predLeafItr, predContribItr) =
|
||||||
|
producePredictionItrs(bBooster, dm)
|
||||||
|
produceResultIterator(batchRow.iterator, rawPredictionItr, predLeafItr, predContribItr)
|
||||||
|
} finally {
|
||||||
|
batchCnt += 1
|
||||||
|
dm.delete()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val dm = new DMatrix(
|
|
||||||
XGBoost.removeMissingValues(featuresIterator.map(_.asXGB), $(missing)),
|
override def hasNext: Boolean = batchIterImpl.hasNext
|
||||||
cacheInfo)
|
|
||||||
try {
|
override def next(): Row = {
|
||||||
val Array(originalPredictionItr, predLeafItr, predContribItr) =
|
val ret = batchIterImpl.next()
|
||||||
producePredictionItrs(bBooster, dm)
|
if (!batchIterImpl.hasNext) {
|
||||||
Rabit.shutdown()
|
Rabit.shutdown()
|
||||||
Iterator(originalPredictionItr, predLeafItr, predContribItr)
|
}
|
||||||
} finally {
|
ret
|
||||||
dm.delete()
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
Iterator()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val resultRDD = inputRDD.zipPartitions(predictionRDD, preservesPartitioning = true) {
|
|
||||||
case (inputIterator, predictionItr) =>
|
|
||||||
if (inputIterator.hasNext) {
|
|
||||||
produceResultIterator(inputIterator, predictionItr.next(), predictionItr.next(),
|
|
||||||
predictionItr.next())
|
|
||||||
} else {
|
|
||||||
Iterator()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bBooster.unpersist(blocking = false)
|
bBooster.unpersist(blocking = false)
|
||||||
dataset.sparkSession.createDataFrame(resultRDD, generateResultSchema(schema))
|
dataset.sparkSession.createDataFrame(resultRDD, generateResultSchema(schema))
|
||||||
}
|
}
|
||||||
@@ -345,14 +358,14 @@ class XGBoostRegressionModel private[ml] (
|
|||||||
resultSchema
|
resultSchema
|
||||||
}
|
}
|
||||||
|
|
||||||
private def producePredictionItrs(broadcastBooster: Broadcast[Booster], dm: DMatrix):
|
private def producePredictionItrs(booster: Broadcast[Booster], dm: DMatrix):
|
||||||
Array[Iterator[Row]] = {
|
Array[Iterator[Row]] = {
|
||||||
val originalPredictionItr = {
|
val originalPredictionItr = {
|
||||||
broadcastBooster.value.predict(dm, outPutMargin = false, $(treeLimit)).map(Row(_)).iterator
|
booster.value.predict(dm, outPutMargin = false, $(treeLimit)).map(Row(_)).iterator
|
||||||
}
|
}
|
||||||
val predLeafItr = {
|
val predLeafItr = {
|
||||||
if (isDefined(leafPredictionCol)) {
|
if (isDefined(leafPredictionCol)) {
|
||||||
broadcastBooster.value.predictLeaf(dm, $(treeLimit)).
|
booster.value.predictLeaf(dm, $(treeLimit)).
|
||||||
map(Row(_)).iterator
|
map(Row(_)).iterator
|
||||||
} else {
|
} else {
|
||||||
Iterator()
|
Iterator()
|
||||||
@@ -360,7 +373,7 @@ class XGBoostRegressionModel private[ml] (
|
|||||||
}
|
}
|
||||||
val predContribItr = {
|
val predContribItr = {
|
||||||
if (isDefined(contribPredictionCol)) {
|
if (isDefined(contribPredictionCol)) {
|
||||||
broadcastBooster.value.predictContrib(dm, $(treeLimit)).
|
booster.value.predictContrib(dm, $(treeLimit)).
|
||||||
map(Row(_)).iterator
|
map(Row(_)).iterator
|
||||||
} else {
|
} else {
|
||||||
Iterator()
|
Iterator()
|
||||||
@@ -371,7 +384,6 @@ class XGBoostRegressionModel private[ml] (
|
|||||||
|
|
||||||
override def transform(dataset: Dataset[_]): DataFrame = {
|
override def transform(dataset: Dataset[_]): DataFrame = {
|
||||||
transformSchema(dataset.schema, logging = true)
|
transformSchema(dataset.schema, logging = true)
|
||||||
|
|
||||||
// Output selected columns only.
|
// Output selected columns only.
|
||||||
// This is a bit complicated since it tries to avoid repeated computation.
|
// This is a bit complicated since it tries to avoid repeated computation.
|
||||||
var outputData = transformInternal(dataset)
|
var outputData = transformInternal(dataset)
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2014 by Contributors
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package ml.dmlc.xgboost4j.scala
|
||||||
|
|
||||||
|
import java.util.Properties
|
||||||
|
|
||||||
|
import org.apache.spark.SparkException
|
||||||
|
|
||||||
|
package object spark {
|
||||||
|
private def loadVersionInfo(): String = {
|
||||||
|
val versionResourceFile = Thread.currentThread().getContextClassLoader.getResourceAsStream(
|
||||||
|
"xgboost4j-version.properties")
|
||||||
|
try {
|
||||||
|
val unknownProp = "<unknown>"
|
||||||
|
val props = new Properties()
|
||||||
|
props.load(versionResourceFile)
|
||||||
|
props.getProperty("version", unknownProp)
|
||||||
|
} catch {
|
||||||
|
case e: Exception =>
|
||||||
|
throw new SparkException("Error loading properties from xgboost4j-version.properties", e)
|
||||||
|
} finally {
|
||||||
|
if (versionResourceFile != null) {
|
||||||
|
try {
|
||||||
|
versionResourceFile.close()
|
||||||
|
} catch {
|
||||||
|
case e: Exception =>
|
||||||
|
throw new SparkException("Error closing xgboost4j version resource stream", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val VERSION: String = loadVersionInfo()
|
||||||
|
}
|
||||||
@@ -22,12 +22,17 @@ import org.json4s.JsonAST.JObject
|
|||||||
import org.json4s.jackson.JsonMethods.{compact, parse, render}
|
import org.json4s.jackson.JsonMethods.{compact, parse, render}
|
||||||
|
|
||||||
import org.apache.spark.SparkContext
|
import org.apache.spark.SparkContext
|
||||||
import org.apache.spark.ml.param.Params
|
import org.apache.spark.ml.param.{Param, Params}
|
||||||
import org.apache.spark.ml.util.MLReader
|
import org.apache.spark.ml.util.MLReader
|
||||||
|
|
||||||
// This originates from apache-spark DefaultPramsReader copy paste
|
// This originates from apache-spark DefaultPramsReader copy paste
|
||||||
private[spark] object DefaultXGBoostParamsReader {
|
private[spark] object DefaultXGBoostParamsReader {
|
||||||
|
|
||||||
|
private val paramNameCompatibilityMap: Map[String, String] = Map("silent" -> "verbosity")
|
||||||
|
|
||||||
|
private val paramValueCompatibilityMap: Map[String, Map[Any, Any]] =
|
||||||
|
Map("objective" -> Map("reg:linear" -> "reg:squarederror"))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All info from metadata file.
|
* All info from metadata file.
|
||||||
*
|
*
|
||||||
@@ -103,6 +108,14 @@ private[spark] object DefaultXGBoostParamsReader {
|
|||||||
Metadata(className, uid, timestamp, sparkVersion, params, metadata, metadataStr)
|
Metadata(className, uid, timestamp, sparkVersion, params, metadata, metadataStr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private def handleBrokenlyChangedValue[T](paramName: String, value: T): T = {
|
||||||
|
paramValueCompatibilityMap.getOrElse(paramName, Map()).getOrElse(value, value).asInstanceOf[T]
|
||||||
|
}
|
||||||
|
|
||||||
|
private def handleBrokenlyChangedName(paramName: String): String = {
|
||||||
|
paramNameCompatibilityMap.getOrElse(paramName, paramName)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extract Params from metadata, and set them in the instance.
|
* Extract Params from metadata, and set them in the instance.
|
||||||
* This works if all Params implement [[org.apache.spark.ml.param.Param.jsonDecode()]].
|
* This works if all Params implement [[org.apache.spark.ml.param.Param.jsonDecode()]].
|
||||||
@@ -113,9 +126,9 @@ private[spark] object DefaultXGBoostParamsReader {
|
|||||||
metadata.params match {
|
metadata.params match {
|
||||||
case JObject(pairs) =>
|
case JObject(pairs) =>
|
||||||
pairs.foreach { case (paramName, jsonValue) =>
|
pairs.foreach { case (paramName, jsonValue) =>
|
||||||
val param = instance.getParam(paramName)
|
val param = instance.getParam(handleBrokenlyChangedName(paramName))
|
||||||
val value = param.jsonDecode(compact(render(jsonValue)))
|
val value = param.jsonDecode(compact(render(jsonValue)))
|
||||||
instance.set(param, value)
|
instance.set(param, handleBrokenlyChangedValue(paramName, value))
|
||||||
}
|
}
|
||||||
case _ =>
|
case _ =>
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2014 by Contributors
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package ml.dmlc.xgboost4j.scala.spark.params
|
||||||
|
|
||||||
|
import org.apache.spark.ml.param.{IntParam, Params}
|
||||||
|
|
||||||
|
private[spark] trait InferenceParams extends Params {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* batch size of inference iteration
|
||||||
|
*/
|
||||||
|
final val inferBatchSize = new IntParam(this, "batchSize", "batch size of inference iteration")
|
||||||
|
|
||||||
|
/** @group getParam */
|
||||||
|
final def getInferBatchSize: Int = ${inferBatchSize}
|
||||||
|
|
||||||
|
setDefault(inferBatchSize, 32 << 10)
|
||||||
|
}
|
||||||
@@ -24,8 +24,8 @@ private[spark] trait LearningTaskParams extends Params {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Specify the learning task and the corresponding learning objective.
|
* Specify the learning task and the corresponding learning objective.
|
||||||
* options: reg:linear, reg:logistic, binary:logistic, binary:logitraw, count:poisson,
|
* options: reg:squarederror, reg:logistic, binary:logistic, binary:logitraw, count:poisson,
|
||||||
* multi:softmax, multi:softprob, rank:pairwise, reg:gamma. default: reg:linear
|
* multi:softmax, multi:softprob, rank:pairwise, reg:gamma. default: reg:squarederror
|
||||||
*/
|
*/
|
||||||
final val objective = new Param[String](this, "objective", "objective function used for " +
|
final val objective = new Param[String](this, "objective", "objective function used for " +
|
||||||
s"training, options: {${LearningTaskParams.supportedObjective.mkString(",")}",
|
s"training, options: {${LearningTaskParams.supportedObjective.mkString(",")}",
|
||||||
@@ -76,6 +76,12 @@ private[spark] trait LearningTaskParams extends Params {
|
|||||||
|
|
||||||
final def getTrainTestRatio: Double = $(trainTestRatio)
|
final def getTrainTestRatio: Double = $(trainTestRatio)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* whether caching training data
|
||||||
|
*/
|
||||||
|
final val cacheTrainingSet = new BooleanParam(this, "cacheTrainingSet",
|
||||||
|
"whether caching training data")
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If non-zero, the training will be stopped after a specified number
|
* If non-zero, the training will be stopped after a specified number
|
||||||
* of consecutive increases in any evaluation metric.
|
* of consecutive increases in any evaluation metric.
|
||||||
@@ -94,17 +100,21 @@ private[spark] trait LearningTaskParams extends Params {
|
|||||||
|
|
||||||
final def getMaximizeEvaluationMetrics: Boolean = $(maximizeEvaluationMetrics)
|
final def getMaximizeEvaluationMetrics: Boolean = $(maximizeEvaluationMetrics)
|
||||||
|
|
||||||
setDefault(objective -> "reg:linear", baseScore -> 0.5,
|
setDefault(objective -> "reg:squarederror", baseScore -> 0.5,
|
||||||
trainTestRatio -> 1.0, numEarlyStoppingRounds -> 0)
|
trainTestRatio -> 1.0, numEarlyStoppingRounds -> 0, cacheTrainingSet -> false)
|
||||||
}
|
}
|
||||||
|
|
||||||
private[spark] object LearningTaskParams {
|
private[spark] object LearningTaskParams {
|
||||||
val supportedObjective = HashSet("reg:linear", "reg:logistic", "binary:logistic",
|
val supportedObjective = HashSet("reg:squarederror", "reg:logistic", "binary:logistic",
|
||||||
"binary:logitraw", "count:poisson", "multi:softmax", "multi:softprob", "rank:pairwise",
|
"binary:logitraw", "count:poisson", "multi:softmax", "multi:softprob", "rank:pairwise",
|
||||||
"rank:ndcg", "rank:map", "reg:gamma", "reg:tweedie")
|
"rank:ndcg", "rank:map", "reg:gamma", "reg:tweedie")
|
||||||
|
|
||||||
val supportedObjectiveType = HashSet("regression", "classification")
|
val supportedObjectiveType = HashSet("regression", "classification")
|
||||||
|
|
||||||
val supportedEvalMetrics = HashSet("rmse", "mae", "logloss", "error", "merror", "mlogloss",
|
val evalMetricsToMaximize = HashSet("auc", "aucpr", "ndcg", "map")
|
||||||
"auc", "aucpr", "ndcg", "map", "gamma-deviance")
|
|
||||||
|
val evalMetricsToMinimize = HashSet("rmse", "mae", "logloss", "error", "merror",
|
||||||
|
"mlogloss", "gamma-deviance")
|
||||||
|
|
||||||
|
val supportedEvalMetrics = evalMetricsToMaximize union evalMetricsToMinimize
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
@@ -0,0 +1 @@
|
|||||||
|
{"class":"ml.dmlc.xgboost4j.scala.spark.XGBoostClassificationModel","timestamp":1555350539033,"sparkVersion":"2.3.2-uber-109","uid":"xgbc_5e7bec215a4c","paramMap":{"useExternalMemory":false,"trainTestRatio":1.0,"alpha":0.0,"seed":0,"numWorkers":100,"skipDrop":0.0,"treeLimit":0,"silent":0,"trackerConf":{"workerConnectionTimeout":0,"trackerImpl":"python"},"missing":"NaN","colsampleBylevel":1.0,"probabilityCol":"probability","checkpointPath":"","lambda":1.0,"rawPredictionCol":"rawPrediction","eta":0.3,"numEarlyStoppingRounds":0,"growPolicy":"depthwise","gamma":0.0,"sampleType":"uniform","maxDepth":6,"rateDrop":0.0,"objective":"reg:linear","customObj":null,"lambdaBias":0.0,"baseScore":0.5,"labelCol":"label","minChildWeight":1.0,"customEval":null,"normalizeType":"tree","maxBin":16,"nthread":4,"numRound":20,"colsampleBytree":1.0,"predictionCol":"prediction","subsample":1.0,"timeoutRequestWorkers":1800000,"featuresCol":"features","evalMetric":"error","sketchEps":0.03,"scalePosWeight":1.0,"checkpointInterval":-1,"maxDeltaStep":0.0,"treeMethod":"approx"}}
|
||||||
@@ -0,0 +1,153 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2014 by Contributors
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package ml.dmlc.xgboost4j.scala.spark
|
||||||
|
|
||||||
|
import ml.dmlc.xgboost4j.java.XGBoostError
|
||||||
|
import org.apache.spark.ml.feature.VectorAssembler
|
||||||
|
import org.apache.spark.ml.linalg.Vectors
|
||||||
|
import org.apache.spark.sql.DataFrame
|
||||||
|
import org.scalatest.FunSuite
|
||||||
|
|
||||||
|
import scala.util.Random
|
||||||
|
|
||||||
|
class MissingValueHandlingSuite extends FunSuite with PerTest {
|
||||||
|
test("dense vectors containing missing value") {
|
||||||
|
def buildDenseDataFrame(): DataFrame = {
|
||||||
|
val numRows = 100
|
||||||
|
val numCols = 5
|
||||||
|
val data = (0 until numRows).map { x =>
|
||||||
|
val label = Random.nextInt(2)
|
||||||
|
val values = Array.tabulate[Double](numCols) { c =>
|
||||||
|
if (c == numCols - 1) 0 else Random.nextDouble
|
||||||
|
}
|
||||||
|
(label, Vectors.dense(values))
|
||||||
|
}
|
||||||
|
ss.createDataFrame(sc.parallelize(data.toList)).toDF("label", "features")
|
||||||
|
}
|
||||||
|
val denseDF = buildDenseDataFrame().repartition(4)
|
||||||
|
val paramMap = List("eta" -> "1", "max_depth" -> "2",
|
||||||
|
"objective" -> "binary:logistic", "missing" -> 0, "num_workers" -> numWorkers).toMap
|
||||||
|
val model = new XGBoostClassifier(paramMap).fit(denseDF)
|
||||||
|
model.transform(denseDF).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
test("handle Float.NaN as missing value correctly") {
|
||||||
|
val spark = ss
|
||||||
|
import spark.implicits._
|
||||||
|
val testDF = Seq(
|
||||||
|
(1.0f, 0.0f, Float.NaN, 1.0),
|
||||||
|
(1.0f, 0.0f, 1.0f, 1.0),
|
||||||
|
(0.0f, 1.0f, 0.0f, 0.0),
|
||||||
|
(1.0f, 0.0f, 1.0f, 1.0),
|
||||||
|
(1.0f, Float.NaN, 0.0f, 0.0),
|
||||||
|
(0.0f, 1.0f, 0.0f, 1.0),
|
||||||
|
(Float.NaN, 0.0f, 0.0f, 1.0)
|
||||||
|
).toDF("col1", "col2", "col3", "label")
|
||||||
|
val vectorAssembler = new VectorAssembler()
|
||||||
|
.setInputCols(Array("col1", "col2", "col3"))
|
||||||
|
.setOutputCol("features")
|
||||||
|
org.apache.spark.SPARK_VERSION match {
|
||||||
|
case version if version.startsWith("2.4") =>
|
||||||
|
val m = vectorAssembler.getClass.getDeclaredMethods
|
||||||
|
.filter(_.getName.contains("setHandleInvalid")).head
|
||||||
|
m.invoke(vectorAssembler, "keep")
|
||||||
|
case _ =>
|
||||||
|
}
|
||||||
|
val inputDF = vectorAssembler.transform(testDF).select("features", "label")
|
||||||
|
val paramMap = List("eta" -> "1", "max_depth" -> "2",
|
||||||
|
"objective" -> "binary:logistic", "missing" -> Float.NaN, "num_workers" -> 1).toMap
|
||||||
|
val model = new XGBoostClassifier(paramMap).fit(inputDF)
|
||||||
|
model.transform(inputDF).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
test("specify a non-zero missing value but with dense vector does not stop" +
|
||||||
|
" application") {
|
||||||
|
val spark = ss
|
||||||
|
import spark.implicits._
|
||||||
|
// spark uses 1.5 * (nnz + 1.0) < size as the condition to decide whether using sparse or dense
|
||||||
|
// vector,
|
||||||
|
val testDF = Seq(
|
||||||
|
(1.0f, 0.0f, -1.0f, 1.0),
|
||||||
|
(1.0f, 0.0f, 1.0f, 1.0),
|
||||||
|
(0.0f, 1.0f, 0.0f, 0.0),
|
||||||
|
(1.0f, 0.0f, 1.0f, 1.0),
|
||||||
|
(1.0f, -1.0f, 0.0f, 0.0),
|
||||||
|
(0.0f, 1.0f, 0.0f, 1.0),
|
||||||
|
(-1.0f, 0.0f, 0.0f, 1.0)
|
||||||
|
).toDF("col1", "col2", "col3", "label")
|
||||||
|
val vectorAssembler = new VectorAssembler()
|
||||||
|
.setInputCols(Array("col1", "col2", "col3"))
|
||||||
|
.setOutputCol("features")
|
||||||
|
val inputDF = vectorAssembler.transform(testDF).select("features", "label")
|
||||||
|
val paramMap = List("eta" -> "1", "max_depth" -> "2",
|
||||||
|
"objective" -> "binary:logistic", "missing" -> -1.0f, "num_workers" -> 1).toMap
|
||||||
|
val model = new XGBoostClassifier(paramMap).fit(inputDF)
|
||||||
|
model.transform(inputDF).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
test("specify a non-zero missing value and meet an empty vector we should" +
|
||||||
|
" stop the application") {
|
||||||
|
val spark = ss
|
||||||
|
import spark.implicits._
|
||||||
|
val testDF = Seq(
|
||||||
|
(1.0f, 0.0f, -1.0f, 1.0),
|
||||||
|
(1.0f, 0.0f, 1.0f, 1.0),
|
||||||
|
(0.0f, 1.0f, 0.0f, 0.0),
|
||||||
|
(1.0f, 0.0f, 1.0f, 1.0),
|
||||||
|
(1.0f, -1.0f, 0.0f, 0.0),
|
||||||
|
(0.0f, 0.0f, 0.0f, 1.0),// empty vector
|
||||||
|
(-1.0f, 0.0f, 0.0f, 1.0)
|
||||||
|
).toDF("col1", "col2", "col3", "label")
|
||||||
|
val vectorAssembler = new VectorAssembler()
|
||||||
|
.setInputCols(Array("col1", "col2", "col3"))
|
||||||
|
.setOutputCol("features")
|
||||||
|
val inputDF = vectorAssembler.transform(testDF).select("features", "label")
|
||||||
|
val paramMap = List("eta" -> "1", "max_depth" -> "2",
|
||||||
|
"objective" -> "binary:logistic", "missing" -> -1.0f, "num_workers" -> 1).toMap
|
||||||
|
intercept[XGBoostError] {
|
||||||
|
new XGBoostClassifier(paramMap).fit(inputDF)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test("specify a non-zero missing value and meet a Sparse vector we should" +
|
||||||
|
" stop the application") {
|
||||||
|
val spark = ss
|
||||||
|
import spark.implicits._
|
||||||
|
ss.sparkContext.setLogLevel("INFO")
|
||||||
|
// spark uses 1.5 * (nnz + 1.0) < size as the condition to decide whether using sparse or dense
|
||||||
|
// vector,
|
||||||
|
val testDF = Seq(
|
||||||
|
(1.0f, 0.0f, -1.0f, 1.0f, 1.0),
|
||||||
|
(1.0f, 0.0f, 1.0f, 1.0f, 1.0),
|
||||||
|
(0.0f, 1.0f, 0.0f, 1.0f, 0.0),
|
||||||
|
(1.0f, 0.0f, 1.0f, 1.0f, 1.0),
|
||||||
|
(1.0f, -1.0f, 0.0f, 1.0f, 0.0),
|
||||||
|
(0.0f, 0.0f, 0.0f, 1.0f, 1.0),
|
||||||
|
(-1.0f, 0.0f, 0.0f, 1.0f, 1.0)
|
||||||
|
).toDF("col1", "col2", "col3", "col4", "label")
|
||||||
|
val vectorAssembler = new VectorAssembler()
|
||||||
|
.setInputCols(Array("col1", "col2", "col3", "col4"))
|
||||||
|
.setOutputCol("features")
|
||||||
|
val inputDF = vectorAssembler.transform(testDF).select("features", "label")
|
||||||
|
inputDF.show()
|
||||||
|
val paramMap = List("eta" -> "1", "max_depth" -> "2",
|
||||||
|
"objective" -> "binary:logistic", "missing" -> -1.0f, "num_workers" -> 1).toMap
|
||||||
|
intercept[XGBoostError] {
|
||||||
|
new XGBoostClassifier(paramMap).fit(inputDF)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,11 +19,12 @@ package ml.dmlc.xgboost4j.scala.spark
|
|||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
import ml.dmlc.xgboost4j.{LabeledPoint => XGBLabeledPoint}
|
import ml.dmlc.xgboost4j.{LabeledPoint => XGBLabeledPoint}
|
||||||
|
|
||||||
import org.apache.spark.{SparkConf, SparkContext}
|
import org.apache.spark.{SparkConf, SparkContext}
|
||||||
import org.apache.spark.sql._
|
import org.apache.spark.sql._
|
||||||
import org.scalatest.{BeforeAndAfterEach, FunSuite}
|
import org.scalatest.{BeforeAndAfterEach, FunSuite}
|
||||||
|
|
||||||
|
import scala.util.Random
|
||||||
|
|
||||||
trait PerTest extends BeforeAndAfterEach { self: FunSuite =>
|
trait PerTest extends BeforeAndAfterEach { self: FunSuite =>
|
||||||
|
|
||||||
protected val numWorkers: Int = Runtime.getRuntime.availableProcessors()
|
protected val numWorkers: Int = Runtime.getRuntime.availableProcessors()
|
||||||
@@ -80,6 +81,18 @@ trait PerTest extends BeforeAndAfterEach { self: FunSuite =>
|
|||||||
.toDF("id", "label", "features")
|
.toDF("id", "label", "features")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected def buildDataFrameWithRandSort(
|
||||||
|
labeledPoints: Seq[XGBLabeledPoint],
|
||||||
|
numPartitions: Int = numWorkers): DataFrame = {
|
||||||
|
val df = buildDataFrame(labeledPoints, numPartitions)
|
||||||
|
val rndSortedRDD = df.rdd.mapPartitions { iter =>
|
||||||
|
iter.map(_ -> Random.nextDouble()).toList
|
||||||
|
.sortBy(_._2)
|
||||||
|
.map(_._1).iterator
|
||||||
|
}
|
||||||
|
ss.createDataFrame(rndSortedRDD, df.schema)
|
||||||
|
}
|
||||||
|
|
||||||
protected def buildDataFrameWithGroup(
|
protected def buildDataFrameWithGroup(
|
||||||
labeledPoints: Seq[XGBLabeledPoint],
|
labeledPoints: Seq[XGBLabeledPoint],
|
||||||
numPartitions: Int = numWorkers): DataFrame = {
|
numPartitions: Int = numWorkers): DataFrame = {
|
||||||
|
|||||||
@@ -19,9 +19,11 @@ package ml.dmlc.xgboost4j.scala.spark
|
|||||||
import java.io.{File, FileNotFoundException}
|
import java.io.{File, FileNotFoundException}
|
||||||
import java.util.Arrays
|
import java.util.Arrays
|
||||||
|
|
||||||
import ml.dmlc.xgboost4j.scala.DMatrix
|
import scala.io.Source
|
||||||
|
|
||||||
|
import ml.dmlc.xgboost4j.scala.DMatrix
|
||||||
import scala.util.Random
|
import scala.util.Random
|
||||||
|
|
||||||
import org.apache.spark.ml.feature._
|
import org.apache.spark.ml.feature._
|
||||||
import org.apache.spark.ml.{Pipeline, PipelineModel}
|
import org.apache.spark.ml.{Pipeline, PipelineModel}
|
||||||
import org.apache.spark.network.util.JavaUtils
|
import org.apache.spark.network.util.JavaUtils
|
||||||
@@ -96,7 +98,7 @@ class PersistenceSuite extends FunSuite with PerTest with BeforeAndAfterAll {
|
|||||||
val testDM = new DMatrix(Regression.test.iterator)
|
val testDM = new DMatrix(Regression.test.iterator)
|
||||||
|
|
||||||
val paramMap = Map("eta" -> "0.1", "max_depth" -> "6", "silent" -> "1",
|
val paramMap = Map("eta" -> "0.1", "max_depth" -> "6", "silent" -> "1",
|
||||||
"objective" -> "reg:linear", "num_round" -> "10", "num_workers" -> numWorkers)
|
"objective" -> "reg:squarederror", "num_round" -> "10", "num_workers" -> numWorkers)
|
||||||
val xgbr = new XGBoostRegressor(paramMap)
|
val xgbr = new XGBoostRegressor(paramMap)
|
||||||
val xgbrPath = new File(tempDir, "xgbr").getPath
|
val xgbrPath = new File(tempDir, "xgbr").getPath
|
||||||
xgbr.write.overwrite().save(xgbrPath)
|
xgbr.write.overwrite().save(xgbrPath)
|
||||||
@@ -162,5 +164,17 @@ class PersistenceSuite extends FunSuite with PerTest with BeforeAndAfterAll {
|
|||||||
assert(xgbModel.getNumRound === xgbModel2.getNumRound)
|
assert(xgbModel.getNumRound === xgbModel2.getNumRound)
|
||||||
assert(xgbModel.getRawPredictionCol === xgbModel2.getRawPredictionCol)
|
assert(xgbModel.getRawPredictionCol === xgbModel2.getRawPredictionCol)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test("cross-version model loading (0.82)") {
|
||||||
|
val modelPath = getClass.getResource("/model/0.82/model").getPath
|
||||||
|
val model = XGBoostClassificationModel.read.load(modelPath)
|
||||||
|
val r = new Random(0)
|
||||||
|
val df = ss.createDataFrame(Seq.fill(100)(r.nextInt(2)).map(i => (i, i))).
|
||||||
|
toDF("feature", "label")
|
||||||
|
val assembler = new VectorAssembler()
|
||||||
|
.setInputCols(df.columns.filter(!_.contains("label")))
|
||||||
|
.setOutputCol("features")
|
||||||
|
model.transform(assembler.transform(df)).show()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,14 +16,73 @@
|
|||||||
|
|
||||||
package ml.dmlc.xgboost4j.scala.spark
|
package ml.dmlc.xgboost4j.scala.spark
|
||||||
|
|
||||||
|
import java.util.concurrent.LinkedBlockingDeque
|
||||||
|
|
||||||
|
import scala.util.Random
|
||||||
|
|
||||||
import ml.dmlc.xgboost4j.java.{IRabitTracker, Rabit, RabitTracker => PyRabitTracker}
|
import ml.dmlc.xgboost4j.java.{IRabitTracker, Rabit, RabitTracker => PyRabitTracker}
|
||||||
import ml.dmlc.xgboost4j.scala.rabit.{RabitTracker => ScalaRabitTracker}
|
import ml.dmlc.xgboost4j.scala.rabit.{RabitTracker => ScalaRabitTracker}
|
||||||
import ml.dmlc.xgboost4j.java.IRabitTracker.TrackerStatus
|
import ml.dmlc.xgboost4j.java.IRabitTracker.TrackerStatus
|
||||||
|
import ml.dmlc.xgboost4j.scala.DMatrix
|
||||||
|
|
||||||
import org.apache.spark.{SparkConf, SparkContext}
|
import org.apache.spark.{SparkConf, SparkContext}
|
||||||
import org.scalatest.FunSuite
|
import org.scalatest.FunSuite
|
||||||
|
|
||||||
|
|
||||||
class RabitTrackerRobustnessSuite extends FunSuite with PerTest {
|
class RabitSuite extends FunSuite with PerTest {
|
||||||
|
|
||||||
|
test("training with Scala-implemented Rabit tracker") {
|
||||||
|
val eval = new EvalError()
|
||||||
|
val training = buildDataFrame(Classification.train)
|
||||||
|
val testDM = new DMatrix(Classification.test.iterator)
|
||||||
|
val paramMap = Map("eta" -> "1", "max_depth" -> "6",
|
||||||
|
"objective" -> "binary:logistic", "num_round" -> 5, "num_workers" -> numWorkers,
|
||||||
|
"tracker_conf" -> TrackerConf(60 * 60 * 1000, "scala"))
|
||||||
|
val model = new XGBoostClassifier(paramMap).fit(training)
|
||||||
|
assert(eval.eval(model._booster.predict(testDM, outPutMargin = true), testDM) < 0.1)
|
||||||
|
}
|
||||||
|
|
||||||
|
test("test Rabit allreduce to validate Scala-implemented Rabit tracker") {
|
||||||
|
val vectorLength = 100
|
||||||
|
val rdd = sc.parallelize(
|
||||||
|
(1 to numWorkers * vectorLength).toArray.map { _ => Random.nextFloat() }, numWorkers).cache()
|
||||||
|
|
||||||
|
val tracker = new ScalaRabitTracker(numWorkers)
|
||||||
|
tracker.start(0)
|
||||||
|
val trackerEnvs = tracker.getWorkerEnvs
|
||||||
|
val collectedAllReduceResults = new LinkedBlockingDeque[Array[Float]]()
|
||||||
|
|
||||||
|
val rawData = rdd.mapPartitions { iter =>
|
||||||
|
Iterator(iter.toArray)
|
||||||
|
}.collect()
|
||||||
|
|
||||||
|
val maxVec = (0 until vectorLength).toArray.map { j =>
|
||||||
|
(0 until numWorkers).toArray.map { i => rawData(i)(j) }.max
|
||||||
|
}
|
||||||
|
|
||||||
|
val allReduceResults = rdd.mapPartitions { iter =>
|
||||||
|
Rabit.init(trackerEnvs)
|
||||||
|
val arr = iter.toArray
|
||||||
|
val results = Rabit.allReduce(arr, Rabit.OpType.MAX)
|
||||||
|
Rabit.shutdown()
|
||||||
|
Iterator(results)
|
||||||
|
}.cache()
|
||||||
|
|
||||||
|
val sparkThread = new Thread() {
|
||||||
|
override def run(): Unit = {
|
||||||
|
allReduceResults.foreachPartition(() => _)
|
||||||
|
val byPartitionResults = allReduceResults.collect()
|
||||||
|
assert(byPartitionResults(0).length == vectorLength)
|
||||||
|
collectedAllReduceResults.put(byPartitionResults(0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sparkThread.start()
|
||||||
|
assert(tracker.waitFor(0L) == 0)
|
||||||
|
sparkThread.join()
|
||||||
|
|
||||||
|
assert(collectedAllReduceResults.poll().sameElements(maxVec))
|
||||||
|
}
|
||||||
|
|
||||||
test("test Java RabitTracker wrapper's exception handling: it should not hang forever.") {
|
test("test Java RabitTracker wrapper's exception handling: it should not hang forever.") {
|
||||||
/*
|
/*
|
||||||
Deliberately create new instances of SparkContext in each unit test to avoid reusing the
|
Deliberately create new instances of SparkContext in each unit test to avoid reusing the
|
||||||
@@ -148,4 +207,23 @@ class RabitTrackerRobustnessSuite extends FunSuite with PerTest {
|
|||||||
// should fail due to connection timeout
|
// should fail due to connection timeout
|
||||||
assert(tracker.waitFor(0L) == TrackerStatus.FAILURE.getStatusCode)
|
assert(tracker.waitFor(0L) == TrackerStatus.FAILURE.getStatusCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test("should allow the dataframe containing rabit calls to be partially evaluated for" +
|
||||||
|
" multiple times (ISSUE-4406)") {
|
||||||
|
val paramMap = Map(
|
||||||
|
"eta" -> "1",
|
||||||
|
"max_depth" -> "6",
|
||||||
|
"silent" -> "1",
|
||||||
|
"objective" -> "binary:logistic")
|
||||||
|
val trainingDF = buildDataFrame(Classification.train)
|
||||||
|
val model = new XGBoostClassifier(paramMap ++ Array("num_round" -> 10,
|
||||||
|
"num_workers" -> numWorkers)).fit(trainingDF)
|
||||||
|
val prediction = model.transform(trainingDF)
|
||||||
|
// a partial evaluation of dataframe will cause rabit initialized but not shutdown in some
|
||||||
|
// threads
|
||||||
|
prediction.show()
|
||||||
|
// a full evaluation here will re-run init and shutdown all rabit proxy
|
||||||
|
// expecting no error
|
||||||
|
prediction.collect()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -27,13 +27,28 @@ import org.apache.spark.Partitioner
|
|||||||
|
|
||||||
class XGBoostClassifierSuite extends FunSuite with PerTest {
|
class XGBoostClassifierSuite extends FunSuite with PerTest {
|
||||||
|
|
||||||
test("XGBoost-Spark XGBoostClassifier ouput should match XGBoost4j") {
|
test("XGBoost-Spark XGBoostClassifier output should match XGBoost4j") {
|
||||||
val trainingDM = new DMatrix(Classification.train.iterator)
|
val trainingDM = new DMatrix(Classification.train.iterator)
|
||||||
val testDM = new DMatrix(Classification.test.iterator)
|
val testDM = new DMatrix(Classification.test.iterator)
|
||||||
val trainingDF = buildDataFrame(Classification.train)
|
val trainingDF = buildDataFrame(Classification.train)
|
||||||
val testDF = buildDataFrame(Classification.test)
|
val testDF = buildDataFrame(Classification.test)
|
||||||
val round = 5
|
checkResultsWithXGBoost4j(trainingDM, testDM, trainingDF, testDF)
|
||||||
|
}
|
||||||
|
|
||||||
|
test("XGBoostClassifier should make correct predictions after upstream random sort") {
|
||||||
|
val trainingDM = new DMatrix(Classification.train.iterator)
|
||||||
|
val testDM = new DMatrix(Classification.test.iterator)
|
||||||
|
val trainingDF = buildDataFrameWithRandSort(Classification.train)
|
||||||
|
val testDF = buildDataFrameWithRandSort(Classification.test)
|
||||||
|
checkResultsWithXGBoost4j(trainingDM, testDM, trainingDF, testDF)
|
||||||
|
}
|
||||||
|
|
||||||
|
private def checkResultsWithXGBoost4j(
|
||||||
|
trainingDM: DMatrix,
|
||||||
|
testDM: DMatrix,
|
||||||
|
trainingDF: DataFrame,
|
||||||
|
testDF: DataFrame,
|
||||||
|
round: Int = 5): Unit = {
|
||||||
val paramMap = Map(
|
val paramMap = Map(
|
||||||
"eta" -> "1",
|
"eta" -> "1",
|
||||||
"max_depth" -> "6",
|
"max_depth" -> "6",
|
||||||
@@ -47,7 +62,7 @@ class XGBoostClassifierSuite extends FunSuite with PerTest {
|
|||||||
"num_workers" -> numWorkers)).fit(trainingDF)
|
"num_workers" -> numWorkers)).fit(trainingDF)
|
||||||
|
|
||||||
val prediction2 = model2.transform(testDF).
|
val prediction2 = model2.transform(testDF).
|
||||||
collect().map(row => (row.getAs[Int]("id"), row.getAs[DenseVector]("probability"))).toMap
|
collect().map(row => (row.getAs[Int]("id"), row.getAs[DenseVector]("probability"))).toMap
|
||||||
|
|
||||||
assert(testDF.count() === prediction2.size)
|
assert(testDF.count() === prediction2.size)
|
||||||
// the vector length in probability column is 2 since we have to fit to the evaluator in Spark
|
// the vector length in probability column is 2 since we have to fit to the evaluator in Spark
|
||||||
@@ -60,7 +75,7 @@ class XGBoostClassifierSuite extends FunSuite with PerTest {
|
|||||||
|
|
||||||
val prediction3 = model1.predict(testDM, outPutMargin = true)
|
val prediction3 = model1.predict(testDM, outPutMargin = true)
|
||||||
val prediction4 = model2.transform(testDF).
|
val prediction4 = model2.transform(testDF).
|
||||||
collect().map(row => (row.getAs[Int]("id"), row.getAs[DenseVector]("rawPrediction"))).toMap
|
collect().map(row => (row.getAs[Int]("id"), row.getAs[DenseVector]("rawPrediction"))).toMap
|
||||||
|
|
||||||
assert(testDF.count() === prediction4.size)
|
assert(testDF.count() === prediction4.size)
|
||||||
// the vector length in rawPrediction column is 2 since we have to fit to the evaluator in Spark
|
// the vector length in rawPrediction column is 2 since we have to fit to the evaluator in Spark
|
||||||
@@ -73,7 +88,9 @@ class XGBoostClassifierSuite extends FunSuite with PerTest {
|
|||||||
|
|
||||||
// check the equality of single instance prediction
|
// check the equality of single instance prediction
|
||||||
val firstOfDM = testDM.slice(Array(0))
|
val firstOfDM = testDM.slice(Array(0))
|
||||||
val firstOfDF = testDF.head().getAs[Vector]("features")
|
val firstOfDF = testDF.filter(_.getAs[Int]("id") == 0)
|
||||||
|
.head()
|
||||||
|
.getAs[Vector]("features")
|
||||||
val prediction5 = math.round(model1.predict(firstOfDM)(0)(0))
|
val prediction5 = math.round(model1.predict(firstOfDM)(0)(0))
|
||||||
val prediction6 = model2.predict(firstOfDF)
|
val prediction6 = model2.predict(firstOfDF)
|
||||||
assert(prediction5 === prediction6)
|
assert(prediction5 === prediction6)
|
||||||
@@ -270,7 +287,7 @@ class XGBoostClassifierSuite extends FunSuite with PerTest {
|
|||||||
test("infrequent features") {
|
test("infrequent features") {
|
||||||
val paramMap = Map("eta" -> "1", "max_depth" -> "6", "silent" -> "1",
|
val paramMap = Map("eta" -> "1", "max_depth" -> "6", "silent" -> "1",
|
||||||
"objective" -> "binary:logistic",
|
"objective" -> "binary:logistic",
|
||||||
"num_round" -> 5, "num_workers" -> 2)
|
"num_round" -> 5, "num_workers" -> 2, "missing" -> 0)
|
||||||
import DataUtils._
|
import DataUtils._
|
||||||
val sparkSession = SparkSession.builder().getOrCreate()
|
val sparkSession = SparkSession.builder().getOrCreate()
|
||||||
import sparkSession.implicits._
|
import sparkSession.implicits._
|
||||||
@@ -291,7 +308,7 @@ class XGBoostClassifierSuite extends FunSuite with PerTest {
|
|||||||
test("infrequent features (use_external_memory)") {
|
test("infrequent features (use_external_memory)") {
|
||||||
val paramMap = Map("eta" -> "1", "max_depth" -> "6", "silent" -> "1",
|
val paramMap = Map("eta" -> "1", "max_depth" -> "6", "silent" -> "1",
|
||||||
"objective" -> "binary:logistic",
|
"objective" -> "binary:logistic",
|
||||||
"num_round" -> 5, "num_workers" -> 2, "use_external_memory" -> true)
|
"num_round" -> 5, "num_workers" -> 2, "use_external_memory" -> true, "missing" -> 0)
|
||||||
import DataUtils._
|
import DataUtils._
|
||||||
val sparkSession = SparkSession.builder().getOrCreate()
|
val sparkSession = SparkSession.builder().getOrCreate()
|
||||||
import sparkSession.implicits._
|
import sparkSession.implicits._
|
||||||
|
|||||||
@@ -17,65 +17,17 @@
|
|||||||
package ml.dmlc.xgboost4j.scala.spark
|
package ml.dmlc.xgboost4j.scala.spark
|
||||||
|
|
||||||
import java.nio.file.Files
|
import java.nio.file.Files
|
||||||
import java.util.concurrent.LinkedBlockingDeque
|
|
||||||
|
|
||||||
import ml.dmlc.xgboost4j.{LabeledPoint => XGBLabeledPoint}
|
import ml.dmlc.xgboost4j.{LabeledPoint => XGBLabeledPoint}
|
||||||
import ml.dmlc.xgboost4j.scala.DMatrix
|
import ml.dmlc.xgboost4j.scala.DMatrix
|
||||||
import ml.dmlc.xgboost4j.scala.rabit.RabitTracker
|
|
||||||
import ml.dmlc.xgboost4j.scala.{XGBoost => SXGBoost, _}
|
import ml.dmlc.xgboost4j.scala.{XGBoost => SXGBoost, _}
|
||||||
import org.apache.hadoop.fs.{FileSystem, Path}
|
import org.apache.hadoop.fs.{FileSystem, Path}
|
||||||
|
|
||||||
import org.apache.spark.TaskContext
|
import org.apache.spark.TaskContext
|
||||||
import org.apache.spark.ml.linalg.Vectors
|
|
||||||
import org.apache.spark.sql._
|
|
||||||
import org.scalatest.FunSuite
|
import org.scalatest.FunSuite
|
||||||
import scala.util.Random
|
|
||||||
|
|
||||||
import ml.dmlc.xgboost4j.java.Rabit
|
|
||||||
|
|
||||||
class XGBoostGeneralSuite extends FunSuite with PerTest {
|
class XGBoostGeneralSuite extends FunSuite with PerTest {
|
||||||
|
|
||||||
test("test Rabit allreduce to validate Scala-implemented Rabit tracker") {
|
|
||||||
val vectorLength = 100
|
|
||||||
val rdd = sc.parallelize(
|
|
||||||
(1 to numWorkers * vectorLength).toArray.map { _ => Random.nextFloat() }, numWorkers).cache()
|
|
||||||
|
|
||||||
val tracker = new RabitTracker(numWorkers)
|
|
||||||
tracker.start(0)
|
|
||||||
val trackerEnvs = tracker.getWorkerEnvs
|
|
||||||
val collectedAllReduceResults = new LinkedBlockingDeque[Array[Float]]()
|
|
||||||
|
|
||||||
val rawData = rdd.mapPartitions { iter =>
|
|
||||||
Iterator(iter.toArray)
|
|
||||||
}.collect()
|
|
||||||
|
|
||||||
val maxVec = (0 until vectorLength).toArray.map { j =>
|
|
||||||
(0 until numWorkers).toArray.map { i => rawData(i)(j) }.max
|
|
||||||
}
|
|
||||||
|
|
||||||
val allReduceResults = rdd.mapPartitions { iter =>
|
|
||||||
Rabit.init(trackerEnvs)
|
|
||||||
val arr = iter.toArray
|
|
||||||
val results = Rabit.allReduce(arr, Rabit.OpType.MAX)
|
|
||||||
Rabit.shutdown()
|
|
||||||
Iterator(results)
|
|
||||||
}.cache()
|
|
||||||
|
|
||||||
val sparkThread = new Thread() {
|
|
||||||
override def run(): Unit = {
|
|
||||||
allReduceResults.foreachPartition(() => _)
|
|
||||||
val byPartitionResults = allReduceResults.collect()
|
|
||||||
assert(byPartitionResults(0).length == vectorLength)
|
|
||||||
collectedAllReduceResults.put(byPartitionResults(0))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sparkThread.start()
|
|
||||||
assert(tracker.waitFor(0L) == 0)
|
|
||||||
sparkThread.join()
|
|
||||||
|
|
||||||
assert(collectedAllReduceResults.poll().sameElements(maxVec))
|
|
||||||
}
|
|
||||||
|
|
||||||
test("distributed training with the specified worker number") {
|
test("distributed training with the specified worker number") {
|
||||||
val trainingRDD = sc.parallelize(Classification.train)
|
val trainingRDD = sc.parallelize(Classification.train)
|
||||||
val (booster, metrics) = XGBoost.trainDistributed(
|
val (booster, metrics) = XGBoost.trainDistributed(
|
||||||
@@ -99,18 +51,6 @@ class XGBoostGeneralSuite extends FunSuite with PerTest {
|
|||||||
assert(eval.eval(model._booster.predict(testDM, outPutMargin = true), testDM) < 0.1)
|
assert(eval.eval(model._booster.predict(testDM, outPutMargin = true), testDM) < 0.1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
test("training with Scala-implemented Rabit tracker") {
|
|
||||||
val eval = new EvalError()
|
|
||||||
val training = buildDataFrame(Classification.train)
|
|
||||||
val testDM = new DMatrix(Classification.test.iterator)
|
|
||||||
val paramMap = Map("eta" -> "1", "max_depth" -> "6",
|
|
||||||
"objective" -> "binary:logistic", "num_round" -> 5, "num_workers" -> numWorkers,
|
|
||||||
"tracker_conf" -> TrackerConf(60 * 60 * 1000, "scala"))
|
|
||||||
val model = new XGBoostClassifier(paramMap).fit(training)
|
|
||||||
assert(eval.eval(model._booster.predict(testDM, outPutMargin = true), testDM) < 0.1)
|
|
||||||
}
|
|
||||||
|
|
||||||
test("test with quantile hist with monotone_constraints (lossguide)") {
|
test("test with quantile hist with monotone_constraints (lossguide)") {
|
||||||
val eval = new EvalError()
|
val eval = new EvalError()
|
||||||
val training = buildDataFrame(Classification.train)
|
val training = buildDataFrame(Classification.train)
|
||||||
@@ -223,30 +163,6 @@ class XGBoostGeneralSuite extends FunSuite with PerTest {
|
|||||||
assert(x < 0.1)
|
assert(x < 0.1)
|
||||||
}
|
}
|
||||||
|
|
||||||
test("dense vectors containing missing value") {
|
|
||||||
def buildDenseDataFrame(): DataFrame = {
|
|
||||||
val numRows = 100
|
|
||||||
val numCols = 5
|
|
||||||
|
|
||||||
val data = (0 until numRows).map { x =>
|
|
||||||
val label = Random.nextInt(2)
|
|
||||||
val values = Array.tabulate[Double](numCols) { c =>
|
|
||||||
if (c == numCols - 1) -0.1 else Random.nextDouble
|
|
||||||
}
|
|
||||||
|
|
||||||
(label, Vectors.dense(values))
|
|
||||||
}
|
|
||||||
|
|
||||||
ss.createDataFrame(sc.parallelize(data.toList)).toDF("label", "features")
|
|
||||||
}
|
|
||||||
|
|
||||||
val denseDF = buildDenseDataFrame().repartition(4)
|
|
||||||
val paramMap = List("eta" -> "1", "max_depth" -> "2",
|
|
||||||
"objective" -> "binary:logistic", "missing" -> -0.1f, "num_workers" -> numWorkers).toMap
|
|
||||||
val model = new XGBoostClassifier(paramMap).fit(denseDF)
|
|
||||||
model.transform(denseDF).collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
test("training with spark parallelism checks disabled") {
|
test("training with spark parallelism checks disabled") {
|
||||||
val eval = new EvalError()
|
val eval = new EvalError()
|
||||||
val training = buildDataFrame(Classification.train)
|
val training = buildDataFrame(Classification.train)
|
||||||
@@ -286,6 +202,33 @@ class XGBoostGeneralSuite extends FunSuite with PerTest {
|
|||||||
assert(error(nextModel._booster) < 0.1)
|
assert(error(nextModel._booster) < 0.1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test("training with checkpoint boosters with cached training dataset") {
|
||||||
|
val eval = new EvalError()
|
||||||
|
val training = buildDataFrame(Classification.train)
|
||||||
|
val testDM = new DMatrix(Classification.test.iterator)
|
||||||
|
|
||||||
|
val tmpPath = Files.createTempDirectory("model1").toAbsolutePath.toString
|
||||||
|
val paramMap = Map("eta" -> "1", "max_depth" -> 2,
|
||||||
|
"objective" -> "binary:logistic", "checkpoint_path" -> tmpPath,
|
||||||
|
"checkpoint_interval" -> 2, "num_workers" -> numWorkers, "cacheTrainingSet" -> true)
|
||||||
|
|
||||||
|
val prevModel = new XGBoostClassifier(paramMap ++ Seq("num_round" -> 5)).fit(training)
|
||||||
|
def error(model: Booster): Float = eval.eval(
|
||||||
|
model.predict(testDM, outPutMargin = true), testDM)
|
||||||
|
|
||||||
|
// Check only one model is kept after training
|
||||||
|
val files = FileSystem.get(sc.hadoopConfiguration).listStatus(new Path(tmpPath))
|
||||||
|
assert(files.length == 1)
|
||||||
|
assert(files.head.getPath.getName == "8.model")
|
||||||
|
val tmpModel = SXGBoost.loadModel(s"$tmpPath/8.model")
|
||||||
|
|
||||||
|
// Train next model based on prev model
|
||||||
|
val nextModel = new XGBoostClassifier(paramMap ++ Seq("num_round" -> 8)).fit(training)
|
||||||
|
assert(error(tmpModel) > error(prevModel._booster))
|
||||||
|
assert(error(prevModel._booster) > error(nextModel._booster))
|
||||||
|
assert(error(nextModel._booster) < 0.1)
|
||||||
|
}
|
||||||
|
|
||||||
test("repartitionForTrainingGroup with group data") {
|
test("repartitionForTrainingGroup with group data") {
|
||||||
// test different splits to cover the corner cases.
|
// test different splits to cover the corner cases.
|
||||||
for (split <- 1 to 20) {
|
for (split <- 1 to 20) {
|
||||||
@@ -386,7 +329,7 @@ class XGBoostGeneralSuite extends FunSuite with PerTest {
|
|||||||
|
|
||||||
test("train with multiple validation datasets (ranking)") {
|
test("train with multiple validation datasets (ranking)") {
|
||||||
val training = buildDataFrameWithGroup(Ranking.train, 5)
|
val training = buildDataFrameWithGroup(Ranking.train, 5)
|
||||||
val Array(train, eval1, eval2) = training.randomSplit(Array(0.6, 0.2, 0.2))
|
val Array(train, eval1, eval2) = training.randomSplit(Array(0.6, 0.2, 0.2), 0)
|
||||||
val paramMap1 = Map("eta" -> "1", "max_depth" -> "6",
|
val paramMap1 = Map("eta" -> "1", "max_depth" -> "6",
|
||||||
"objective" -> "rank:pairwise",
|
"objective" -> "rank:pairwise",
|
||||||
"num_round" -> 5, "num_workers" -> numWorkers, "group_col" -> "group")
|
"num_round" -> 5, "num_workers" -> numWorkers, "group_col" -> "group")
|
||||||
@@ -414,4 +357,42 @@ class XGBoostGeneralSuite extends FunSuite with PerTest {
|
|||||||
assert(model2.summary.trainObjectiveHistory !== model2.summary.validationObjectiveHistory(0))
|
assert(model2.summary.trainObjectiveHistory !== model2.summary.validationObjectiveHistory(0))
|
||||||
assert(model2.summary.trainObjectiveHistory !== model2.summary.validationObjectiveHistory(1))
|
assert(model2.summary.trainObjectiveHistory !== model2.summary.validationObjectiveHistory(1))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test("infer with different batch sizes") {
|
||||||
|
val regModel = new XGBoostRegressor(Map(
|
||||||
|
"eta" -> "1",
|
||||||
|
"max_depth" -> "6",
|
||||||
|
"silent" -> "1",
|
||||||
|
"objective" -> "reg:squarederror",
|
||||||
|
"num_round" -> 5,
|
||||||
|
"num_workers" -> numWorkers))
|
||||||
|
.fit(buildDataFrame(Regression.train))
|
||||||
|
val regDF = buildDataFrame(Regression.test)
|
||||||
|
|
||||||
|
val regRet1 = regModel.transform(regDF).collect()
|
||||||
|
val regRet2 = regModel.setInferBatchSize(1).transform(regDF).collect()
|
||||||
|
val regRet3 = regModel.setInferBatchSize(10).transform(regDF).collect()
|
||||||
|
val regRet4 = regModel.setInferBatchSize(32 << 15).transform(regDF).collect()
|
||||||
|
assert(regRet1 sameElements regRet2)
|
||||||
|
assert(regRet1 sameElements regRet3)
|
||||||
|
assert(regRet1 sameElements regRet4)
|
||||||
|
|
||||||
|
val clsModel = new XGBoostClassifier(Map(
|
||||||
|
"eta" -> "1",
|
||||||
|
"max_depth" -> "6",
|
||||||
|
"silent" -> "1",
|
||||||
|
"objective" -> "binary:logistic",
|
||||||
|
"num_round" -> 5,
|
||||||
|
"num_workers" -> numWorkers))
|
||||||
|
.fit(buildDataFrame(Classification.train))
|
||||||
|
val clsDF = buildDataFrame(Classification.test)
|
||||||
|
|
||||||
|
val clsRet1 = clsModel.transform(clsDF).collect()
|
||||||
|
val clsRet2 = clsModel.setInferBatchSize(1).transform(clsDF).collect()
|
||||||
|
val clsRet3 = clsModel.setInferBatchSize(10).transform(clsDF).collect()
|
||||||
|
val clsRet4 = clsModel.setInferBatchSize(32 << 15).transform(clsDF).collect()
|
||||||
|
assert(clsRet1 sameElements clsRet2)
|
||||||
|
assert(clsRet1 sameElements clsRet3)
|
||||||
|
assert(clsRet1 sameElements clsRet4)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,24 +19,39 @@ package ml.dmlc.xgboost4j.scala.spark
|
|||||||
import ml.dmlc.xgboost4j.scala.{DMatrix, XGBoost => ScalaXGBoost}
|
import ml.dmlc.xgboost4j.scala.{DMatrix, XGBoost => ScalaXGBoost}
|
||||||
import org.apache.spark.ml.linalg.Vector
|
import org.apache.spark.ml.linalg.Vector
|
||||||
import org.apache.spark.sql.functions._
|
import org.apache.spark.sql.functions._
|
||||||
import org.apache.spark.sql.Row
|
import org.apache.spark.sql.{DataFrame, Row}
|
||||||
import org.apache.spark.sql.types._
|
import org.apache.spark.sql.types._
|
||||||
import org.scalatest.FunSuite
|
import org.scalatest.FunSuite
|
||||||
|
|
||||||
class XGBoostRegressorSuite extends FunSuite with PerTest {
|
class XGBoostRegressorSuite extends FunSuite with PerTest {
|
||||||
|
|
||||||
test("XGBoost-Spark XGBoostRegressor ouput should match XGBoost4j: regression") {
|
test("XGBoost-Spark XGBoostRegressor output should match XGBoost4j") {
|
||||||
val trainingDM = new DMatrix(Regression.train.iterator)
|
val trainingDM = new DMatrix(Regression.train.iterator)
|
||||||
val testDM = new DMatrix(Regression.test.iterator)
|
val testDM = new DMatrix(Regression.test.iterator)
|
||||||
val trainingDF = buildDataFrame(Regression.train)
|
val trainingDF = buildDataFrame(Regression.train)
|
||||||
val testDF = buildDataFrame(Regression.test)
|
val testDF = buildDataFrame(Regression.test)
|
||||||
val round = 5
|
checkResultsWithXGBoost4j(trainingDM, testDM, trainingDF, testDF)
|
||||||
|
}
|
||||||
|
|
||||||
|
test("XGBoostRegressor should make correct predictions after upstream random sort") {
|
||||||
|
val trainingDM = new DMatrix(Regression.train.iterator)
|
||||||
|
val testDM = new DMatrix(Regression.test.iterator)
|
||||||
|
val trainingDF = buildDataFrameWithRandSort(Regression.train)
|
||||||
|
val testDF = buildDataFrameWithRandSort(Regression.test)
|
||||||
|
checkResultsWithXGBoost4j(trainingDM, testDM, trainingDF, testDF)
|
||||||
|
}
|
||||||
|
|
||||||
|
private def checkResultsWithXGBoost4j(
|
||||||
|
trainingDM: DMatrix,
|
||||||
|
testDM: DMatrix,
|
||||||
|
trainingDF: DataFrame,
|
||||||
|
testDF: DataFrame,
|
||||||
|
round: Int = 5): Unit = {
|
||||||
val paramMap = Map(
|
val paramMap = Map(
|
||||||
"eta" -> "1",
|
"eta" -> "1",
|
||||||
"max_depth" -> "6",
|
"max_depth" -> "6",
|
||||||
"silent" -> "1",
|
"silent" -> "1",
|
||||||
"objective" -> "reg:linear")
|
"objective" -> "reg:squarederror")
|
||||||
|
|
||||||
val model1 = ScalaXGBoost.train(trainingDM, paramMap, round)
|
val model1 = ScalaXGBoost.train(trainingDM, paramMap, round)
|
||||||
val prediction1 = model1.predict(testDM)
|
val prediction1 = model1.predict(testDM)
|
||||||
@@ -45,7 +60,7 @@ class XGBoostRegressorSuite extends FunSuite with PerTest {
|
|||||||
"num_workers" -> numWorkers)).fit(trainingDF)
|
"num_workers" -> numWorkers)).fit(trainingDF)
|
||||||
|
|
||||||
val prediction2 = model2.transform(testDF).
|
val prediction2 = model2.transform(testDF).
|
||||||
collect().map(row => (row.getAs[Int]("id"), row.getAs[Double]("prediction"))).toMap
|
collect().map(row => (row.getAs[Int]("id"), row.getAs[Double]("prediction"))).toMap
|
||||||
|
|
||||||
assert(prediction1.indices.count { i =>
|
assert(prediction1.indices.count { i =>
|
||||||
math.abs(prediction1(i)(0) - prediction2(i)) > 0.01
|
math.abs(prediction1(i)(0) - prediction2(i)) > 0.01
|
||||||
@@ -54,7 +69,9 @@ class XGBoostRegressorSuite extends FunSuite with PerTest {
|
|||||||
|
|
||||||
// check the equality of single instance prediction
|
// check the equality of single instance prediction
|
||||||
val firstOfDM = testDM.slice(Array(0))
|
val firstOfDM = testDM.slice(Array(0))
|
||||||
val firstOfDF = testDF.head().getAs[Vector]("features")
|
val firstOfDF = testDF.filter(_.getAs[Int]("id") == 0)
|
||||||
|
.head()
|
||||||
|
.getAs[Vector]("features")
|
||||||
val prediction3 = model1.predict(firstOfDM)(0)(0)
|
val prediction3 = model1.predict(firstOfDM)(0)(0)
|
||||||
val prediction4 = model2.predict(firstOfDF)
|
val prediction4 = model2.predict(firstOfDF)
|
||||||
assert(math.abs(prediction3 - prediction4) <= 0.01f)
|
assert(math.abs(prediction3 - prediction4) <= 0.01f)
|
||||||
@@ -69,7 +86,7 @@ class XGBoostRegressorSuite extends FunSuite with PerTest {
|
|||||||
"eta" -> "1",
|
"eta" -> "1",
|
||||||
"max_depth" -> "6",
|
"max_depth" -> "6",
|
||||||
"silent" -> "1",
|
"silent" -> "1",
|
||||||
"objective" -> "reg:linear",
|
"objective" -> "reg:squarederror",
|
||||||
"num_round" -> round,
|
"num_round" -> round,
|
||||||
"num_workers" -> numWorkers)
|
"num_workers" -> numWorkers)
|
||||||
|
|
||||||
@@ -80,7 +97,7 @@ class XGBoostRegressorSuite extends FunSuite with PerTest {
|
|||||||
.setEta(1)
|
.setEta(1)
|
||||||
.setMaxDepth(6)
|
.setMaxDepth(6)
|
||||||
.setSilent(1)
|
.setSilent(1)
|
||||||
.setObjective("reg:linear")
|
.setObjective("reg:squarederror")
|
||||||
.setNumRound(round)
|
.setNumRound(round)
|
||||||
.setNumWorkers(numWorkers)
|
.setNumWorkers(numWorkers)
|
||||||
.fit(trainingDF)
|
.fit(trainingDF)
|
||||||
@@ -108,7 +125,7 @@ class XGBoostRegressorSuite extends FunSuite with PerTest {
|
|||||||
|
|
||||||
test("use weight") {
|
test("use weight") {
|
||||||
val paramMap = Map("eta" -> "1", "max_depth" -> "6", "silent" -> "1",
|
val paramMap = Map("eta" -> "1", "max_depth" -> "6", "silent" -> "1",
|
||||||
"objective" -> "reg:linear", "num_round" -> 5, "num_workers" -> numWorkers)
|
"objective" -> "reg:squarederror", "num_round" -> 5, "num_workers" -> numWorkers)
|
||||||
|
|
||||||
val getWeightFromId = udf({id: Int => if (id == 0) 1.0f else 0.001f}, DataTypes.FloatType)
|
val getWeightFromId = udf({id: Int => if (id == 0) 1.0f else 0.001f}, DataTypes.FloatType)
|
||||||
val trainingDF = buildDataFrame(Regression.train)
|
val trainingDF = buildDataFrame(Regression.train)
|
||||||
@@ -123,7 +140,7 @@ class XGBoostRegressorSuite extends FunSuite with PerTest {
|
|||||||
|
|
||||||
test("test predictionLeaf") {
|
test("test predictionLeaf") {
|
||||||
val paramMap = Map("eta" -> "1", "max_depth" -> "6", "silent" -> "1",
|
val paramMap = Map("eta" -> "1", "max_depth" -> "6", "silent" -> "1",
|
||||||
"objective" -> "reg:linear", "num_round" -> 5, "num_workers" -> numWorkers)
|
"objective" -> "reg:squarederror", "num_round" -> 5, "num_workers" -> numWorkers)
|
||||||
val training = buildDataFrame(Regression.train)
|
val training = buildDataFrame(Regression.train)
|
||||||
val testDF = buildDataFrame(Regression.test)
|
val testDF = buildDataFrame(Regression.test)
|
||||||
val groundTruth = testDF.count()
|
val groundTruth = testDF.count()
|
||||||
@@ -137,7 +154,7 @@ class XGBoostRegressorSuite extends FunSuite with PerTest {
|
|||||||
|
|
||||||
test("test predictionLeaf with empty column name") {
|
test("test predictionLeaf with empty column name") {
|
||||||
val paramMap = Map("eta" -> "1", "max_depth" -> "6", "silent" -> "1",
|
val paramMap = Map("eta" -> "1", "max_depth" -> "6", "silent" -> "1",
|
||||||
"objective" -> "reg:linear", "num_round" -> 5, "num_workers" -> numWorkers)
|
"objective" -> "reg:squarederror", "num_round" -> 5, "num_workers" -> numWorkers)
|
||||||
val training = buildDataFrame(Regression.train)
|
val training = buildDataFrame(Regression.train)
|
||||||
val testDF = buildDataFrame(Regression.test)
|
val testDF = buildDataFrame(Regression.test)
|
||||||
val xgb = new XGBoostRegressor(paramMap)
|
val xgb = new XGBoostRegressor(paramMap)
|
||||||
@@ -149,7 +166,7 @@ class XGBoostRegressorSuite extends FunSuite with PerTest {
|
|||||||
|
|
||||||
test("test predictionContrib") {
|
test("test predictionContrib") {
|
||||||
val paramMap = Map("eta" -> "1", "max_depth" -> "6", "silent" -> "1",
|
val paramMap = Map("eta" -> "1", "max_depth" -> "6", "silent" -> "1",
|
||||||
"objective" -> "reg:linear", "num_round" -> 5, "num_workers" -> numWorkers)
|
"objective" -> "reg:squarederror", "num_round" -> 5, "num_workers" -> numWorkers)
|
||||||
val training = buildDataFrame(Regression.train)
|
val training = buildDataFrame(Regression.train)
|
||||||
val testDF = buildDataFrame(Regression.test)
|
val testDF = buildDataFrame(Regression.test)
|
||||||
val groundTruth = testDF.count()
|
val groundTruth = testDF.count()
|
||||||
@@ -163,7 +180,7 @@ class XGBoostRegressorSuite extends FunSuite with PerTest {
|
|||||||
|
|
||||||
test("test predictionContrib with empty column name") {
|
test("test predictionContrib with empty column name") {
|
||||||
val paramMap = Map("eta" -> "1", "max_depth" -> "6", "silent" -> "1",
|
val paramMap = Map("eta" -> "1", "max_depth" -> "6", "silent" -> "1",
|
||||||
"objective" -> "reg:linear", "num_round" -> 5, "num_workers" -> numWorkers)
|
"objective" -> "reg:squarederror", "num_round" -> 5, "num_workers" -> numWorkers)
|
||||||
val training = buildDataFrame(Regression.train)
|
val training = buildDataFrame(Regression.train)
|
||||||
val testDF = buildDataFrame(Regression.test)
|
val testDF = buildDataFrame(Regression.test)
|
||||||
val xgb = new XGBoostRegressor(paramMap)
|
val xgb = new XGBoostRegressor(paramMap)
|
||||||
@@ -175,7 +192,7 @@ class XGBoostRegressorSuite extends FunSuite with PerTest {
|
|||||||
|
|
||||||
test("test predictionLeaf and predictionContrib") {
|
test("test predictionLeaf and predictionContrib") {
|
||||||
val paramMap = Map("eta" -> "1", "max_depth" -> "6", "silent" -> "1",
|
val paramMap = Map("eta" -> "1", "max_depth" -> "6", "silent" -> "1",
|
||||||
"objective" -> "reg:linear", "num_round" -> 5, "num_workers" -> numWorkers)
|
"objective" -> "reg:squarederror", "num_round" -> 5, "num_workers" -> numWorkers)
|
||||||
val training = buildDataFrame(Regression.train)
|
val training = buildDataFrame(Regression.train)
|
||||||
val testDF = buildDataFrame(Regression.test)
|
val testDF = buildDataFrame(Regression.test)
|
||||||
val groundTruth = testDF.count()
|
val groundTruth = testDF.count()
|
||||||
|
|||||||
208
jvm-packages/xgboost4j-tester/generate_pom.py
Normal file
208
jvm-packages/xgboost4j-tester/generate_pom.py
Normal file
@@ -0,0 +1,208 @@
|
|||||||
|
import sys
|
||||||
|
|
||||||
|
pom_template = """
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<groupId>ml.dmlc</groupId>
|
||||||
|
<artifactId>xgboost4j-tester</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
|
||||||
|
<name>xgboost4j-tester</name>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
<maven.compiler.source>{maven_compiler_source}</maven.compiler.source>
|
||||||
|
<maven.compiler.target>{maven_compiler_target}</maven.compiler.target>
|
||||||
|
<spark.version>{spark_version}</spark.version>
|
||||||
|
<scala.version>{scala_version}</scala.version>
|
||||||
|
<scala.binary.version>{scala_binary_version}</scala.binary.version>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.esotericsoftware.kryo</groupId>
|
||||||
|
<artifactId>kryo</artifactId>
|
||||||
|
<version>2.21</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.scala-lang</groupId>
|
||||||
|
<artifactId>scala-compiler</artifactId>
|
||||||
|
<version>${{scala.version}}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.scala-lang</groupId>
|
||||||
|
<artifactId>scala-reflect</artifactId>
|
||||||
|
<version>${{scala.version}}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.scala-lang</groupId>
|
||||||
|
<artifactId>scala-library</artifactId>
|
||||||
|
<version>${{scala.version}}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>commons-logging</groupId>
|
||||||
|
<artifactId>commons-logging</artifactId>
|
||||||
|
<version>1.2</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.typesafe.akka</groupId>
|
||||||
|
<artifactId>akka-actor_${{scala.binary.version}}</artifactId>
|
||||||
|
<version>2.3.11</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.typesafe.akka</groupId>
|
||||||
|
<artifactId>akka-testkit_${{scala.binary.version}}</artifactId>
|
||||||
|
<version>2.3.11</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.scalatest</groupId>
|
||||||
|
<artifactId>scalatest_${{scala.binary.version}}</artifactId>
|
||||||
|
<version>3.0.0</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.commons</groupId>
|
||||||
|
<artifactId>commons-lang3</artifactId>
|
||||||
|
<version>3.4</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.spark</groupId>
|
||||||
|
<artifactId>spark-core_${{scala.binary.version}}</artifactId>
|
||||||
|
<version>${{spark.version}}</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.spark</groupId>
|
||||||
|
<artifactId>spark-sql_${{scala.binary.version}}</artifactId>
|
||||||
|
<version>${{spark.version}}</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.spark</groupId>
|
||||||
|
<artifactId>spark-mllib_${{scala.binary.version}}</artifactId>
|
||||||
|
<version>${{spark.version}}</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>junit</groupId>
|
||||||
|
<artifactId>junit</artifactId>
|
||||||
|
<version>4.11</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ml.dmlc</groupId>
|
||||||
|
<artifactId>xgboost4j</artifactId>
|
||||||
|
<version>{xgboost4j_version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ml.dmlc</groupId>
|
||||||
|
<artifactId>xgboost4j</artifactId>
|
||||||
|
<version>{xgboost4j_version}</version>
|
||||||
|
<classifier>tests</classifier>
|
||||||
|
<type>test-jar</type>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ml.dmlc</groupId>
|
||||||
|
<artifactId>xgboost4j-spark</artifactId>
|
||||||
|
<version>{xgboost4j_version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ml.dmlc</groupId>
|
||||||
|
<artifactId>xgboost4j-example</artifactId>
|
||||||
|
<version>{xgboost4j_version}</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-clean-plugin</artifactId>
|
||||||
|
<version>3.1.0</version>
|
||||||
|
</plugin>
|
||||||
|
<!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-resources-plugin</artifactId>
|
||||||
|
<version>3.0.2</version>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>3.8.0</version>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-jar-plugin</artifactId>
|
||||||
|
<version>3.0.2</version>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-install-plugin</artifactId>
|
||||||
|
<version>2.5.2</version>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-deploy-plugin</artifactId>
|
||||||
|
<version>2.8.2</version>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-assembly-plugin</artifactId>
|
||||||
|
<version>2.4</version>
|
||||||
|
<configuration>
|
||||||
|
<descriptorRefs>
|
||||||
|
<descriptorRef>jar-with-dependencies</descriptorRef>
|
||||||
|
</descriptorRefs>
|
||||||
|
<archive>
|
||||||
|
<manifest>
|
||||||
|
<mainClass>ml.dmlc.xgboost4j.tester.App</mainClass>
|
||||||
|
</manifest>
|
||||||
|
</archive>
|
||||||
|
</configuration>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<phase>package</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>single</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
<!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-site-plugin</artifactId>
|
||||||
|
<version>3.7.1</version>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-project-info-reports-plugin</artifactId>
|
||||||
|
<version>3.0.0</version>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
|
<version>2.22.1</version>
|
||||||
|
<configuration>
|
||||||
|
<dependenciesToScan>
|
||||||
|
<dependency>ml.dmlc:xgboost4j</dependency>
|
||||||
|
</dependenciesToScan>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</project>
|
||||||
|
"""
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
if len(sys.argv) != 7:
|
||||||
|
print('Usage: {} [xgboost4j version] [maven compiler source level] [maven compiler target level] [spark version] [scala version] [scala binary version]'.format(sys.argv[0]))
|
||||||
|
sys.exit(1)
|
||||||
|
with open('pom.xml', 'w') as f:
|
||||||
|
print(pom_template.format(xgboost4j_version=sys.argv[1],
|
||||||
|
maven_compiler_source=sys.argv[2],
|
||||||
|
maven_compiler_target=sys.argv[3],
|
||||||
|
spark_version=sys.argv[4],
|
||||||
|
scala_version=sys.argv[5],
|
||||||
|
scala_binary_version=sys.argv[6]), file=f)
|
||||||
10
jvm-packages/xgboost4j-tester/get_iris.py
Normal file
10
jvm-packages/xgboost4j-tester/get_iris.py
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
from sklearn.datasets import load_iris
|
||||||
|
import numpy as np
|
||||||
|
import pandas
|
||||||
|
|
||||||
|
X, y = load_iris(return_X_y=True)
|
||||||
|
y = y.astype(np.int)
|
||||||
|
df = pandas.DataFrame(data=X, columns=['sepal length', 'sepal width', 'petal length', 'petal width'])
|
||||||
|
class_id_to_name = {0:'Iris-setosa', 1:'Iris-versicolor', 2:'Iris-virginica'}
|
||||||
|
df['class'] = np.vectorize(class_id_to_name.get)(y)
|
||||||
|
df.to_csv('./iris.csv', float_format='%.1f', header=False, index=False)
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user