Merge branch 'master' of https://github.com/mlpack/mlpack into access_models
This commit is contained in:
-219
@@ -1,219 +0,0 @@
|
||||
clone_depth: 10
|
||||
|
||||
environment:
|
||||
BOOST_MATH : "C:/projects/mlpack/\
|
||||
boost_math_c99-vc140.1.60.0.0/lib/native/address-model-64/lib/*.*"
|
||||
BOOST_RANDOM : "C:/projects/mlpack/\
|
||||
boost_random-vc140.1.60.0.0/lib/native/address-model-64/lib/*.*"
|
||||
ARMADILLO_DOWNLOAD : "https://data.kurg.org/armadillo-8.400.0.tar.xz"
|
||||
ARMADILLO_LIBRARY : "C:/projects/mlpack/armadillo-8.400.0/\
|
||||
build/Debug/armadillo.lib"
|
||||
BLAS_LIBRARY : "%APPVEYOR_BUILD_FOLDER%/OpenBLAS.0.2.14.1/lib/native/lib/x64/\
|
||||
libopenblas.dll.a"
|
||||
BOOST_INCLUDE : "C:/projects/mlpack/boost.1.60.0.0/lib/native/include"
|
||||
JENKINS_DOC_DOWNLOAD : "http://ci.mlpack.org/job/mlpack%20-%20doxygen%20\
|
||||
build/lastSuccessfulBuild/artifact/build/doc/html/*zip*/html.zip"
|
||||
JENKINS_DOC : "C:/projects/mlpack/dist/win-installer/jenkinsdoc.zip"
|
||||
GIT_VERSION_FILE : "C:/projects/mlpack/src/mlpack/core/util/gitversion.hpp"
|
||||
matrix:
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
||||
VSVER: Visual Studio 16 2019
|
||||
MSBUILD: C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\MSBuild.exe
|
||||
|
||||
# We have removed the VS studio 15 2017 build since it is not possible to complete
|
||||
# or finish the build due to the `compiler out of heap space issues`.
|
||||
# Therefore, in the meanwhile, we are only doing the installation for VS 16 2019.
|
||||
|
||||
configuration: Release
|
||||
|
||||
os: Visual Studio 2019
|
||||
|
||||
install:
|
||||
- ps: nuget install boost -o "${env:APPVEYOR_BUILD_FOLDER}" -Version 1.60.0
|
||||
- ps: >
|
||||
nuget install boost_random-vc140
|
||||
-o "${env:APPVEYOR_BUILD_FOLDER}" -Version 1.60.0
|
||||
- ps: >
|
||||
nuget install boost_math_c99-vc140
|
||||
-o "${env:APPVEYOR_BUILD_FOLDER}" -Version 1.60.0
|
||||
- ps: >
|
||||
nuget install unofficial-flayan-cereal
|
||||
-o "${env:APPVEYOR_BUILD_FOLDER}"
|
||||
- ps: nuget install OpenBLAS -o "${env:APPVEYOR_BUILD_FOLDER}"
|
||||
- set path=C:\Program Files (x86)\WiX Toolset v3.11\bin;%path%
|
||||
|
||||
build_script:
|
||||
- mkdir boost_libs
|
||||
- ps: cp ${env:BOOST_MATH} C:\projects\mlpack\boost_libs\
|
||||
- ps: cp ${env:BOOST_RANDOM} C:\projects\mlpack\boost_libs\
|
||||
- echo TEST_ARMA is %ARMADILLO_DOWNLOAD%
|
||||
- >
|
||||
appveyor DownloadFile %ARMADILLO_DOWNLOAD%
|
||||
-FileName armadillo.tar.xz
|
||||
- 7z x armadillo.tar.xz -so -txz | 7z x -si -ttar > nul
|
||||
- cd armadillo-8.400.0 && mkdir build && cd build
|
||||
- >
|
||||
cmake -G "%VSVER%"
|
||||
-DBLAS_LIBRARY:FILEPATH=%BLAS_LIBRARY%
|
||||
-DLAPACK_LIBRARY:FILEPATH=%BLAS_LIBRARY%
|
||||
-DCMAKE_PREFIX:FILEPATH="%APPVEYOR_BUILD_FOLDER%/armadillo"
|
||||
-DBUILD_SHARED_LIBS=OFF
|
||||
-DCMAKE_BUILD_TYPE=Release ..
|
||||
- >
|
||||
"%MSBUILD%" "C:\projects\mlpack\armadillo-8.400.0\build\armadillo.sln"
|
||||
/m /verbosity:quiet /p:Configuration=Release;Platform=x64
|
||||
- cd C:\projects\mlpack && mkdir build && cd build
|
||||
- >
|
||||
cmake -G "%VSVER%"
|
||||
-DBLAS_LIBRARIES:FILEPATH=%BLAS_LIBRARY%
|
||||
-DLAPACK_LIBRARIES:FILEPATH=%BLAS_LIBRARY%
|
||||
-DARMADILLO_INCLUDE_DIR="C:/projects/mlpack/armadillo-8.400.0/include"
|
||||
-DARMADILLO_LIBRARY:FILEPATH=%ARMADILLO_LIBRARY%
|
||||
-DCEREAL_INCLUDE_DIR="C:/projects/mlpack/unofficial-flayan-cereal.1.2.2/build/native/include"
|
||||
-DBOOST_INCLUDEDIR:PATH=%BOOST_INCLUDE%
|
||||
-DDEBUG=OFF
|
||||
-DPROFILE=OFF
|
||||
-DBUILD_PYTHON_BINDINGS=OFF
|
||||
-DBUILD_GO_BINDINGS=OFF
|
||||
-DBUILD_R_BINDINGS=OFF
|
||||
-DBUILD_TESTS=OFF
|
||||
-DCMAKE_BUILD_TYPE=Release ..
|
||||
- >
|
||||
"%MSBUILD%" "C:\projects\mlpack\build\mlpack.sln"
|
||||
/m /verbosity:minimal /nologo /p:BuildInParallel=true
|
||||
/p:Configuration=Release;Platform=x64
|
||||
|
||||
# Zip Artifacts.
|
||||
- >
|
||||
7z a mlpack-windows-no-libs.zip
|
||||
"%APPVEYOR_BUILD_FOLDER%\build\Release\*.exe"
|
||||
- >
|
||||
7z a mlpack-windows.zip
|
||||
"%APPVEYOR_BUILD_FOLDER%\build\Release\*.*"
|
||||
"%APPVEYOR_BUILD_FOLDER%/OpenBLAS.0.2.14.1/lib/native/lib/x64/*.*"
|
||||
|
||||
# Pulling documentation for the installer.
|
||||
- ps: >
|
||||
try{(new-object net.webclient).DownloadFile(${env:JENKINS_DOC_DOWNLOAD},
|
||||
'C:\projects\mlpack\dist\win-installer\jenkinsdoc.zip')}
|
||||
catch{Write-Output "Unable to pull jenkins doc, skipping!"}
|
||||
- ps: >
|
||||
try{(Add-Type -AssemblyName System.IO.Compression.FileSystem);
|
||||
[System.IO.Compression.ZipFile]::ExtractToDirectory(${env:JENKINS_DOC},
|
||||
'C:\projects\mlpack\dist\win-installer\staging\doc')}
|
||||
catch{Write-Output "Unable to add doc to installer, skipping!"}
|
||||
|
||||
# Preparing installer staging.
|
||||
- cd C:\projects\mlpack\dist\win-installer\staging && mkdir lib
|
||||
- ps: >
|
||||
cp C:\projects\mlpack\build\Release\*.lib
|
||||
C:\projects\mlpack\dist\win-installer\staging\lib\
|
||||
- ps: >
|
||||
cp C:\projects\mlpack\build\Release\*.exp
|
||||
C:\projects\mlpack\dist\win-installer\staging\lib\
|
||||
- ps: >
|
||||
cp C:\projects\mlpack\build\Release\*.dll
|
||||
C:\projects\mlpack\dist\win-installer\staging\
|
||||
- ps: >
|
||||
cp C:\projects\mlpack\build\Release\*.exe
|
||||
C:\projects\mlpack\dist\win-installer\staging\
|
||||
- ps: >
|
||||
cp C:\projects\mlpack\OpenBLAS.0.2.14.1\lib\native\bin\x64\*.dll
|
||||
C:\projects\mlpack\dist\win-installer\staging\
|
||||
- ps: >
|
||||
cp C:\projects\mlpack\build\include\mlpack
|
||||
C:\projects\mlpack\dist\win-installer\staging -recurse
|
||||
- ps: >
|
||||
cp C:\projects\mlpack\doc\examples
|
||||
C:\projects\mlpack\dist\win-installer\staging -recurse
|
||||
- ps: >
|
||||
cp C:\projects\mlpack\src\mlpack\tests\data\german.csv
|
||||
C:\projects\mlpack\dist\win-installer\staging\examples\sample-ml-app\sample-ml-app\data\
|
||||
|
||||
# Checking current gitversion or mlpack version.
|
||||
- ps: >
|
||||
$ver = (Get-Content
|
||||
"${env:APPVEYOR_BUILD_FOLDER}\src\mlpack\core\util\version.hpp" |
|
||||
where {$_ -like "*MLPACK_VERSION*"});
|
||||
$env:MLPACK_VERSION += $ver[0].substring($ver[0].length - 1, 1) + '.';
|
||||
$env:MLPACK_VERSION += $ver[1].substring($ver[1].length - 1, 1) + '.';
|
||||
$env:MLPACK_VERSION += $ver[2].substring($ver[2].length - 1, 1);
|
||||
|
||||
if (Test-Path ${env:GIT_VERSION_FILE})
|
||||
{
|
||||
$ver = (Get-Content ${env:GIT_VERSION_FILE});
|
||||
$env:INSTALL_VERSION = $ver.Split('"')[1].Split(' ')[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
$env:INSTALL_VERSION = $env:MLPACK_VERSION;
|
||||
}
|
||||
- echo INSTALL_VERSION is %INSTALL_VERSION%
|
||||
|
||||
# Building MSI installer.
|
||||
- cd C:\projects\mlpack\dist\win-installer\mlpack-win-installer
|
||||
- >
|
||||
heat dir ..\staging
|
||||
-cg HeatGenerated
|
||||
-dr INSTALLFOLDER
|
||||
-sreg
|
||||
-srd
|
||||
-var var.HarvestPath
|
||||
-ag
|
||||
-sfrag
|
||||
-out HeatGeneratedFileList.wxs
|
||||
- >
|
||||
candle -dHarvestPath=..\staging
|
||||
-dConfiguration=Release
|
||||
-dOutDir=bin\x64\Release\
|
||||
-dPlatform=x64
|
||||
-dProjectDir=.
|
||||
-dProjectExt=.wixproj
|
||||
-dProjectFileName=mlpack-win-installer.wixproj
|
||||
-dProjectName=mlpack-win-installer
|
||||
-dProjectPath=mlpack-win-installer.wixproj
|
||||
-dTargetDir=.\bin\x64\Release\
|
||||
-dTargetExt=.msi
|
||||
-dTargetFileName=mlpack-windows.msi
|
||||
-dTargetName=mlpack-windows
|
||||
-dTargetPath=.\bin\x64\Release\mlpack-windows.msi
|
||||
-out obj\x64\Release\
|
||||
-arch x64
|
||||
-ext "C:\Program Files (x86)\WiX Toolset v3.11\bin\\WixUIExtension.dll"
|
||||
Product.wxs HeatGeneratedFileList.wxs
|
||||
- >
|
||||
light -out .\bin\x64\Release\mlpack-%INSTALL_VERSION%.msi
|
||||
-pdbout .\bin\x64\Release\mlpack-windows.wixpdb
|
||||
-cultures:null
|
||||
-loc mlpack-localization.wxl
|
||||
-ext "C:\Program Files (x86)\WiX Toolset v3.11\bin\\WixUIExtension.dll"
|
||||
-contentsfile
|
||||
obj\x64\Release\mlpack-win-installer.wixproj.BindContentsFileListnull.txt
|
||||
-outputsfile
|
||||
obj\x64\Release\mlpack-win-installer.wixproj.BindOutputsFileListnull.txt
|
||||
-builtoutputsfile
|
||||
obj\x64\Release\mlpack-win-installer.wixproj.BindBuiltOutputsFileListnull.txt
|
||||
-wixprojectfile
|
||||
mlpack-win-installer.wixproj
|
||||
obj\x64\Release\Product.wixobj
|
||||
obj\x64\Release\HeatGeneratedFileList.wixobj
|
||||
|
||||
artifacts:
|
||||
- path: 'build\*.zip'
|
||||
name: mlpack-windows-zip
|
||||
|
||||
- path: 'dist\win-installer\mlpack-win-installer\bin\x64\Release\*.msi'
|
||||
name: mlpack-windows-installer
|
||||
|
||||
notifications:
|
||||
- provider: Email
|
||||
to:
|
||||
- mlpack-git@lists.mlpack.org
|
||||
on_build_success: true
|
||||
on_build_failure: true
|
||||
on_build_status_changed: true
|
||||
|
||||
cache:
|
||||
- packages -> **\packages.config
|
||||
- armadillo.tar.xz -> appveyor.yaml
|
||||
|
||||
@@ -1,110 +0,0 @@
|
||||
# This module looks for mex, the MATLAB compiler.
|
||||
# The following variables are defined when the script completes:
|
||||
# MATLAB_MEX: location of mex compiler
|
||||
# MATLAB_ROOT: root of MATLAB installation
|
||||
# MATLABMEX_FOUND: 0 if not found, 1 if found
|
||||
|
||||
set(MATLABMEX_FOUND 0)
|
||||
|
||||
if(WIN32)
|
||||
# This is untested but taken from the older FindMatlab.cmake script as well as
|
||||
# the modifications by Ramon Casero and Tom Doel for Gerardus.
|
||||
|
||||
# Search for a version of Matlab available, starting from the most modern one
|
||||
# to older versions.
|
||||
foreach(MATVER "7.20" "7.19" "7.18" "7.17" "7.16" "7.15" "7.14" "7.13" "7.12"
|
||||
"7.11" "7.10" "7.9" "7.8" "7.7" "7.6" "7.5" "7.4")
|
||||
if((NOT DEFINED MATLAB_ROOT)
|
||||
OR ("${MATLAB_ROOT}" STREQUAL "")
|
||||
OR ("${MATLAB_ROOT}" STREQUAL "/registry"))
|
||||
get_filename_component(MATLAB_ROOT
|
||||
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\MathWorks\\MATLAB\\${MATVER};MATLABROOT]"
|
||||
ABSOLUTE)
|
||||
set(MATLAB_VERSION ${MATVER})
|
||||
endif()
|
||||
OR ("${MATLAB_ROOT}" STREQUAL "")
|
||||
OR ("${MATLAB_ROOT}" STREQUAL "/registry"))
|
||||
endforeach()
|
||||
|
||||
find_program(MATLAB_MEX
|
||||
mex
|
||||
${MATLAB_ROOT}/bin
|
||||
)
|
||||
else()
|
||||
# Check if this is a Mac.
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
# This code is untested but taken from the older FindMatlab.cmake script as
|
||||
# well as the modifications by Ramon Casero and Tom Doel for Gerardus.
|
||||
|
||||
set(LIBRARY_EXTENSION .dylib)
|
||||
|
||||
# If this is a Mac and the attempts to find MATLAB_ROOT have so far failed,~
|
||||
# we look in the applications folder
|
||||
if((NOT DEFINED MATLAB_ROOT) OR ("${MATLAB_ROOT}" STREQUAL ""))
|
||||
|
||||
# Search for a version of Matlab available, starting from the most modern
|
||||
# one to older versions
|
||||
foreach(MATVER "R2013b" "R2013a" "R2012b" "R2012a" "R2011b" "R2011a"
|
||||
"R2010b" "R2010a" "R2009b" "R2009a" "R2008b")
|
||||
if((NOT DEFINED MATLAB_ROOT) OR ("${MATLAB_ROOT}" STREQUAL ""))
|
||||
if(EXISTS /Applications/MATLAB_${MATVER}.app)
|
||||
set(MATLAB_ROOT /Applications/MATLAB_${MATVER}.app)
|
||||
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
endif()
|
||||
|
||||
find_program(MATLAB_MEX
|
||||
mex
|
||||
PATHS
|
||||
${MATLAB_ROOT}/bin
|
||||
)
|
||||
|
||||
else()
|
||||
# On a Linux system. The goal is to find MATLAB_ROOT.
|
||||
set(LIBRARY_EXTENSION .so)
|
||||
|
||||
find_program(MATLAB_MEX_POSSIBLE_LINK
|
||||
mex
|
||||
PATHS
|
||||
${MATLAB_ROOT}/bin
|
||||
/opt/matlab/bin
|
||||
/usr/local/matlab/bin
|
||||
$ENV{HOME}/matlab/bin
|
||||
# Now all the versions
|
||||
/opt/matlab/[rR]20[0-9][0-9][abAB]/bin
|
||||
/usr/local/matlab/[rR]20[0-9][0-9][abAB]/bin
|
||||
/opt/matlab-[rR]20[0-9][0-9][abAB]/bin
|
||||
/opt/matlab_[rR]20[0-9][0-9][abAB]/bin
|
||||
/usr/local/matlab-[rR]20[0-9][0-9][abAB]/bin
|
||||
/usr/local/matlab_[rR]20[0-9][0-9][abAB]/bin
|
||||
$ENV{HOME}/matlab/[rR]20[0-9][0-9][abAB]/bin
|
||||
$ENV{HOME}/matlab-[rR]20[0-9][0-9][abAB]/bin
|
||||
$ENV{HOME}/matlab_[rR]20[0-9][0-9][abAB]/bin
|
||||
)
|
||||
|
||||
get_filename_component(MATLAB_MEX "${MATLAB_MEX_POSSIBLE_LINK}" REALPATH)
|
||||
get_filename_component(MATLAB_BIN_ROOT "${MATLAB_MEX}" PATH)
|
||||
# Strip ./bin/.
|
||||
get_filename_component(MATLAB_ROOT "${MATLAB_BIN_ROOT}" PATH)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT EXISTS "${MATLAB_MEX}" AND "${MatlabMex_FIND_REQUIRED}")
|
||||
message(FATAL_ERROR "Could not find MATLAB mex compiler; try specifying MATLAB_ROOT.")
|
||||
else()
|
||||
if(EXISTS "${MATLAB_MEX}")
|
||||
message(STATUS "Found MATLAB mex compiler: ${MATLAB_MEX}")
|
||||
message(STATUS "MATLAB root: ${MATLAB_ROOT}")
|
||||
set(MATLABMEX_FOUND 1)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
mark_as_advanced(
|
||||
MATLAB_MEX
|
||||
MATLABMEX_FOUND
|
||||
MATLAB_ROOT
|
||||
)
|
||||
|
||||
@@ -44,8 +44,8 @@ function(append_model SERIALIZATION_FILE PROGRAM_MAIN_FILE)
|
||||
else ()
|
||||
string(APPEND GOMODEL_SAFE_TYPE ${MODEL_CHAR})
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
# See if the model type already exists.
|
||||
file(READ "${SERIALIZATION_FILE}" SERIALIZATION_FILE_CONTENTS)
|
||||
@@ -77,7 +77,7 @@ function(append_model SERIALIZATION_FILE PROGRAM_MAIN_FILE)
|
||||
" C.mlpackSet${MODEL_SAFE_TYPE}"
|
||||
"Ptr(C.CString(identifier), (unsafe.Pointer)(ptr.mem))\n"
|
||||
"}\n\n")
|
||||
endif ()
|
||||
endif()
|
||||
endforeach ()
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
@@ -1,135 +0,0 @@
|
||||
#!/bin/bash
|
||||
# This script gets the test coverage for mlpack_test.
|
||||
test_case="ALL"
|
||||
gcov_loc=""
|
||||
token=""
|
||||
clean=true
|
||||
current_log_file=`date +'%Y.%h.%d:%H:%M:%S-coverage.log'`
|
||||
current_coverage_file=`date +'%Y.%h.%d:%H:%M:%S-coverage.info'`
|
||||
max_cov_count=50000
|
||||
|
||||
# default directories
|
||||
root_dir="../"
|
||||
|
||||
# Extract arguments.
|
||||
for i in "$@"
|
||||
do
|
||||
case $i in
|
||||
-h|--help)
|
||||
echo "Usage: mlpack_coverage --help|-h"
|
||||
echo " mlpack_coverage [-r=test_suite] [-g=gcov_tool_location]"
|
||||
echo " [--token=coveralls_token]"
|
||||
echo "Optional parameters:"
|
||||
echo " -n|--no_test Do not run test before coverage computation"
|
||||
echo " -r|--run_test Run tests with specific test suite"
|
||||
echo " --no_clean Do not remove existing gcda file"
|
||||
echo " -g|--gcov_tool_location Gcov location if not default"
|
||||
echo " -t|--token Upload to coveralls with given token"
|
||||
echo " --max_cov_count Max line coverage count (default 50000)"
|
||||
echo " --root_dir Set the root directory from which gcov will be called. (default ../)"
|
||||
exit 0
|
||||
shift
|
||||
;;
|
||||
-n|--no_test)
|
||||
test_case=""
|
||||
shift
|
||||
;;
|
||||
-r=*|--run_test=*)
|
||||
test_case="${i#*=}"
|
||||
shift # past argument=value
|
||||
;;
|
||||
--no_clean)
|
||||
clean=false
|
||||
shift
|
||||
;;
|
||||
-g=*|--gcov_tool_location=*)
|
||||
gcov_loc="${i#*=}"
|
||||
shift # past argument=value
|
||||
;;
|
||||
-t=*|--token=*)
|
||||
token="${i#*=}"
|
||||
shift # past argument=value
|
||||
;;
|
||||
--max_cov_count)
|
||||
max_cov_count="${i#*=}"
|
||||
shift
|
||||
;;
|
||||
--root_dir=*)
|
||||
root_dir="${i#*=}"
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
# unknown option
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ "$clean" = true ]; then
|
||||
echo "Deleting existing coverage data..."
|
||||
find ./ -name "*.gcda" -type f -delete
|
||||
fi
|
||||
|
||||
# Initial pass.
|
||||
echo "Generating primary coverage report."
|
||||
[[ -d ./coveragehistory/ ]] || mkdir coveragehistory
|
||||
lcov -b . -c -i -d ./ -o .coverage.wtest.base > ./coveragehistory/$current_log_file
|
||||
|
||||
# Run the tests.
|
||||
if [ "$test_case" = "ALL" ]; then
|
||||
echo "Running all the tests..."
|
||||
"@CMAKE_BINARY_DIR@"/bin/mlpack_test
|
||||
elif ! [ "$test_case" = "" ]; then
|
||||
echo "Running test suite: $test_case"
|
||||
"@CMAKE_BINARY_DIR@"/bin/mlpack_test --run_test=$test_case
|
||||
fi
|
||||
|
||||
# Generate coverage based on executed tests.
|
||||
echo "Computing coverage..."
|
||||
if [ "$gcov_loc" = "" ];
|
||||
then lcov -b . -c -d ./ -o .coverage.wtest.run >> ./coveragehistory/$current_log_file
|
||||
else
|
||||
lcov -b . -c -d ./ -o .coverage.wtest.run --gcov-tool=$gcov_loc >> ./coveragehistory/$current_log_file
|
||||
fi
|
||||
|
||||
echo "Filtering coverage files..."
|
||||
# Clear negative entries in coverage file
|
||||
sed -E 's/-([0-9]+)/$max_cov_count/g' -i .coverage.wtest.run
|
||||
# Merge coverage tracefiles.
|
||||
lcov -a .coverage.wtest.base -a .coverage.wtest.run -o .coverage.total >> ./coveragehistory/$current_log_file
|
||||
|
||||
# Filtering, extracting project files.
|
||||
lcov -e .coverage.total "@CMAKE_CURRENT_SOURCE_DIR@/src/mlpack/*" -o .coverage.total.filtered >> ./coveragehistory/$current_log_file
|
||||
|
||||
# Filtering, removing test-files and main.cpp.
|
||||
lcov -r .coverage.total.filtered "@CMAKE_CURRENT_SOURCE_DIR@/src/mlpack/*/*_main.cpp" -o .coverage.total.filtered >> ./coveragehistory/$current_log_file
|
||||
lcov -r .coverage.total.filtered "@CMAKE_CURRENT_SOURCE_DIR@/src/mlpack/tests/*" -o .coverage.total.filtered >> ./coveragehistory/$current_log_file
|
||||
|
||||
# Remove untestable files.
|
||||
lcov -r .coverage.total.filtered "@CMAKE_CURRENT_SOURCE_DIR@/src/mlpack/core/util/gitversion.hpp" -o .coverage.total.filtered >> ./coveragehistory/$current_log_file
|
||||
lcov -r .coverage.total.filtered "@CMAKE_CURRENT_SOURCE_DIR@/src/mlpack/core/util/arma_config.hpp" -o .coverage.total.filtered >> ./coveragehistory/$current_log_file
|
||||
|
||||
# Extra: Replace /build/ with /src/ to unify directories.
|
||||
cat .coverage.total.filtered > .coverage.total
|
||||
|
||||
# Extra: Clear up previous data, create html folder.
|
||||
if [[ -d ./coverage/ ]] ; then
|
||||
rm -rf ./coverage/*
|
||||
else
|
||||
mkdir coverage
|
||||
fi
|
||||
|
||||
# Step 9: Generate webpage.
|
||||
genhtml -o ./coverage/ .coverage.total
|
||||
|
||||
# Extra: Preserve coverage file in coveragehistory folder.
|
||||
coverage_file=$current_coverage_file
|
||||
cp .coverage.total ./coveragehistory/$current_coverage_file
|
||||
|
||||
# Clean temporary coverage files.
|
||||
#rm .coverage.*
|
||||
|
||||
# Upload the result to coveralls if token is provided.
|
||||
if ! [ "$token" = "" ]; then
|
||||
cpp-coveralls -n -r $root_dir -b $root_dir -l ./coveragehistory/$current_coverage_file -t "$token" --max-cov-count $max_cov_count
|
||||
fi
|
||||
|
||||
@@ -9,7 +9,6 @@ include(CMake/CheckHash.cmake)
|
||||
option(DEBUG "Compile with debugging information." OFF)
|
||||
option(PROFILE "Compile with profiling information." OFF)
|
||||
option(ARMA_EXTRA_DEBUG "Compile with extra Armadillo debugging symbols." OFF)
|
||||
option(MATLAB_BINDINGS "Compile MATLAB bindings if MATLAB is found." OFF)
|
||||
option(TEST_VERBOSE "Run test cases with verbose output." OFF)
|
||||
option(BUILD_TESTS "Build tests." ON)
|
||||
option(BUILD_CLI_EXECUTABLES "Build command-line executables." ON)
|
||||
@@ -80,8 +79,6 @@ option(BUILD_R_BINDINGS "Build R bindings." OFF)
|
||||
# generation.
|
||||
option(BUILD_MARKDOWN_BINDINGS "Build Markdown bindings for website documentation." OFF)
|
||||
|
||||
option(BUILD_WITH_COVERAGE
|
||||
"Build with support for code coverage tools (gcc only)." OFF)
|
||||
option(MATHJAX
|
||||
"Use MathJax for HTML Doxygen output (disabled by default)." OFF)
|
||||
option(FORCE_CXX11
|
||||
@@ -196,38 +193,6 @@ if(CMAKE_COMPILER_IS_GNUCC)
|
||||
${CMAKE_THREAD_LIBS_INIT})
|
||||
endif()
|
||||
|
||||
# Setup build for test coverage
|
||||
if(BUILD_WITH_COVERAGE)
|
||||
# Currently coverage only works with GNU g++.
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
# Find gcov and lcov
|
||||
find_program(GCOV gcov)
|
||||
find_program(LCOV lcov)
|
||||
|
||||
if(NOT GCOV)
|
||||
message(FATAL_ERROR
|
||||
"gcov not found! gcov is required when BUILD_WITH_COVERAGE=ON.")
|
||||
endif()
|
||||
|
||||
set(MLPACK_LIBRARIES ${MLPACK_LIBRARIES} "supc++")
|
||||
set(MLPACK_LIBRARIES ${MLPACK_LIBRARIES} "quadmath")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --coverage -fno-inline -fno-inline-small-functions -fno-default-inline -fprofile-arcs -fkeep-inline-functions")
|
||||
message(STATUS "Adding debug compile options for code coverage.")
|
||||
# Remove optimizations for better line coverage
|
||||
set(DEBUG ON)
|
||||
|
||||
if(LCOV)
|
||||
configure_file(CMake/mlpack_coverage.in mlpack_coverage @ONLY)
|
||||
add_custom_target(mlpack_coverage DEPENDS mlpack_test COMMAND ${PROJECT_BINARY_DIR}/mlpack_coverage)
|
||||
else()
|
||||
message(WARNING "'lcov' not found; local coverage report is disabled. "
|
||||
"Install 'lcov' and rerun cmake to generate local coverage report.")
|
||||
endif()
|
||||
else()
|
||||
message(FATAL_ERROR "BUILD_WITH_COVERAGE can only work with GNU environment.")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Debugging CFLAGS. Turn optimizations off; turn debugging symbols on.
|
||||
if(DEBUG)
|
||||
if (NOT MSVC)
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
### mlpack ?.?.?
|
||||
###### ????-??-??
|
||||
* Added warm start feature to Random Forest (#2881); this feature is
|
||||
accessible from mlpack's bindings to different languages.
|
||||
|
||||
* Added Pixel Shuffle layer (#2563).
|
||||
|
||||
* Add "check_input_matrices" option to python bindings that checks
|
||||
@@ -37,6 +40,12 @@
|
||||
* Add `Lambda1()`, `Lambda2()`, `UseCholesky()`, and `Tolerance()` members to
|
||||
`LARS` so parameters for training can be modified (#2861).
|
||||
|
||||
* Remove unused `ElemType` template parameter from `DecisionTree` and
|
||||
`RandomForest` (#2874).
|
||||
|
||||
* Fix Python binding build when the CMake variable `USE_OPENMP` is set to
|
||||
`OFF` (#2884).
|
||||
|
||||
### mlpack 3.4.2
|
||||
###### 2020-10-26
|
||||
* Added Mean Absolute Percentage Error.
|
||||
|
||||
@@ -14,8 +14,7 @@ src="https://cdn.rawgit.com/mlpack/mlpack.org/e7d36ed8/mlpack-black.svg" style="
|
||||
</h5>
|
||||
|
||||
<p align="center">
|
||||
<a href="http://ci.mlpack.org/job/mlpack%20-%20git%20commit%20test/"><img src="https://img.shields.io/jenkins/build.svg?jobUrl=http%3A%2F%2Fci.mlpack.org%2Fjob%2Fmlpack%2520-%2520git%2520commit%2520test%2F&label=Linux%20build&style=flat-square" alt="Jenkins"></a>
|
||||
<a href="https://coveralls.io/github/mlpack/mlpack?branch=master"><img src="https://img.shields.io/coveralls/mlpack/mlpack/master.svg?style=flat-square" alt="Coveralls"></a>
|
||||
<a href="https://dev.azure.com/mlpack/mlpack/_build?definitionId=1"><img alt="Azure DevOps builds (job)" src="https://img.shields.io/azure-devops/build/mlpack/84320e87-76e3-4b6e-8b6e-3adaf6b36eed/1/master?job=Linux&label=Linux%20Build&style=flat-square"></a>
|
||||
<a href="https://opensource.org/licenses/BSD-3-Clause"><img src="https://img.shields.io/badge/License-BSD%203--Clause-blue.svg?style=flat-square" alt="License"></a>
|
||||
<a href="http://numfocus.org/donate-to-mlpack"><img src="https://img.shields.io/badge/sponsored%20by-NumFOCUS-orange.svg?style=flat-square&colorA=E1523D&colorB=007D8A" alt="NumFOCUS"></a>
|
||||
</p>
|
||||
@@ -142,10 +141,10 @@ If you are compiling Armadillo by hand, ensure that LAPACK and BLAS are enabled.
|
||||
|
||||
### 4. Building mlpack from source
|
||||
|
||||
This document discusses how to build mlpack from source. These build directions
|
||||
This document discusses how to build mlpack from source. These build directions
|
||||
will work for any Linux-like shell environment (for example Ubuntu, macOS,
|
||||
FreeBSD etc). However, mlpack is in the repositories of many Linux distributions
|
||||
and so it may be easier to use the package manager for your system. For example,
|
||||
FreeBSD etc). However, mlpack is in the repositories of many Linux distributions
|
||||
and so it may be easier to use the package manager for your system. For example,
|
||||
on Ubuntu, you can install the mlpack library and command-line executables (e.g.
|
||||
mlpack_pca, mlpack_kmeans etc.) with the following command:
|
||||
|
||||
@@ -183,7 +182,7 @@ sufficient.
|
||||
|
||||
The next step is to run CMake to configure the project. Running CMake is the
|
||||
equivalent to running `./configure` with autotools. If you run CMake with no
|
||||
options, it will configure the project to build with no debugging symbols and
|
||||
options, it will configure the project to build with no debugging symbols and
|
||||
no profiling information:
|
||||
|
||||
$ cmake ../
|
||||
@@ -239,7 +238,7 @@ This will build all library components as well as 'mlpack_test'.
|
||||
|
||||
$ make
|
||||
|
||||
If you do not want to build everything in the library, individual components
|
||||
If you do not want to build everything in the library, individual components
|
||||
of the build can be specified:
|
||||
|
||||
$ make mlpack_pca mlpack_knn mlpack_kfn
|
||||
@@ -252,7 +251,7 @@ and submit an issue. The mlpack developers will quickly help you figure it out:
|
||||
Alternately, mlpack help can be found in IRC at `#mlpack` on chat.freenode.net.
|
||||
|
||||
If you wish to install mlpack to `/usr/local/include/mlpack/`, `/usr/local/lib/`,
|
||||
and `/usr/local/bin/`, make sure you have root privileges (or write permissions
|
||||
and `/usr/local/bin/`, make sure you have root privileges (or write permissions
|
||||
to those three directories), and simply type
|
||||
|
||||
$ make install
|
||||
|
||||
@@ -191,8 +191,6 @@ The full list of options mlpack allows:
|
||||
- DOWNLOAD_ENSMALLEN=(ON/OFF): If ensmallen is not found, download it
|
||||
(default ON)
|
||||
- DOWNLOAD_STB_IMAGE=(ON/OFF): If STB is not found, download it (default ON)
|
||||
- BUILD_WITH_COVERAGE=(ON/OFF): Build with support for code coverage tools
|
||||
(gcc only) (default OFF)
|
||||
- PYTHON_EXECUTABLE=(/path/to/python_version): Path to specific Python executable
|
||||
- PYTHON_INSTALL_PREFIX=(/path/to/python/): Path to root of Python installation
|
||||
- JULIA_EXECUTABLE=(/path/to/julia): Path to specific Julia executable
|
||||
|
||||
@@ -46,6 +46,7 @@ A list of all the sections this tutorial contains.
|
||||
- \ref cli_ex2_lrtut
|
||||
- \ref cli_ex3_lrtut
|
||||
- \ref cli_ex4_lrtut
|
||||
- \ref cli_ex5_lrtut
|
||||
- \ref linreg_lrtut
|
||||
- \ref linreg_ex1_lrtut
|
||||
- \ref linreg_ex2_lrtut
|
||||
@@ -113,22 +114,23 @@ $ cat dataset.csv
|
||||
4,4
|
||||
|
||||
$ cat lr.xml
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
|
||||
<!DOCTYPE boost_serialization>
|
||||
<boost_serialization signature="serialization::archive" version="12">
|
||||
<linearRegressionModel class_id="0" tracking_level="0" version="0">
|
||||
<parameters class_id="1" tracking_level="0" version="0">
|
||||
<n_rows>2</n_rows>
|
||||
<n_cols>1</n_cols>
|
||||
<n_elem>2</n_elem>
|
||||
<vec_state>1</vec_state>
|
||||
<item>-3.97205464519563669e-16</item>
|
||||
<item>1.00000000000000022e+00</item>
|
||||
</parameters>
|
||||
<lambda>0.00000000000000000e+00</lambda>
|
||||
<intercept>1</intercept>
|
||||
</linearRegressionModel>
|
||||
</boost_serialization>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<cereal>
|
||||
<model>
|
||||
<cereal_class_version>0</cereal_class_version>
|
||||
<parameters>
|
||||
<n_rows>2</n_rows>
|
||||
<n_cols>1</n_cols>
|
||||
<vec_state>1</vec_state>
|
||||
<elem>0</elem>
|
||||
<elem>1</elem>
|
||||
</parameters>
|
||||
<lambda>0</lambda>
|
||||
<intercept>true</intercept>
|
||||
</model>
|
||||
</cereal>
|
||||
|
||||
|
||||
@endcode
|
||||
|
||||
As you can see, the function for this input is \f$f(y)=0+1x_1\f$. We can see
|
||||
@@ -141,36 +143,102 @@ dataset is one dimensional, and the last column has the \f$y\f$ values, or
|
||||
responses, for each row. You can specify these responses in a separate file if
|
||||
you want, using the \c --input_responses, or \c -r, option.
|
||||
|
||||
@subsection cli_ex2_lrtut Compute model and predict at the same time
|
||||
@subsection cli_ex2_lrtut Train a multivariate linear regression model
|
||||
|
||||
Multivariate linear regression means that the response variable is predicted by
|
||||
more than just one input variable. In this example we will try to fit a
|
||||
multivariate linear regression model to data that contains four variables, stored in
|
||||
\c dataset_2.csv.
|
||||
|
||||
@code
|
||||
$ mlpack_linear_regression --training_file dataset.csv --test_file predict.csv \
|
||||
$ cat dataset_2.csv
|
||||
0,0,0,0,14
|
||||
1,1,1,1,24
|
||||
2,1,0,2,27
|
||||
1,2,2,2,32
|
||||
-1,-3,0,2,17
|
||||
@endcode
|
||||
|
||||
Now let's run \c mlpack_linear_regression as usual:
|
||||
|
||||
@code
|
||||
$ mlpack_linear_regression --training_file dataset_2.csv -v -M lr.xml
|
||||
[INFO ] Loading 'dataset_2.csv' as CSV data. Size is 5 x 5.
|
||||
[INFO ]
|
||||
[INFO ] Execution parameters:
|
||||
[INFO ] help: 0
|
||||
[INFO ] info:
|
||||
[INFO ] input_model_file:
|
||||
[INFO ] lambda: 0
|
||||
[INFO ] output_model_file: lr.xml
|
||||
[INFO ] output_predictions_file:
|
||||
[INFO ] test_file:
|
||||
[INFO ] training_file: dataset_2.csv
|
||||
[INFO ] training_responses_file:
|
||||
[INFO ] verbose: 1
|
||||
[INFO ] version: 0
|
||||
[INFO ] Program timers:
|
||||
[INFO ] load_regressors: 0.000060s
|
||||
[INFO ] loading_data: 0.000050s
|
||||
[INFO ] regression: 0.000049s
|
||||
[INFO ] total_time: 0.000118s
|
||||
|
||||
$ cat lr.xml
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<cereal>
|
||||
<model>
|
||||
<cereal_class_version>0</cereal_class_version>
|
||||
<parameters>
|
||||
<n_rows>5</n_rows>
|
||||
<n_cols>1</n_cols>
|
||||
<vec_state>1</vec_state>
|
||||
<elem>14.00000000000002</elem>
|
||||
<elem>1.9999999999999447</elem>
|
||||
<elem>1.0000000000000431</elem>
|
||||
<elem>2.9999999999999516</elem>
|
||||
<elem>4.0000000000000249</elem>
|
||||
</parameters>
|
||||
<lambda>0</lambda>
|
||||
<intercept>true</intercept>
|
||||
</model>
|
||||
</cereal>
|
||||
@endcode
|
||||
|
||||
If we take a look at the \c lr.xml output we can see the \c \<parameters\> part has five elements which
|
||||
the first corresponds to \f$\beta_0\f$ , the second corresponds to \f$\beta_1\f$ , and so on. This is equivalent
|
||||
to \f$f(y) = \beta_0 + \beta_1x_1 + \beta_2x_2 + \beta_3x_3 + \beta_4x_4\f$ or \f$f(y)=14+2x_1+1x_2+3x_3+4x_4\f$.
|
||||
|
||||
@subsection cli_ex3_lrtut Compute model and predict at the same time
|
||||
|
||||
@code
|
||||
$ mlpack_linear_regression --training_file dataset.csv --test_file predict.csv --output_predictions_file predictions.csv \
|
||||
> -v
|
||||
[WARN ] '--output_predictions_file (-o)' ignored because '--test_file (-T)' is specified!
|
||||
[INFO ] Loading 'dataset.csv' as CSV data. Size is 2 x 5.
|
||||
[INFO ] Loading 'predict.csv' as raw ASCII formatted data. Size is 1 x 3.
|
||||
[INFO ] Saving CSV data to 'predictions.csv'.
|
||||
[INFO ]
|
||||
[INFO ]
|
||||
[INFO ] Execution parameters:
|
||||
[INFO ] help: false
|
||||
[INFO ] info: ""
|
||||
[INFO ] input_model_file: ""
|
||||
[INFO ] help: 0
|
||||
[INFO ] info:
|
||||
[INFO ] input_model_file:
|
||||
[INFO ] lambda: 0
|
||||
[INFO ] output_model_file: ""
|
||||
[INFO ] output_predictions: predictions.csv
|
||||
[INFO ] test_file: predict.csv
|
||||
[INFO ] training_file: dataset.csv
|
||||
[INFO ] training_responses: ""
|
||||
[INFO ] verbose: true
|
||||
[INFO ] version: false
|
||||
[INFO ]
|
||||
[INFO ] output_model_file:
|
||||
[INFO ] output_predictions_file: 'predictions.csv' (1x3 matrix)
|
||||
[INFO ] test_file: 'predict.csv' (0x0 matrix)
|
||||
[INFO ] training_file: 'dataset.csv' (0x0 matrix)
|
||||
[INFO ] training_responses_file: ''
|
||||
[INFO ] verbose: 1
|
||||
[INFO ] version: 0
|
||||
[INFO ] Program timers:
|
||||
[INFO ] load_regressors: 0.000371s
|
||||
[INFO ] load_test_points: 0.000229s
|
||||
[INFO ] loading_data: 0.000491s
|
||||
[INFO ] prediction: 0.000075s
|
||||
[INFO ] regression: 0.000449s
|
||||
[INFO ] saving_data: 0.000186s
|
||||
[INFO ] total_time: 0.002731s
|
||||
[INFO ] load_regressors: 0.000069s
|
||||
[INFO ] load_test_points: 0.000031s
|
||||
[INFO ] loading_data: 0.000079s
|
||||
[INFO ] prediction: 0.000001s
|
||||
[INFO ] regression: 0.000054s
|
||||
[INFO ] saving_data: 0.000055s
|
||||
[INFO ] total_time: 0.000203s
|
||||
|
||||
|
||||
$ cat dataset.csv
|
||||
0,0
|
||||
@@ -195,51 +263,52 @@ about the \c predict.csv dataset is that it has the same dimensionality as the
|
||||
dataset used to create the model, one. If the model generating dataset has
|
||||
\f$d\f$ dimensions, so must the dataset we want to predict for.
|
||||
|
||||
@subsection cli_ex3_lrtut Prediction using a precomputed model
|
||||
@subsection cli_ex4_lrtut Prediction using a precomputed model
|
||||
|
||||
@code
|
||||
$ mlpack_linear_regression --input_model_file lr.xml --test_file predict.csv -v
|
||||
$ mlpack_linear_regression --input_model_file lr.xml --test_file predict.csv --output_predictions_file predictions.csv -v
|
||||
[WARN ] '--output_predictions_file (-o)' ignored because '--test_file (-T)' is specified!
|
||||
[INFO ] Loading 'predict.csv' as raw ASCII formatted data. Size is 1 x 3.
|
||||
[INFO ] Saving CSV data to 'predictions.csv'.
|
||||
[INFO ]
|
||||
[INFO ]
|
||||
[INFO ] Execution parameters:
|
||||
[INFO ] help: false
|
||||
[INFO ] info: ""
|
||||
[INFO ] help: 0
|
||||
[INFO ] info:
|
||||
[INFO ] input_model_file: lr.xml
|
||||
[INFO ] lambda: 0
|
||||
[INFO ] output_model_file: ""
|
||||
[INFO ] output_predictions: predictions.csv
|
||||
[INFO ] test_file: predict.csv
|
||||
[INFO ] training_file: ""
|
||||
[INFO ] training_responses: ""
|
||||
[INFO ] verbose: true
|
||||
[INFO ] version: false
|
||||
[INFO ]
|
||||
[INFO ] output_model_file:
|
||||
[INFO ] output_predictions_file: 'predictions.csv' (1x3 matrix)
|
||||
[INFO ] test_file: 'predict.csv' (0x0 matrix)
|
||||
[INFO ] training_file: ''
|
||||
[INFO ] training_responses_file: ''
|
||||
[INFO ] verbose: 1
|
||||
[INFO ] version: 0
|
||||
[INFO ] Program timers:
|
||||
[INFO ] load_model: 0.000264s
|
||||
[INFO ] load_test_points: 0.000186s
|
||||
[INFO ] loading_data: 0.000157s
|
||||
[INFO ] prediction: 0.000098s
|
||||
[INFO ] saving_data: 0.000157s
|
||||
[INFO ] total_time: 0.001688s
|
||||
[INFO ] load_model: 0.000051s
|
||||
[INFO ] load_test_points: 0.000052s
|
||||
[INFO ] loading_data: 0.000044s
|
||||
[INFO ] prediction: 0.000010s
|
||||
[INFO ] saving_data: 0.000079s
|
||||
[INFO ] total_time: 0.000160s
|
||||
|
||||
|
||||
$ cat lr.xml
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
|
||||
<!DOCTYPE boost_serialization>
|
||||
<boost_serialization signature="serialization::archive" version="12">
|
||||
<linearRegressionModel class_id="0" tracking_level="0" version="0">
|
||||
<parameters class_id="1" tracking_level="0" version="0">
|
||||
<n_rows>2</n_rows>
|
||||
<n_cols>1</n_cols>
|
||||
<n_elem>2</n_elem>
|
||||
<vec_state>1</vec_state>
|
||||
<item>-3.97205464519563669e-16</item>
|
||||
<item>1.00000000000000022e+00</item>
|
||||
</parameters>
|
||||
<lambda>0.00000000000000000e+00</lambda>
|
||||
<intercept>1</intercept>
|
||||
</linearRegressionModel>
|
||||
</boost_serialization>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<cereal>
|
||||
<model>
|
||||
<cereal_class_version>0</cereal_class_version>
|
||||
<parameters>
|
||||
<n_rows>2</n_rows>
|
||||
<n_cols>1</n_cols>
|
||||
<vec_state>1</vec_state>
|
||||
<elem>0</elem>
|
||||
<elem>1</elem>
|
||||
</parameters>
|
||||
<lambda>0</lambda>
|
||||
<intercept>true</intercept>
|
||||
</model>
|
||||
</cereal>
|
||||
|
||||
|
||||
$ cat predict.csv
|
||||
2
|
||||
@@ -252,7 +321,7 @@ $ cat predictions.csv
|
||||
4.0000000000e+00
|
||||
@endcode
|
||||
|
||||
@subsection cli_ex4_lrtut Using ridge regression
|
||||
@subsection cli_ex5_lrtut Using ridge regression
|
||||
|
||||
Sometimes, the input matrix of predictors has a covariance matrix that is not
|
||||
invertible, or the system is overdetermined. In this case, ridge regression is
|
||||
|
||||
@@ -153,19 +153,22 @@ the output shape is represented by the number of possible actions, which in this
|
||||
(`foward` and `backward`).
|
||||
|
||||
We can also use mlpack's ann module to setup a custom FFN network. For example, here we use a single
|
||||
hidden layer.
|
||||
hidden layer. However, the Q-Learning agent expects the object to have a `ResetNoise` method which `SimpleDQN` has.
|
||||
We can't pass mlpack's FFN network directly. Instead, we have to wrap it into `SimpleDQN` object.
|
||||
|
||||
@code
|
||||
int main()
|
||||
{
|
||||
// Set up the network.
|
||||
FFN<MeanSquaredError<>, GaussianInitialization> model(MeanSquaredError<>(),
|
||||
FFN<MeanSquaredError<>, GaussianInitialization> network(MeanSquaredError<>(),
|
||||
GaussianInitialization(0, 0.001));
|
||||
model.Add<Linear<>>(4, 128);
|
||||
model.Add<ReLULayer<>>();
|
||||
model.Add<Linear<>>(128, 128);
|
||||
model.Add<ReLULayer<>>();
|
||||
model.Add<Linear<>>(128, 2);
|
||||
network.Add<Linear<>>(4, 128);
|
||||
network.Add<ReLULayer<>>();
|
||||
network.Add<Linear<>>(128, 128);
|
||||
network.Add<ReLULayer<>>();
|
||||
network.Add<Linear<>>(128, 2);
|
||||
|
||||
SimpleDQN<> model(network);
|
||||
|
||||
@endcode
|
||||
|
||||
@@ -323,7 +326,7 @@ auto measure = [&returns, &position, &episode](double episodeReturn)
|
||||
|
||||
std::cout << "Episode No.: " << episode
|
||||
<< "; Episode Return: " << episodeReturn
|
||||
<< "; Average Return: " << arma::mean(returns) << endl;
|
||||
<< "; Average Return: " << arma::mean(returns) << std::endl;
|
||||
};
|
||||
@endcode
|
||||
|
||||
@@ -389,7 +392,7 @@ int main()
|
||||
|
||||
std::cout << "Episode No.: " << episode
|
||||
<< "; Episode Return: " << episodeReturn
|
||||
<< "; Average Return: " << arma::mean(returns) << endl;
|
||||
<< "; Average Return: " << arma::mean(returns) << std::endl;
|
||||
};
|
||||
|
||||
for (int i = 0; i < 100; i++)
|
||||
|
||||
@@ -284,6 +284,11 @@ if (BUILD_R_BINDINGS)
|
||||
DESTINATION
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/mlpack/")
|
||||
|
||||
file(COPY
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/mlpack/configure"
|
||||
DESTINATION
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/mlpack/")
|
||||
|
||||
# Do the actual build.
|
||||
add_custom_target(r_build ALL)
|
||||
|
||||
|
||||
@@ -20,6 +20,5 @@ Suggests: testthat (>= 2.1.0)
|
||||
URL: https://www.mlpack.org/doc/mlpack-@PACKAGE_VERSION@/r_documentation.html,
|
||||
https://github.com/mlpack/mlpack
|
||||
BugReports: https://github.com/mlpack/mlpack/issues
|
||||
LazyData: true
|
||||
RoxygenNote: 7.1.0
|
||||
Encoding: UTF-8
|
||||
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
#!/bin/sh
|
||||
|
||||
if test `uname` = "SunOS" ;
|
||||
then
|
||||
sed '1 s/$/ -ftrack-macro-expansion=0 -pipe --param ggc-min-expand=10 --param ggc-min-heapsize=8192/' ./src/Makevars > ./src/Makevars.tmp && cat ./src/Makevars.tmp > ./src/Makevars && rm ./src/Makevars.tmp
|
||||
fi
|
||||
|
||||
exit 0
|
||||
@@ -1,3 +1,3 @@
|
||||
PKG_CXXFLAGS = -DBOOST_MATH_PROMOTE_DOUBLE_POLICY=false -I. $(SHLIB_OPENMP_CXXFLAGS)
|
||||
PKG_CXXFLAGS = -DBOOST_MATH_PROMOTE_DOUBLE_POLICY=false -I. $(SHLIB_OPENMP_CXXFLAGS) -ftrack-macro-expansion=0 -pipe --param ggc-min-expand=10 --param ggc-min-heapsize=8192
|
||||
PKG_LIBS = $(SHLIB_OPENMP_CXXFLAGS) $(LAPACK_LIBS) $(BLAS_LIBS) $(FLIBS)
|
||||
CXX_STD = CXX11
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
#include <Rcpp.h>
|
||||
|
||||
// To suppress Found ‘__assert_fail’, possibly from ‘assert’ (C).
|
||||
// To suppress Found '__assert_fail', possibly from 'assert' (C).
|
||||
#define BOOST_DISABLE_ASSERTS
|
||||
|
||||
// Rcpp has its own stream object which cooperates more nicely with R's i/o
|
||||
|
||||
@@ -98,8 +98,9 @@ std::string PrintTypeDoc(
|
||||
"of the data is detected by the extension of the filename. The storage"
|
||||
" should be such that one row corresponds to one point, and one column "
|
||||
"corresponds to one dimension (this is the typical storage format for "
|
||||
"on-disk data). All values of the matrix will be loaded as double-"
|
||||
"precision floating point data.";
|
||||
"on-disk data). CSV files will be checked for a header; if no header "
|
||||
"is found, the first row will be loaded as a data point. All values of"
|
||||
" the matrix will be loaded as double-precision floating point data.";
|
||||
}
|
||||
else if (std::is_same<T, arma::Mat<size_t>>::value)
|
||||
{
|
||||
@@ -111,8 +112,10 @@ std::string PrintTypeDoc(
|
||||
"compiled with HDF5 support. The type of the data is detected by the "
|
||||
"extension of the filename. The storage should be such that one row "
|
||||
"corresponds to one point, and one column corresponds to one dimension "
|
||||
"(this is the typical storage format for on-disk data). All values of "
|
||||
"the matrix will be loaded as unsigned integers.";
|
||||
"(this is the typical storage format for on-disk data). CSV files will"
|
||||
" be checked for a header; if no header is found, the first row will be"
|
||||
" loaded as a data point. All values of the matrix will be loaded as "
|
||||
"unsigned integers.";
|
||||
}
|
||||
else if (std::is_same<T, arma::rowvec>::value ||
|
||||
std::is_same<T, arma::vec>::value)
|
||||
|
||||
@@ -52,18 +52,15 @@ if os.getenv('NO_BUILD') == '1':
|
||||
else:
|
||||
cxx_flags = '${CMAKE_CXX_FLAGS}'.strip()
|
||||
cxx_flags = re.sub(' +', ' ', cxx_flags)
|
||||
extra_args = ['-DBINDING_TYPE=BINDING_TYPE_PYX', '-std=c++11']
|
||||
if '${OpenMP_CXX_FLAGS}' != '':
|
||||
extra_args.append('${OpenMP_CXX_FLAGS}')
|
||||
if cxx_flags:
|
||||
extra_args = ['-DBINDING_TYPE=BINDING_TYPE_PYX',
|
||||
'-std=c++11',
|
||||
'${OpenMP_CXX_FLAGS}'] + cxx_flags.split(' ')
|
||||
else:
|
||||
extra_args = ['-DBINDING_TYPE=BINDING_TYPE_PYX',
|
||||
'-std=c++11',
|
||||
'${OpenMP_CXX_FLAGS}']
|
||||
extra_args.extend(cxx_flags.split(' '))
|
||||
|
||||
# Extra options for MSVC compiler.
|
||||
if platform.system() == 'Windows':
|
||||
extra_args = extra_args + ['/MD', '/O2', '/Ob2', '/DNDEBUG']
|
||||
extra_args.extend(['/MD', '/O2', '/Ob2', '/DNDEBUG'])
|
||||
|
||||
# This is used for parallel builds; CMake will set PYX_TO_BUILD accordingly.
|
||||
if module is not None:
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
/**
|
||||
/**
|
||||
* @file core.hpp
|
||||
*
|
||||
* Include all of the base components required to write mlpack methods, and the
|
||||
|
||||
@@ -47,6 +47,10 @@ std::string GetStringType(const arma::file_type& type)
|
||||
* from Armadillo's function guess_file_type_internal(), but we avoid using
|
||||
* internal Armadillo functionality.
|
||||
*
|
||||
* If the file is detected as a CSV, and the CSV is detected to have a header
|
||||
* row, the stream `f` will be fast-forwarded to point at the second line of the
|
||||
* file.
|
||||
*
|
||||
* @param f Opened istream to look into to guess the file type.
|
||||
*/
|
||||
arma::file_type GuessFileType(std::istream& f)
|
||||
@@ -114,6 +118,53 @@ arma::file_type GuessFileType(std::istream& f)
|
||||
}
|
||||
}
|
||||
|
||||
if (hasComma && (hasBracket == false))
|
||||
{
|
||||
// If we believe we have a CSV file, then we want to try to skip any header
|
||||
// row. We'll detect a header row by simply seeing if anything in the first
|
||||
// line doesn't parse as a number.
|
||||
//
|
||||
// TODO: this is not a foolproof algorithm, so there should eventually be a
|
||||
// way added for the user to explicitly indicate that there is or isn't a
|
||||
// header.
|
||||
std::string firstLine;
|
||||
std::getline(f, firstLine);
|
||||
|
||||
std::stringstream str(firstLine);
|
||||
std::string token;
|
||||
bool allNumeric = true;
|
||||
// We'll abuse 'getline()' to split on commas.
|
||||
while (std::getline(str, token, ','))
|
||||
{
|
||||
// Let's see if we can parse the token into a number.
|
||||
double num;
|
||||
std::string rest;
|
||||
|
||||
// Try to parse into a number.
|
||||
std::stringstream s(token);
|
||||
s >> num;
|
||||
if (s.fail())
|
||||
{
|
||||
allNumeric = false;
|
||||
break;
|
||||
}
|
||||
|
||||
// Now check to see there isn't anything else. (This catches cases like,
|
||||
// e.g., "1a".)
|
||||
s >> rest;
|
||||
if (rest.length() > 0)
|
||||
{
|
||||
allNumeric = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If we could parse everything into a number, then let's rewind `f` so that
|
||||
// it's at the start of the file.
|
||||
if (allNumeric)
|
||||
f.seekg(pos1);
|
||||
}
|
||||
|
||||
delete[] dataMem;
|
||||
|
||||
if (hasBinary)
|
||||
@@ -131,12 +182,14 @@ arma::file_type GuessFileType(std::istream& f)
|
||||
* necessary. (For instance, a .csv file could be delimited by spaces, commas,
|
||||
* or tabs.) This is meant to be used during loading.
|
||||
*
|
||||
* If the file is detected as a CSV, and the CSV is detected to have a header
|
||||
* row, `stream` will be fast-forwarded to point at the second line of the file.
|
||||
*
|
||||
* @param stream Opened file stream to look into for autodetection.
|
||||
* @param filename Name of the file.
|
||||
* @return The detected file type.
|
||||
*/
|
||||
arma::file_type AutoDetect(std::fstream& stream,
|
||||
const std::string& filename)
|
||||
arma::file_type AutoDetect(std::fstream& stream, const std::string& filename)
|
||||
{
|
||||
// Get the extension.
|
||||
std::string extension = Extension(filename);
|
||||
|
||||
@@ -30,6 +30,10 @@ std::string GetStringType(const arma::file_type& type);
|
||||
* from Armadillo's function guess_file_type_internal(), but we avoid using
|
||||
* internal Armadillo functionality.
|
||||
*
|
||||
* If the file is detected as a CSV, and the CSV is detected to have a header
|
||||
* row, the stream `f` will be fast-forwarded to point at the second line of the
|
||||
* file.
|
||||
*
|
||||
* @param f Opened istream to look into to guess the file type.
|
||||
*/
|
||||
arma::file_type GuessFileType(std::istream& f);
|
||||
@@ -40,6 +44,9 @@ arma::file_type GuessFileType(std::istream& f);
|
||||
* necessary. (For instance, a .csv file could be delimited by spaces, commas,
|
||||
* or tabs.) This is meant to be used during loading.
|
||||
*
|
||||
* If the file is detected as a CSV, and the CSV is detected to have a header
|
||||
* row, `stream` will be fast-forwarded to point at the second line of the file.
|
||||
*
|
||||
* @param stream Opened file stream to look into for autodetection.
|
||||
* @param filename Name of the file.
|
||||
* @return The detected file type. arma::file_type_unknown if unknown.
|
||||
|
||||
@@ -48,6 +48,10 @@ namespace data /** Functions to load and save matrices and models. */ {
|
||||
* `inputLoadType` parameter with the correct type above (e.g.
|
||||
* `arma::csv_ascii`.)
|
||||
*
|
||||
* If the detected file type is CSV (`arma::csv_ascii`), the first row will be
|
||||
* checked for a CSV header. If a CSV header is not detected, the first row
|
||||
* will be treated as data; otherwise, the first row will be skipped.
|
||||
*
|
||||
* If the parameter 'fatal' is set to true, a std::runtime_error exception will
|
||||
* be thrown if the matrix does not load successfully. The parameter
|
||||
* 'transpose' controls whether or not the matrix is transposed after loading.
|
||||
|
||||
@@ -18,11 +18,57 @@
|
||||
namespace mlpack {
|
||||
namespace data {
|
||||
|
||||
/**
|
||||
* This helper function splits any `input` data into training and testing parts.
|
||||
* In order to shuffle the input data before spliting, an array of shuffled
|
||||
* indices of the input data is passed in the form of argument `order`.
|
||||
*/
|
||||
template<typename InputType>
|
||||
void SplitHelper(const InputType& input,
|
||||
InputType& train,
|
||||
InputType& test,
|
||||
const double testRatio,
|
||||
const arma::uvec& order = arma::uvec())
|
||||
{
|
||||
const size_t testSize = static_cast<size_t>(input.n_cols * testRatio);
|
||||
const size_t trainSize = input.n_cols - testSize;
|
||||
|
||||
// Initialising the sizes of outputs if not already initialized.
|
||||
train.set_size(input.n_rows, trainSize);
|
||||
test.set_size(input.n_rows, testSize);
|
||||
|
||||
// Shuffling and spliting simultaneously.
|
||||
if (!order.is_empty())
|
||||
{
|
||||
if (trainSize > 0)
|
||||
{
|
||||
for (size_t i = 0; i < trainSize; ++i)
|
||||
train.col(i) = input.col(order(i));
|
||||
}
|
||||
if (trainSize < input.n_cols)
|
||||
{
|
||||
for (size_t i = trainSize; i < input.n_cols; ++i)
|
||||
test.col(i - trainSize) = input.col(order(i));
|
||||
}
|
||||
}
|
||||
// Spliting only.
|
||||
else
|
||||
{
|
||||
if (trainSize > 0)
|
||||
train = input.cols(0, trainSize - 1);
|
||||
|
||||
if (trainSize < input.n_cols)
|
||||
test = input.cols(trainSize, input.n_cols - 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an input dataset and labels, stratify into a training set and test set.
|
||||
* It is recommended to have the input labels between the range [0, n) where n
|
||||
* is the number of different labels. The NormalizeLabels() function in
|
||||
* mlpack::data can be used for this.
|
||||
* Expects labels to be of type arma::Row<> or arma::Col<>.
|
||||
* Throws a runtime error if this is not the case.
|
||||
* Example usage below. This overload places the stratified dataset into the
|
||||
* four output parameters given (trainData, testData, trainLabel,
|
||||
* and testLabel).
|
||||
@@ -52,13 +98,14 @@ namespace data {
|
||||
* @param shuffleData If true, the sample order is shuffled; otherwise, each
|
||||
* sample is visited in linear order. (Default true.)
|
||||
*/
|
||||
template<typename T, typename U>
|
||||
template<typename T, typename LabelsType,
|
||||
typename = std::enable_if_t<arma::is_arma_type<LabelsType>::value> >
|
||||
void StratifiedSplit(const arma::Mat<T>& input,
|
||||
const arma::Row<U>& inputLabel,
|
||||
const LabelsType& inputLabel,
|
||||
arma::Mat<T>& trainData,
|
||||
arma::Mat<T>& testData,
|
||||
arma::Row<U>& trainLabel,
|
||||
arma::Row<U>& testLabel,
|
||||
LabelsType& trainLabel,
|
||||
LabelsType& testLabel,
|
||||
const double testRatio,
|
||||
const bool shuffleData = true)
|
||||
{
|
||||
@@ -95,29 +142,24 @@ void StratifiedSplit(const arma::Mat<T>& input,
|
||||
* 0
|
||||
* 1 1
|
||||
*/
|
||||
const bool typeCheck = (arma::is_Row<LabelsType>::value)
|
||||
|| (arma::is_Col<LabelsType>::value);
|
||||
if (!typeCheck)
|
||||
throw std::runtime_error("data::Split(): when stratified sampling is done, "
|
||||
"labels must have type `arma::Row<>`!");
|
||||
size_t trainIdx = 0;
|
||||
size_t testIdx = 0;
|
||||
size_t trainSize = 0;
|
||||
size_t testSize = 0;
|
||||
arma::uvec labelCounts;
|
||||
arma::uvec testLabelCounts;
|
||||
U maxLabel = inputLabel.max();
|
||||
typename LabelsType::elem_type maxLabel = inputLabel.max();
|
||||
|
||||
labelCounts.zeros(maxLabel+1);
|
||||
testLabelCounts.zeros(maxLabel+1);
|
||||
|
||||
arma::uvec order =
|
||||
arma::linspace<arma::uvec>(0, input.n_cols - 1, input.n_cols);
|
||||
|
||||
if (shuffleData)
|
||||
{
|
||||
order = arma::shuffle(order);
|
||||
}
|
||||
|
||||
for (U label : inputLabel)
|
||||
{
|
||||
for (typename LabelsType::elem_type label : inputLabel)
|
||||
++labelCounts[label];
|
||||
}
|
||||
|
||||
for (arma::uword labelCount : labelCounts)
|
||||
{
|
||||
@@ -127,24 +169,50 @@ void StratifiedSplit(const arma::Mat<T>& input,
|
||||
|
||||
trainData.set_size(input.n_rows, trainSize);
|
||||
testData.set_size(input.n_rows, testSize);
|
||||
trainLabel.set_size(trainSize);
|
||||
testLabel.set_size(testSize);
|
||||
trainLabel.set_size(inputLabel.n_rows, trainSize);
|
||||
testLabel.set_size(inputLabel.n_rows, testSize);
|
||||
|
||||
for (arma::uword i : order)
|
||||
if (shuffleData)
|
||||
{
|
||||
U label = inputLabel[i];
|
||||
if (testLabelCounts[label] < floor(labelCounts[label] * testRatio))
|
||||
arma::uvec order = arma::shuffle(
|
||||
arma::linspace<arma::uvec>(0, input.n_cols - 1, input.n_cols));
|
||||
|
||||
for (arma::uword i : order)
|
||||
{
|
||||
testLabelCounts[label] += 1;
|
||||
testData.col(testIdx) = input.col(i);
|
||||
testLabel[testIdx] = inputLabel[i];
|
||||
testIdx += 1;
|
||||
typename LabelsType::elem_type label = inputLabel[i];
|
||||
if (testLabelCounts[label] < floor(labelCounts[label] * testRatio))
|
||||
{
|
||||
testLabelCounts[label] += 1;
|
||||
testData.col(testIdx) = input.col(i);
|
||||
testLabel[testIdx] = inputLabel[i];
|
||||
testIdx += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
trainData.col(trainIdx) = input.col(i);
|
||||
trainLabel[trainIdx] = inputLabel[i];
|
||||
trainIdx += 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
}
|
||||
else
|
||||
{
|
||||
for (arma::uword i = 0; i < input.n_cols; i++)
|
||||
{
|
||||
trainData.col(trainIdx) = input.col(i);
|
||||
trainLabel[trainIdx] = inputLabel[i];
|
||||
trainIdx += 1;
|
||||
typename LabelsType::elem_type label = inputLabel[i];
|
||||
if (testLabelCounts[label] < floor(labelCounts[label] * testRatio))
|
||||
{
|
||||
testLabelCounts[label] += 1;
|
||||
testData.col(testIdx) = input.col(i);
|
||||
testLabel[testIdx] = inputLabel[i];
|
||||
testIdx += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
trainData.col(trainIdx) = input.col(i);
|
||||
trainLabel[trainIdx] = inputLabel[i];
|
||||
trainIdx += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -169,6 +237,9 @@ void StratifiedSplit(const arma::Mat<T>& input,
|
||||
* testData, trainLabel, testLabel, 0.3);
|
||||
* @endcode
|
||||
*
|
||||
* @tparam T Type of the elements of the input matrix.
|
||||
* @tparam LabelsType Type of input labels. It can be arma::Mat, arma::Row,
|
||||
* arma::Cube or arma::SpMat.
|
||||
* @param input Input dataset to split.
|
||||
* @param inputLabel Input labels to split.
|
||||
* @param trainData Matrix to store training data into.
|
||||
@@ -179,50 +250,28 @@ void StratifiedSplit(const arma::Mat<T>& input,
|
||||
* @param shuffleData If true, the sample order is shuffled; otherwise, each
|
||||
* sample is visited in linear order. (Default true.)
|
||||
*/
|
||||
template<typename T, typename U>
|
||||
template<typename T, typename LabelsType,
|
||||
typename = std::enable_if_t<arma::is_arma_type<LabelsType>::value> >
|
||||
void Split(const arma::Mat<T>& input,
|
||||
const arma::Row<U>& inputLabel,
|
||||
const LabelsType& inputLabel,
|
||||
arma::Mat<T>& trainData,
|
||||
arma::Mat<T>& testData,
|
||||
arma::Row<U>& trainLabel,
|
||||
arma::Row<U>& testLabel,
|
||||
LabelsType& trainLabel,
|
||||
LabelsType& testLabel,
|
||||
const double testRatio,
|
||||
const bool shuffleData = true)
|
||||
{
|
||||
const size_t testSize = static_cast<size_t>(input.n_cols * testRatio);
|
||||
const size_t trainSize = input.n_cols - testSize;
|
||||
trainData.set_size(input.n_rows, trainSize);
|
||||
testData.set_size(input.n_rows, testSize);
|
||||
trainLabel.set_size(trainSize);
|
||||
testLabel.set_size(testSize);
|
||||
|
||||
if (shuffleData)
|
||||
{
|
||||
arma::uvec order = arma::shuffle(arma::linspace<arma::uvec>(
|
||||
0, input.n_cols - 1, input.n_cols));
|
||||
if (trainSize > 0)
|
||||
{
|
||||
trainData = input.cols(order.subvec(0, trainSize - 1));
|
||||
trainLabel = inputLabel.cols(order.subvec(0, trainSize - 1));
|
||||
}
|
||||
if (trainSize < input.n_cols)
|
||||
{
|
||||
testData = input.cols(order.subvec(trainSize, input.n_cols - 1));
|
||||
testLabel = inputLabel.cols(order.subvec(trainSize, input.n_cols - 1));
|
||||
}
|
||||
arma::uvec order = arma::shuffle(arma::linspace<arma::uvec>(0,
|
||||
input.n_cols - 1, input.n_cols));
|
||||
SplitHelper(input, trainData, testData, testRatio, order);
|
||||
SplitHelper(inputLabel, trainLabel, testLabel, testRatio, order);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (trainSize > 0)
|
||||
{
|
||||
trainData = input.cols(0, trainSize - 1);
|
||||
trainLabel = inputLabel.subvec(0, trainSize - 1);
|
||||
}
|
||||
if (trainSize < input.n_cols)
|
||||
{
|
||||
testData = input.cols(trainSize , input.n_cols - 1);
|
||||
testLabel = inputLabel.subvec(trainSize , input.n_cols - 1);
|
||||
}
|
||||
SplitHelper(input, trainData, testData, testRatio);
|
||||
SplitHelper(inputLabel, trainLabel, testLabel, testRatio);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -256,29 +305,15 @@ void Split(const arma::Mat<T>& input,
|
||||
const double testRatio,
|
||||
const bool shuffleData = true)
|
||||
{
|
||||
const size_t testSize = static_cast<size_t>(input.n_cols * testRatio);
|
||||
const size_t trainSize = input.n_cols - testSize;
|
||||
trainData.set_size(input.n_rows, trainSize);
|
||||
testData.set_size(input.n_rows, testSize);
|
||||
|
||||
if (shuffleData)
|
||||
{
|
||||
arma::uvec order = arma::shuffle(arma::linspace<arma::uvec>(
|
||||
0, input.n_cols - 1, input.n_cols));
|
||||
|
||||
if (trainSize > 0)
|
||||
trainData = input.cols(order.subvec(0, trainSize - 1));
|
||||
|
||||
if (trainSize < input.n_cols)
|
||||
testData = input.cols(order.subvec(trainSize, input.n_cols - 1));
|
||||
arma::uvec order = arma::shuffle(arma::linspace<arma::uvec>(0,
|
||||
input.n_cols - 1, input.n_cols));
|
||||
SplitHelper(input, trainData, testData, testRatio, order);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (trainSize > 0)
|
||||
trainData = input.cols(0, trainSize - 1);
|
||||
|
||||
if (trainSize < input.n_cols)
|
||||
testData = input.cols(trainSize , input.n_cols - 1);
|
||||
SplitHelper(input, trainData, testData, testRatio);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -295,6 +330,9 @@ void Split(const arma::Mat<T>& input,
|
||||
* auto splitResult = Split(input, label, 0.2);
|
||||
* @endcode
|
||||
*
|
||||
* @tparam T Type of the elements of the input matrix.
|
||||
* @tparam LabelsType Type of input labels. It can be arma::Mat, arma::Row,
|
||||
* arma::Cube or arma::SpMat.
|
||||
* @param input Input dataset to split.
|
||||
* @param inputLabel Input labels to split.
|
||||
* @param testRatio Percentage of dataset to use for test set (between 0 and 1).
|
||||
@@ -302,22 +340,24 @@ void Split(const arma::Mat<T>& input,
|
||||
* sample is visited in linear order. (Default true).
|
||||
* @param stratifyData If true, the train and test splits are stratified
|
||||
* so that the ratio of each class in the training and test sets is the same
|
||||
* as in the original dataset.
|
||||
* as in the original dataset. Expects labels to be of type arma::Row<> or
|
||||
* arma::Col<>.
|
||||
* @return std::tuple containing trainData (arma::Mat<T>), testData
|
||||
* (arma::Mat<T>), trainLabel (arma::Row<U>), and testLabel (arma::Row<U>).
|
||||
*/
|
||||
template<typename T, typename U>
|
||||
std::tuple<arma::Mat<T>, arma::Mat<T>, arma::Row<U>, arma::Row<U>>
|
||||
template<typename T, typename LabelsType,
|
||||
typename = std::enable_if_t<arma::is_arma_type<LabelsType>::value> >
|
||||
std::tuple<arma::Mat<T>, arma::Mat<T>, LabelsType, LabelsType>
|
||||
Split(const arma::Mat<T>& input,
|
||||
const arma::Row<U>& inputLabel,
|
||||
const LabelsType& inputLabel,
|
||||
const double testRatio,
|
||||
const bool shuffleData = true,
|
||||
const bool stratifyData = false)
|
||||
{
|
||||
arma::Mat<T> trainData;
|
||||
arma::Mat<T> testData;
|
||||
arma::Row<U> trainLabel;
|
||||
arma::Row<U> testLabel;
|
||||
LabelsType trainLabel;
|
||||
LabelsType testLabel;
|
||||
|
||||
if (stratifyData)
|
||||
{
|
||||
@@ -368,6 +408,208 @@ Split(const arma::Mat<T>& input,
|
||||
std::move(testData));
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an input dataset and labels, split into a training set and test set.
|
||||
* Example usage below. This overload places the split dataset into the four
|
||||
* output parameters given (trainData, testData, trainLabel, and testLabel).
|
||||
*
|
||||
* The input dataset must be of type arma::field. It should have the shape -
|
||||
* (n_rows = 1, n_cols = Number of samples, n_slices = 1).
|
||||
*
|
||||
* NOTE: Here FieldType could be arma::field<arma::mat> or arma::field<arma::vec>.
|
||||
*
|
||||
* @code
|
||||
* arma::field<arma::mat> input = loadData();
|
||||
* arma::field<arma::vec> label = loadLabel();
|
||||
* arma::field<arma::mat> trainData;
|
||||
* arma::field<arma::mat> testData;
|
||||
* arma::field<arma::vec> trainLabel;
|
||||
* arma::field<arma::vec> testLabel;
|
||||
* math::RandomSeed(100); // Set the seed if you like.
|
||||
*
|
||||
* // Split the dataset into a training and test set, with 30% of the data being
|
||||
* // held out for the test set.
|
||||
* Split(input, label, trainData, testData, trainLabel, testLabel, 0.3);
|
||||
* @endcode
|
||||
*
|
||||
* @param input Input dataset to split.
|
||||
* @param inputLabel Input labels to split.
|
||||
* @param trainData FieldType to store training data into.
|
||||
* @param testData FieldType test data into.
|
||||
* @param trainLabel Field vector to store training labels into.
|
||||
* @param testLabel Field vector to store test labels into.
|
||||
* @param testRatio Percentage of dataset to use for test set (between 0 and 1).
|
||||
* @param shuffleData If true, the sample order is shuffled; otherwise, each
|
||||
* sample is visited in linear order. (Default true.)
|
||||
*/
|
||||
template <typename FieldType, typename T,
|
||||
typename = std::enable_if_t<
|
||||
arma::is_Col<typename FieldType::object_type>::value ||
|
||||
arma::is_Mat_only<typename FieldType::object_type>::value>>
|
||||
void Split(const FieldType& input,
|
||||
const arma::field<T>& inputLabel,
|
||||
FieldType& trainData,
|
||||
arma::field<T>& trainLabel,
|
||||
FieldType& testData,
|
||||
arma::field<T>& testLabel,
|
||||
const double testRatio,
|
||||
const bool shuffleData = true)
|
||||
{
|
||||
if (shuffleData)
|
||||
{
|
||||
arma::uvec order = arma::shuffle(arma::linspace<arma::uvec>(0,
|
||||
input.n_cols - 1, input.n_cols));
|
||||
SplitHelper(input, trainData, testData, testRatio, order);
|
||||
SplitHelper(inputLabel, trainLabel, testLabel, testRatio, order);
|
||||
}
|
||||
else
|
||||
{
|
||||
SplitHelper(input, trainData, testData, testRatio);
|
||||
SplitHelper(inputLabel, trainLabel, testLabel, testRatio);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an input dataset, split into a training set and test set.
|
||||
* Example usage below. This overload places the split dataset into the two
|
||||
* output parameters given (trainData, testData).
|
||||
*
|
||||
* The input dataset must be of type arma::field. It should have the shape -
|
||||
* (n_rows = 1, n_cols = Number of samples, n_slices = 1)
|
||||
*
|
||||
* NOTE: Here FieldType could be arma::field<arma::mat> or arma::field<arma::vec>
|
||||
*
|
||||
* @code
|
||||
* arma::field<arma::mat> input = loadData();
|
||||
* arma::field<arma::mat> trainData;
|
||||
* arma::field<arma::mat> testData;
|
||||
* math::RandomSeed(100); // Set the seed if you like.
|
||||
*
|
||||
* // Split the dataset into a training and test set, with 30% of the data being
|
||||
* // held out for the test set.
|
||||
* Split(input, trainData, testData, 0.3);
|
||||
* @endcode
|
||||
*
|
||||
* @param input Input dataset to split.
|
||||
* @param trainData FieldType to store training data into.
|
||||
* @param testData FieldType test data into.
|
||||
* @param testRatio Percentage of dataset to use for test set (between 0 and 1).
|
||||
* @param shuffleData If true, the sample order is shuffled; otherwise, each
|
||||
* sample is visited in linear order. (Default true).
|
||||
*/
|
||||
template <class FieldType,
|
||||
class = std::enable_if_t<
|
||||
arma::is_Col<typename FieldType::object_type>::value ||
|
||||
arma::is_Mat_only<typename FieldType::object_type>::value>>
|
||||
void Split(const FieldType& input,
|
||||
FieldType& trainData,
|
||||
FieldType& testData,
|
||||
const double testRatio,
|
||||
const bool shuffleData = true)
|
||||
{
|
||||
if (shuffleData)
|
||||
{
|
||||
arma::uvec order = arma::shuffle(arma::linspace<arma::uvec>(0,
|
||||
input.n_cols - 1, input.n_cols));
|
||||
SplitHelper(input, trainData, testData, testRatio, order);
|
||||
}
|
||||
else
|
||||
{
|
||||
SplitHelper(input, trainData, testData, testRatio);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an input dataset and labels, split into a training set and test set.
|
||||
* Example usage below. This overload returns the split dataset as a std::tuple
|
||||
* with four elements: an FieldType containing the training data, an
|
||||
* FieldType containing the test data, an arma::field<arma::vec> containing the
|
||||
* training labels, and an arma::field<arma::vec> containing the test labels.
|
||||
*
|
||||
* The input dataset must be of type arma::field. It should have the shape -
|
||||
* (n_rows = 1, n_cols = Number of samples, n_slices = 1)
|
||||
*
|
||||
* NOTE: Here FieldType could be arma::field<arma::mat> or arma::field<arma::vec>
|
||||
*
|
||||
* @code
|
||||
* arma::field<arma::mat> input = loadData();
|
||||
* arma::field<arma::vec> label = loadLabel();
|
||||
* auto splitResult = Split(input, label, 0.2);
|
||||
* @endcode
|
||||
*
|
||||
* @param input Input dataset to split.
|
||||
* @param inputLabel Input labels to split.
|
||||
* @param testRatio Percentage of dataset to use for test set (between 0 and 1).
|
||||
* @param shuffleData If true, the sample order is shuffled; otherwise, each
|
||||
* sample is visited in linear order. (Default true).
|
||||
* @return std::tuple containing trainData (FieldType), testData
|
||||
* (FieldType), trainLabel (arma::field<arma::vec>), and
|
||||
* testLabel (arma::field<arma::vec>).
|
||||
*/
|
||||
template <class FieldType, typename T,
|
||||
class = std::enable_if_t<
|
||||
arma::is_Col<typename FieldType::object_type>::value ||
|
||||
arma::is_Mat_only<typename FieldType::object_type>::value>>
|
||||
std::tuple<FieldType, FieldType, arma::field<T>, arma::field<T>>
|
||||
Split(const FieldType& input,
|
||||
const arma::field<T>& inputLabel,
|
||||
const double testRatio,
|
||||
const bool shuffleData = true)
|
||||
{
|
||||
FieldType trainData;
|
||||
FieldType testData;
|
||||
arma::field<T> trainLabel;
|
||||
arma::field<T> testLabel;
|
||||
|
||||
Split(input, inputLabel, trainData, trainLabel, testData, testLabel,
|
||||
testRatio, shuffleData);
|
||||
|
||||
return std::make_tuple(std::move(trainData),
|
||||
std::move(testData),
|
||||
std::move(trainLabel),
|
||||
std::move(testLabel));
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an input dataset, split into a training set and test set.
|
||||
* Example usage below. This overload returns the split dataset as a std::tuple
|
||||
* with two elements: an FieldType containing the training data and an
|
||||
* FieldType containing the test data.
|
||||
*
|
||||
* The input dataset must be of type arma::field. It should have the shape -
|
||||
* (n_rows = 1, n_cols = Number of samples, n_slices = 1)
|
||||
*
|
||||
* NOTE: Here FieldType could be arma::field<arma::mat> or arma::field<arma::vec>
|
||||
*
|
||||
* @code
|
||||
* arma::field<arma::mat> input = loadData();
|
||||
* auto splitResult = Split(input, 0.2);
|
||||
* @endcode
|
||||
*
|
||||
* @param input Input dataset to split.
|
||||
* @param testRatio Percentage of dataset to use for test set (between 0 and 1).
|
||||
* @param shuffleData If true, the sample order is shuffled; otherwise, each
|
||||
* sample is visited in linear order. (Default true).
|
||||
* @return std::tuple containing trainData (FieldType)
|
||||
* and testData (FieldType).
|
||||
*/
|
||||
template <class FieldType,
|
||||
class = std::enable_if_t<
|
||||
arma::is_Col<typename FieldType::object_type>::value ||
|
||||
arma::is_Mat_only<typename FieldType::object_type>::value>>
|
||||
std::tuple<FieldType, FieldType>
|
||||
Split(const FieldType& input,
|
||||
const double testRatio,
|
||||
const bool shuffleData = true)
|
||||
{
|
||||
FieldType trainData;
|
||||
FieldType testData;
|
||||
Split(input, trainData, testData, testRatio, shuffleData);
|
||||
|
||||
return std::make_tuple(std::move(trainData),
|
||||
std::move(testData));
|
||||
}
|
||||
|
||||
} // namespace data
|
||||
} // namespace mlpack
|
||||
|
||||
|
||||
@@ -90,11 +90,11 @@ class GaussianDistribution
|
||||
*/
|
||||
void Probability(const arma::mat& x, arma::vec& probabilities) const
|
||||
{
|
||||
probabilities.set_size(x.n_cols);
|
||||
for (size_t i = 0; i < x.n_cols; ++i)
|
||||
{
|
||||
probabilities(i) = Probability(x.unsafe_col(i));
|
||||
}
|
||||
// Use LogProbability(), then transform the log-probabilities out of
|
||||
// logspace.
|
||||
arma::vec logProbs;
|
||||
LogProbability(x, logProbs);
|
||||
probabilities = arma::exp(logProbs);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -110,17 +110,11 @@ class GaussianDistribution
|
||||
// Column i of 'diffs' is the difference between x.col(i) and the mean.
|
||||
arma::mat diffs = x;
|
||||
diffs.each_col() -= mean;
|
||||
// Now, we only want to calculate the diagonal elements of (diffs' * cov^-1
|
||||
// * diffs). We just don't need any of the other elements. We can
|
||||
// calculate the right hand part of the equation (instead of the left side)
|
||||
// so that later we are referencing columns, not rows -- that is faster.
|
||||
const arma::mat rhs = -0.5 * invCov * diffs;
|
||||
arma::vec logExponents(diffs.n_cols); // We will now fill this.
|
||||
for (size_t i = 0; i < diffs.n_cols; ++i)
|
||||
logExponents(i) = accu(diffs.unsafe_col(i) % rhs.unsafe_col(i));
|
||||
|
||||
// Now, we only want to calculate the diagonal elements of (diffs' * cov^-1
|
||||
// * diffs). We just don't need any of the other elements.
|
||||
logProbabilities = -0.5 * x.n_rows * log2pi - 0.5 * logDetCov +
|
||||
logExponents;
|
||||
sum(diffs % (-0.5 * invCov * diffs), 0).t();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -28,7 +28,7 @@ template<typename T>
|
||||
T LogAdd(T x, T y);
|
||||
|
||||
/**
|
||||
* Sum a vector of log values. (T should be an Armadillo type.)
|
||||
* Log-sum a vector of log values. (T should be an Armadillo type.)
|
||||
*
|
||||
* @param x vector of log values
|
||||
* @return log(e^x0 + e^x1 + ...)
|
||||
@@ -36,6 +36,38 @@ T LogAdd(T x, T y);
|
||||
template<typename T>
|
||||
typename T::elem_type AccuLog(const T& x);
|
||||
|
||||
/**
|
||||
* Compute the sum of exponentials of each element in each column, then compute
|
||||
* the log of that. If InPlace is true, then the values of `y` will also be
|
||||
* added to the sum.
|
||||
*
|
||||
* That is, if InPlace is false, then this method will set `y` such that:
|
||||
*
|
||||
* `y_i = log(sum(exp(x.col(i))))`
|
||||
*
|
||||
* and if InPlace is true, then `y` will be set such that:
|
||||
*
|
||||
* `y_i = log(sum(exp(x.col(i))) + exp(y_i))`.
|
||||
*/
|
||||
template<typename T, bool InPlace = false>
|
||||
void LogSumExp(const T& x, arma::Col<typename T::elem_type>& y);
|
||||
|
||||
/**
|
||||
* Compute the sum of exponentials of each element in each row, then compute the
|
||||
* log of that. If InPlace is true, then the values of `y` will also be added
|
||||
* to the sum.
|
||||
*
|
||||
* That is, if InPlace is false, then this method will set `y` such that:
|
||||
*
|
||||
* `y_i = log(sum(exp(x.row(i))))`
|
||||
*
|
||||
* and if InPlace is true, then `y` will be set such that:
|
||||
*
|
||||
* `y_i = log(sum(exp(x.row(i))) + exp(y_i))`.
|
||||
*/
|
||||
template<typename T, bool InPlace = false>
|
||||
void LogSumExpT(const T& x, arma::Col<typename T::elem_type>& y);
|
||||
|
||||
} // namespace math
|
||||
} // namespace mlpack
|
||||
|
||||
|
||||
@@ -47,8 +47,10 @@ T LogAdd(T x, T y)
|
||||
r = y;
|
||||
}
|
||||
|
||||
return (r == -std::numeric_limits<T>::infinity() ||
|
||||
d == -std::numeric_limits<T>::infinity()) ? r : r + log(1 + exp(d));
|
||||
if (std::isinf(d) || std::isinf(r))
|
||||
return r;
|
||||
|
||||
return r + log(1 + exp(d));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -60,15 +62,77 @@ T LogAdd(T x, T y)
|
||||
template<typename T>
|
||||
typename T::elem_type AccuLog(const T& x)
|
||||
{
|
||||
typename T::elem_type sum =
|
||||
-std::numeric_limits<typename T::elem_type>::infinity();
|
||||
typename T::elem_type maxVal = max(x);
|
||||
if (maxVal == -std::numeric_limits<typename T::elem_type>::infinity())
|
||||
return maxVal;
|
||||
|
||||
for (size_t i = 0; i < x.n_elem; ++i)
|
||||
return maxVal + log(sum(exp(x - maxVal)));;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the sum of exponentials of each element in each column, then compute
|
||||
* the log of that. If InPlace is true, then the values of `y` will also be
|
||||
* added to the sum.
|
||||
*/
|
||||
template<typename T, bool InPlace>
|
||||
void LogSumExp(const T& x, arma::Col<typename T::elem_type>& y)
|
||||
{
|
||||
arma::Col<typename T::elem_type> maxs;
|
||||
|
||||
if (InPlace)
|
||||
{
|
||||
sum = LogAdd(sum, x[i]);
|
||||
// Compute the maximum in each column (treating y as a column too).
|
||||
maxs = max(max(x, 1), y);
|
||||
|
||||
y = maxs + log(sum(exp(x - repmat(maxs, 1, x.n_cols)), 1) +
|
||||
exp(y - maxs));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Compute the maximum element in each column.
|
||||
maxs = max(x, 1);
|
||||
|
||||
y = maxs + log(sum(exp(x - repmat(maxs, 1, x.n_cols)), 1));
|
||||
}
|
||||
|
||||
return sum;
|
||||
if (maxs.has_inf())
|
||||
{
|
||||
y.replace(-std::numeric_limits<typename T::elem_type>::quiet_NaN(),
|
||||
-std::numeric_limits<typename T::elem_type>::infinity());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the sum of exponentials of each element in each row, then compute the
|
||||
* log of that. If InPlace is true, then the values of `y` will also be added
|
||||
* to the sum.
|
||||
*/
|
||||
template<typename T, bool InPlace>
|
||||
void LogSumExpT(const T& x, arma::Col<typename T::elem_type>& y)
|
||||
{
|
||||
arma::Row<typename T::elem_type> maxs;
|
||||
|
||||
if (InPlace)
|
||||
{
|
||||
// Compute the maximum element in each column.
|
||||
maxs = max(max(x, 0), y.t());
|
||||
|
||||
y = maxs.t() + log(sum(exp(x - repmat(maxs, x.n_rows, 1)), 0) +
|
||||
exp(y.t() - maxs)).t();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Compute the maximum element in each column.
|
||||
arma::Row<typename T::elem_type> maxs = max(x, 0);
|
||||
|
||||
y = (maxs + log(sum(exp(x - repmat(maxs, x.n_rows, 1)), 0))).t();
|
||||
}
|
||||
|
||||
if (maxs.has_inf())
|
||||
{
|
||||
y.replace(-std::numeric_limits<typename T::elem_type>::quiet_NaN(),
|
||||
-std::numeric_limits<typename T::elem_type>::infinity());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace math
|
||||
|
||||
@@ -42,7 +42,7 @@ inline void RandomSeed(const size_t seed)
|
||||
#if (!defined(BINDING_TYPE) || BINDING_TYPE != BINDING_TYPE_TEST)
|
||||
randGen.seed((uint32_t) seed);
|
||||
#if (BINDING_TYPE == BINDING_TYPE_R)
|
||||
// To suppress Found ‘srand’, possibly from ‘srand’ (C).
|
||||
// To suppress Found 'srand', possibly from 'srand' (C).
|
||||
(void) seed;
|
||||
#else
|
||||
srand((unsigned int) seed);
|
||||
|
||||
@@ -129,23 +129,23 @@ class Timers
|
||||
void PrintTimer(const std::string& timerName);
|
||||
|
||||
/**
|
||||
* Initializes a timer, available like a normal value specified on
|
||||
* the command line. Timers are of type timeval. If a timer is started, then
|
||||
* Initializes a timer, available like a normal value specified on
|
||||
* the command line. Timers are of type timeval. If a timer is started, then
|
||||
* stopped, then re-started, then stopped, the final timer value will be the
|
||||
* length of both runs of the timer.
|
||||
*
|
||||
* @param timerName The name of the timer in question.
|
||||
*
|
||||
* @param timerName The name of the timer in question.
|
||||
* @param threadId Id of the thread accessing the timer.
|
||||
*/
|
||||
*/
|
||||
void StartTimer(const std::string& timerName,
|
||||
const std::thread::id& threadId = std::thread::id());
|
||||
|
||||
/**
|
||||
* Halts the timer, and replaces its value with the delta time from its start.
|
||||
*
|
||||
* @param timerName The name of the timer in question.
|
||||
* Halts the timer, and replaces its value with the delta time from its start.
|
||||
*
|
||||
* @param timerName The name of the timer in question.
|
||||
* @param threadId Id of the thread accessing the timer.
|
||||
*/
|
||||
*/
|
||||
void StopTimer(const std::string& timerName,
|
||||
const std::thread::id& threadId = std::thread::id());
|
||||
|
||||
|
||||
@@ -16,10 +16,10 @@ namespace mlpack {
|
||||
namespace util {
|
||||
|
||||
/**
|
||||
* Convert a string to lowercase letters.
|
||||
*
|
||||
* @param input The string to convert.
|
||||
*/
|
||||
* Convert a string to lowercase letters.
|
||||
*
|
||||
* @param input The string to convert.
|
||||
*/
|
||||
inline std::string ToLower(const std::string& input)
|
||||
{
|
||||
std::string output;
|
||||
|
||||
@@ -31,7 +31,7 @@ namespace amf {
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
* This is a multiplicative rule that ensures that the Kullback–Leibler
|
||||
* This is a multiplicative rule that ensures that the Kullback-Leibler
|
||||
* divergence
|
||||
*
|
||||
* \f[
|
||||
|
||||
@@ -20,6 +20,7 @@ set(SOURCES
|
||||
poisson1_function.hpp
|
||||
gaussian_function.hpp
|
||||
hard_swish_function.hpp
|
||||
tanh_exponential_function.hpp
|
||||
)
|
||||
|
||||
# Add directory name to sources.
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
/**
|
||||
* @file methods/ann/activation_functions/tanh_exponential_function.hpp
|
||||
* @author Mayank Raj
|
||||
*
|
||||
* Definition and implementation of the Tanh exponential function.
|
||||
*
|
||||
* For more information see the following paper
|
||||
*
|
||||
* @code
|
||||
* @misc{The Institution of Engineering and Technology 2015 ,
|
||||
* title = {TanhExp: A Smooth Activation Function with High Convergence Speed for Lightweight Neural Networks},
|
||||
* author = {Xinyu Liu and Xiaoguang Di},
|
||||
* year = {2020},
|
||||
* url = {https://arxiv.org/pdf/2003.09855v2.pdf},
|
||||
* eprint = {2003.09855v2},
|
||||
* archivePrefix = {arXiv},
|
||||
* primaryClass = {cs.LG} }
|
||||
* @endcode
|
||||
*
|
||||
* mlpack is free software; you may redistribute it and/or modify it under the
|
||||
* terms of the 3-clause BSD license. You should have received a copy of the
|
||||
* 3-clause BSD license along with mlpack. If not, see
|
||||
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
|
||||
*/
|
||||
#ifndef MLPACK_METHODS_ANN_ACTIVATION_FUNCTIONS_TANH_EXPONENTIAL_FUNCTION_HPP
|
||||
#define MLPACK_METHODS_ANN_ACTIVATION_FUNCTIONS_TANH_EXPONENTIAL_FUNCTION_HPP
|
||||
|
||||
#include <mlpack/prereqs.hpp>
|
||||
|
||||
namespace mlpack {
|
||||
namespace ann /** Artificial Neural Network. */ {
|
||||
|
||||
/**
|
||||
* The TanhExp function, defined by
|
||||
*
|
||||
* @f{eqnarray*}{
|
||||
* f(x) = x * tanh(e^x)\\
|
||||
* f'(x) = tanh(e^x) - x*e^x*(tanh(e^x)^2 - 1)\\
|
||||
* @f}
|
||||
*/
|
||||
class TanhExpFunction
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Computes the TanhExp function.
|
||||
*
|
||||
* @param x Input data.
|
||||
* @return f(x).
|
||||
*/
|
||||
static double Fn(const double x)
|
||||
{
|
||||
return x * std::tanh(std::exp(x));
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the TanhExp function.
|
||||
*
|
||||
* @param x Input data.
|
||||
* @param y The resulting output activation.
|
||||
*/
|
||||
template<typename InputVecType, typename OutputVecType>
|
||||
static void Fn(const InputVecType& x, OutputVecType& y)
|
||||
{
|
||||
y = x % arma::tanh(arma::exp(x));
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the first derivative of the TanhExp function.
|
||||
*
|
||||
* @param y Input activation.
|
||||
* @return f'(x)
|
||||
*/
|
||||
static double Deriv(const double y)
|
||||
{
|
||||
return std::tanh(std::exp(y)) - y * std::exp(y) *
|
||||
(std::pow(std::tanh(std::exp(y)), 2) - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the first derivatives of the tanh function.
|
||||
*
|
||||
* @param y Input activations.
|
||||
* @param x The resulting derivatives.
|
||||
*/
|
||||
template<typename InputVecType, typename OutputVecType>
|
||||
static void Deriv(const InputVecType& y, OutputVecType& x)
|
||||
{
|
||||
x = arma::tanh(arma::exp(y)) - y % arma::exp(y) %
|
||||
(arma::pow(arma::tanh(arma::exp(y)), 2) - 1);
|
||||
}
|
||||
}; // class TanhExpFunction
|
||||
|
||||
} // namespace ann
|
||||
} // namespace mlpack
|
||||
|
||||
#endif
|
||||
@@ -28,6 +28,7 @@
|
||||
#include <mlpack/methods/ann/activation_functions/elish_function.hpp>
|
||||
#include <mlpack/methods/ann/activation_functions/gaussian_function.hpp>
|
||||
#include <mlpack/methods/ann/activation_functions/hard_swish_function.hpp>
|
||||
#include <mlpack/methods/ann/activation_functions/tanh_exponential_function.hpp>
|
||||
|
||||
namespace mlpack {
|
||||
namespace ann /** Artificial Neural Network. */ {
|
||||
@@ -52,6 +53,7 @@ namespace ann /** Artificial Neural Network. */ {
|
||||
* - ElliotLayer
|
||||
* - GaussianLayer
|
||||
* - HardSwishLayer
|
||||
* - TanhExpLayer
|
||||
*
|
||||
* @tparam ActivationFunction Activation function used for the embedding layer.
|
||||
* @tparam InputDataType Type of the input data (arma::colvec, arma::mat,
|
||||
@@ -290,6 +292,17 @@ template <
|
||||
using HardSwishFunctionLayer = BaseLayer<
|
||||
ActivationFunction, InputDataType, OutputDataType>;
|
||||
|
||||
/**
|
||||
* Standard TanhExp-Layer using the TanhExp activation function.
|
||||
*/
|
||||
template <
|
||||
class ActivationFunction = TanhExpFunction,
|
||||
typename InputDataType = arma::mat,
|
||||
typename OutputDataType = arma::mat
|
||||
>
|
||||
using TanhExpFunctionLayer = BaseLayer<
|
||||
ActivationFunction, InputDataType, OutputDataType>;
|
||||
|
||||
} // namespace ann
|
||||
} // namespace mlpack
|
||||
|
||||
|
||||
@@ -79,6 +79,12 @@ class Constant
|
||||
//! Get the output size.
|
||||
size_t OutSize() const { return outSize; }
|
||||
|
||||
//! Get the size of the weights.
|
||||
size_t WeightSize() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize the layer.
|
||||
*/
|
||||
|
||||
@@ -123,6 +123,12 @@ class LinearNoBias
|
||||
//! Modify the gradient.
|
||||
OutputDataType& Gradient() { return gradient; }
|
||||
|
||||
//! Get the size of the weights.
|
||||
size_t WeightSize() const
|
||||
{
|
||||
return inSize * outSize;
|
||||
}
|
||||
|
||||
//! Get the shape of the input.
|
||||
size_t InputShape() const
|
||||
{
|
||||
|
||||
@@ -38,7 +38,7 @@ LinearNoBias<InputDataType, OutputDataType, RegularizerType>::LinearNoBias(
|
||||
outSize(outSize),
|
||||
regularizer(regularizer)
|
||||
{
|
||||
weights.set_size(outSize * inSize, 1);
|
||||
weights.set_size(WeightSize(), 1);
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType,
|
||||
|
||||
@@ -166,9 +166,17 @@ class MeanPooling
|
||||
for (size_t i = 0, rowidx = 0; i < output.n_rows;
|
||||
++i, rowidx += strideWidth)
|
||||
{
|
||||
size_t rowEnd = rowidx + kernelWidth - 1;
|
||||
size_t colEnd = colidx + kernelHeight - 1;
|
||||
|
||||
if (rowEnd > input.n_rows - 1)
|
||||
rowEnd = input.n_rows - 1;
|
||||
if (colEnd > input.n_cols - 1)
|
||||
colEnd = input.n_cols - 1;
|
||||
|
||||
arma::mat subInput = input(
|
||||
arma::span(rowidx, rowidx + kernelWidth - 1 - offset),
|
||||
arma::span(colidx, colidx + kernelHeight - 1 - offset));
|
||||
arma::span(rowidx, rowEnd),
|
||||
arma::span(colidx, colEnd));
|
||||
|
||||
output(i, j) = arma::mean(arma::mean(subInput));
|
||||
}
|
||||
@@ -186,22 +194,36 @@ class MeanPooling
|
||||
const arma::Mat<eT>& error,
|
||||
arma::Mat<eT>& output)
|
||||
{
|
||||
const size_t rStep = input.n_rows / error.n_rows - offset;
|
||||
const size_t cStep = input.n_cols / error.n_cols - offset;
|
||||
|
||||
arma::Mat<eT> unpooledError;
|
||||
for (size_t j = 0; j < input.n_cols - cStep; j += cStep)
|
||||
for (size_t j = 0, colidx = 0; j < input.n_cols; j += strideHeight, colidx++)
|
||||
{
|
||||
for (size_t i = 0; i < input.n_rows - rStep; i += rStep)
|
||||
{
|
||||
const arma::Mat<eT>& inputArea = input(arma::span(i, i + rStep - 1),
|
||||
arma::span(j, j + cStep - 1));
|
||||
for (size_t i = 0, rowidx = 0; i < input.n_rows; i += strideWidth, rowidx++)
|
||||
{
|
||||
size_t rowEnd = i + kernelWidth - 1;
|
||||
size_t colEnd = j + kernelHeight - 1;
|
||||
|
||||
unpooledError = arma::Mat<eT>(inputArea.n_rows, inputArea.n_cols);
|
||||
unpooledError.fill(error(i / rStep, j / cStep) / inputArea.n_elem);
|
||||
if (rowEnd > input.n_rows - 1)
|
||||
{
|
||||
if (floor)
|
||||
continue;
|
||||
rowEnd = input.n_rows - 1;
|
||||
}
|
||||
|
||||
output(arma::span(i, i + rStep - 1 - offset),
|
||||
arma::span(j, j + cStep - 1 - offset)) += unpooledError;
|
||||
if (colEnd > input.n_cols - 1)
|
||||
{
|
||||
if (floor)
|
||||
continue;
|
||||
colEnd = input.n_cols - 1;
|
||||
}
|
||||
|
||||
arma::mat InputArea = input(arma::span(i, rowEnd), arma::span(j, colEnd));
|
||||
|
||||
unpooledError = arma::Mat<eT>(InputArea.n_rows, InputArea.n_cols);
|
||||
unpooledError.fill(error(rowidx, colidx) / InputArea.n_elem);
|
||||
|
||||
output(arma::span(i, i + InputArea.n_rows - 1),
|
||||
arma::span(j, j + InputArea.n_cols - 1)) += unpooledError;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -245,9 +267,6 @@ class MeanPooling
|
||||
//! If true use maximum a posteriori during the forward pass.
|
||||
bool deterministic;
|
||||
|
||||
//! Locally-stored stored rounding offset.
|
||||
size_t offset;
|
||||
|
||||
//! Locally-stored number of input units.
|
||||
size_t batchSize;
|
||||
|
||||
|
||||
@@ -45,7 +45,6 @@ MeanPooling<InputDataType, OutputDataType>::MeanPooling(
|
||||
outputHeight(0),
|
||||
reset(false),
|
||||
deterministic(false),
|
||||
offset(0),
|
||||
batchSize(0)
|
||||
{
|
||||
// Nothing to do here.
|
||||
@@ -67,8 +66,6 @@ void MeanPooling<InputDataType, OutputDataType>::Forward(
|
||||
(double) kernelWidth) / (double) strideWidth + 1);
|
||||
outputHeight = std::floor((inputHeight -
|
||||
(double) kernelHeight) / (double) strideHeight + 1);
|
||||
|
||||
offset = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -76,8 +73,6 @@ void MeanPooling<InputDataType, OutputDataType>::Forward(
|
||||
(double) kernelWidth) / (double) strideWidth + 1);
|
||||
outputHeight = std::ceil((inputHeight -
|
||||
(double) kernelHeight) / (double) strideHeight + 1);
|
||||
|
||||
offset = 1;
|
||||
}
|
||||
|
||||
outputTemp = arma::zeros<arma::Cube<eT> >(outputWidth, outputHeight,
|
||||
|
||||
@@ -110,6 +110,12 @@ class RBF
|
||||
//! Modify the delta.
|
||||
OutputDataType& Delta() { return delta; }
|
||||
|
||||
//! Get the size of the weights.
|
||||
size_t WeightSize() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
//! Get the shape of the input.
|
||||
size_t InputShape() const
|
||||
{
|
||||
|
||||
@@ -18,12 +18,12 @@ using namespace mlpack::regression;
|
||||
|
||||
BayesianLinearRegression::BayesianLinearRegression(const bool centerData,
|
||||
const bool scaleData,
|
||||
const size_t nIterMax,
|
||||
const double tol) :
|
||||
const size_t maxIterations,
|
||||
const double tolerance) :
|
||||
centerData(centerData),
|
||||
scaleData(scaleData),
|
||||
nIterMax(nIterMax),
|
||||
tol(tol),
|
||||
maxIterations(maxIterations),
|
||||
tolerance(tolerance),
|
||||
responsesOffset(0.0),
|
||||
alpha(0.0),
|
||||
beta(0.0),
|
||||
@@ -60,7 +60,7 @@ double BayesianLinearRegression::Train(const arma::mat& data,
|
||||
unsigned short i = 0;
|
||||
double deltaAlpha = 1.0, deltaBeta = 1.0, crit = 1.0;
|
||||
|
||||
while ((crit > tol) && (i < nIterMax))
|
||||
while ((crit > tolerance) && (i < maxIterations))
|
||||
{
|
||||
deltaAlpha = -alpha;
|
||||
deltaBeta = -beta;
|
||||
|
||||
@@ -21,30 +21,30 @@ namespace mlpack {
|
||||
namespace regression {
|
||||
|
||||
/**
|
||||
* A Bayesian approach to the maximum likelihood estimation of the parameters
|
||||
* \f$ \omega \f$ of the linear regression model. The Complexity is governed by
|
||||
* the addition of a gaussian isotropic prior of precision \f$ \alpha \f$ over
|
||||
* \f$ \omega \f$:
|
||||
* A Bayesian approach to the maximum likelihood estimation of the parameters
|
||||
* \f$ \omega \f$ of the linear regression model. The Complexity is governed by
|
||||
* the addition of a gaussian isotropic prior of precision \f$ \alpha \f$ over
|
||||
* \f$ \omega \f$:
|
||||
*
|
||||
* \f[
|
||||
* p(\omega|\alpha) = \mathcal{N}(\omega|0, \alpha^{-1}I)
|
||||
* \f]
|
||||
*
|
||||
* The optimization procedure calculates the posterior distribution of
|
||||
* \f$ \omega \f$ knowing the data by maximizing an approximation of the log
|
||||
* marginal likelihood derived from a type II maximum likelihood approximation.
|
||||
*
|
||||
* The optimization procedure calculates the posterior distribution of
|
||||
* \f$ \omega \f$ knowing the data by maximizing an approximation of the log
|
||||
* marginal likelihood derived from a type II maximum likelihood approximation.
|
||||
* The determination of \f$ alpha \f$ and of the noise precision \f$ beta \f$
|
||||
* is part of the optimization process, leading to an automatic determination of
|
||||
* w. The model being entirely based on probabilty distributions, uncertainties
|
||||
* is part of the optimization process, leading to an automatic determination of
|
||||
* w. The model being entirely based on probabilty distributions, uncertainties
|
||||
* are available and easly computed for both the parameters and the predictions.
|
||||
*
|
||||
* The advantage over linear regression and ridge regression is that the
|
||||
* The advantage over linear regression and ridge regression is that the
|
||||
* regularization is determined from all the training data alone without any
|
||||
* require to an hold out method.
|
||||
* require to an hold out method.
|
||||
*
|
||||
* The code below is an implementation of the maximization of the evidence
|
||||
* The code below is an implementation of the maximization of the evidence
|
||||
* function described in the section 3.5.2 of the C.Bishop book, Pattern
|
||||
* Recognition and Machine Learning.
|
||||
* Recognition and Machine Learning.
|
||||
*
|
||||
* @code
|
||||
* @article{MacKay91bayesianinterpolation,
|
||||
@@ -60,36 +60,37 @@ namespace regression {
|
||||
* @code
|
||||
* @book{Bishop:2006:PRM:1162264,
|
||||
* author = {Bishop, Christopher M.},
|
||||
* title = {Pattern Recognition and Machine Learning (Information Science
|
||||
* title = {Pattern Recognition and Machine Learning (Information Science
|
||||
* and Statistics)},
|
||||
* chapter = {3}
|
||||
* year = {2006},
|
||||
* isbn = {0387310738},
|
||||
* publisher = {Springer-Verlag},
|
||||
* address = {Berlin, Heidelberg},
|
||||
* }
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
*
|
||||
* Example of use:
|
||||
*
|
||||
* @code
|
||||
* arma::mat xTrain; // Train data matrix. Column-major.
|
||||
* arma::rowvec yTrain; // Train target values.
|
||||
|
||||
*
|
||||
* // Train the model. Regularization strength is optimally tunned with the
|
||||
* // training data alone by applying the Train method.
|
||||
* BayesianLinearRegression estimator(); // Instanciate the estimator with default option.
|
||||
* // Instantiate the estimator with default option.
|
||||
* BayesianLinearRegression estimator;
|
||||
* estimator.Train(xTrain, yTrain);
|
||||
|
||||
*
|
||||
* // Prediction on test points.
|
||||
* arma::mat xTest; // Test data matrix. Column-major.
|
||||
* arma::rowvec predictions;
|
||||
|
||||
*
|
||||
* estimator.Predict(xTest, prediction);
|
||||
|
||||
*
|
||||
* arma::rowvec yTest; // Test target values.
|
||||
* estimator.RMSE(xTest, yTest); // Evaluate using the RMSE score.
|
||||
|
||||
*
|
||||
* // Compute the standard deviations of the predictions.
|
||||
* arma::rowvec stds;
|
||||
* estimator.Predict(xTest, responses, stds)
|
||||
@@ -107,19 +108,20 @@ class BayesianLinearRegression
|
||||
* examples.
|
||||
* @param scaleData Whether or not scale the data according to the
|
||||
* standard deviation of each feature.
|
||||
* @param nIterMax Maximum number of iterations for convergency.
|
||||
* @param tol Level from which the solution is considered sufficientlly
|
||||
* stable.
|
||||
* @param maxIterations Maximum number of iterations for convergency.
|
||||
* @param tolerance Level from which the solution is considered sufficientlly
|
||||
* stable.
|
||||
*/
|
||||
BayesianLinearRegression(const bool centerData = true,
|
||||
const bool scaleData = false,
|
||||
const size_t nIterMax = 50,
|
||||
const double tol = 1e-4);
|
||||
const size_t maxIterations = 50,
|
||||
const double tolerance = 1e-4);
|
||||
|
||||
/**
|
||||
* Run BayesianLinearRegression. The input matrix (like all mlpack matrices) should be
|
||||
* column-major -- each column is an observation and each row is a dimension.
|
||||
*
|
||||
* Run BayesianLinearRegression. The input matrix (like all mlpack matrices)
|
||||
* should be column-major -- each column is an observation and each row is a
|
||||
* dimension.
|
||||
*
|
||||
* @param data Column-major input data, dim(P, N).
|
||||
* @param responses A vector of targets, dim(N).
|
||||
* @return Root mean squared error.
|
||||
@@ -139,12 +141,13 @@ class BayesianLinearRegression
|
||||
arma::rowvec& predictions) const;
|
||||
|
||||
/**
|
||||
* Predict \f$y_{i}\f$ and the standard deviation of the predictive posterior
|
||||
* Predict \f$y_{i}\f$ and the standard deviation of the predictive posterior
|
||||
* distribution for each data point in the given data matrix, using the
|
||||
* currently-trained Bayesian Ridge estimator.
|
||||
*
|
||||
* @param points The data point to apply the model.
|
||||
* @param predictions Vector which will contain calculated values on completion.
|
||||
* @param predictions Vector which will contain calculated values on
|
||||
* completion.
|
||||
* @param std Standard deviations of the predictions.
|
||||
*/
|
||||
void Predict(const arma::mat& points,
|
||||
@@ -163,7 +166,7 @@ class BayesianLinearRegression
|
||||
const arma::rowvec& responses) const;
|
||||
|
||||
/**
|
||||
* Get the solution vector.
|
||||
* Get the solution vector.
|
||||
*
|
||||
* @return omega Solution vector.
|
||||
*/
|
||||
@@ -187,7 +190,7 @@ class BayesianLinearRegression
|
||||
|
||||
/**
|
||||
* Get the estimated variance. Train() must be called before.
|
||||
*
|
||||
*
|
||||
* @return 1.0 / \f$ \beta \f$
|
||||
*/
|
||||
double Variance() const { return 1.0 / Beta(); }
|
||||
@@ -200,7 +203,7 @@ class BayesianLinearRegression
|
||||
const arma::colvec& DataOffset() const { return dataOffset; }
|
||||
|
||||
/**
|
||||
* Get the vector of standard deviations computed on the features over the
|
||||
* Get the vector of standard deviations computed on the features over the
|
||||
* training points.
|
||||
*
|
||||
* @return dataOffset
|
||||
@@ -214,9 +217,31 @@ class BayesianLinearRegression
|
||||
*/
|
||||
double ResponsesOffset() const { return responsesOffset; }
|
||||
|
||||
//! Get whether the data will be centered during training.
|
||||
bool CenterData() const { return centerData; }
|
||||
//! Modify whether the data will be centered during training.
|
||||
bool& CenterData() { return centerData; }
|
||||
|
||||
//! Get whether the data will be scaled by standard deviations during
|
||||
//! training.
|
||||
bool ScaleData() const { return scaleData; }
|
||||
//! Modify whether the data will be scaled by standard deviations during
|
||||
//! training.
|
||||
bool& ScaleData() { return scaleData; }
|
||||
|
||||
//! Get the maximum number of iterations for training.
|
||||
size_t MaxIterations() const { return maxIterations; }
|
||||
//! Modify the maximum number of iterations for training.
|
||||
size_t& MaxIterations() { return maxIterations; }
|
||||
|
||||
//! Get the tolerance for training to converge.
|
||||
double Tolerance() const { return tolerance; }
|
||||
//! Modify the tolerance for training to converge.
|
||||
double& Tolerance() { return tolerance; }
|
||||
|
||||
/**
|
||||
* Serialize the BayesianLinearRegression model.
|
||||
**/
|
||||
*/
|
||||
template<typename Archive>
|
||||
void serialize(Archive& ar, const uint32_t version);
|
||||
|
||||
@@ -227,11 +252,11 @@ class BayesianLinearRegression
|
||||
//! Scale the data by standard deviations if true.
|
||||
bool scaleData;
|
||||
|
||||
//! Maximum number of iterations for convergency.
|
||||
size_t nIterMax;
|
||||
//! Maximum number of iterations for convergence.
|
||||
size_t maxIterations;
|
||||
|
||||
//! Level from which the solution is considered sufficientlly stable.
|
||||
double tol;
|
||||
double tolerance;
|
||||
|
||||
//! Mean vector computed over the points.
|
||||
arma::colvec dataOffset;
|
||||
@@ -251,7 +276,7 @@ class BayesianLinearRegression
|
||||
//! Effective number of parameters.
|
||||
double gamma;
|
||||
|
||||
//! Solution vector
|
||||
//! Solution vector.
|
||||
arma::colvec omega;
|
||||
|
||||
//! Covariance matrix of the solution vector omega.
|
||||
|
||||
@@ -26,8 +26,8 @@ void BayesianLinearRegression::serialize(Archive& ar,
|
||||
{
|
||||
ar(CEREAL_NVP(centerData));
|
||||
ar(CEREAL_NVP(scaleData));
|
||||
ar(CEREAL_NVP(nIterMax));
|
||||
ar(CEREAL_NVP(tol));
|
||||
ar(CEREAL_NVP(maxIterations));
|
||||
ar(CEREAL_NVP(tolerance));
|
||||
ar(CEREAL_NVP(dataOffset));
|
||||
ar(CEREAL_NVP(dataScale));
|
||||
ar(CEREAL_NVP(responsesOffset));
|
||||
|
||||
@@ -83,7 +83,7 @@ void RandomizedBlockKrylovSVD::Apply(const arma::mat& data,
|
||||
|
||||
arma::qr_econ(Q, R, K);
|
||||
|
||||
// Approximate eigenvalues and eigenvectors using Rayleigh–Ritz method.
|
||||
// Approximate eigenvalues and eigenvectors using Rayleigh-Ritz method.
|
||||
arma::svd_econ(u, s, v, Q.t() * data);
|
||||
|
||||
// Do economical singular value decomposition and compute only the
|
||||
|
||||
@@ -29,7 +29,6 @@ class AllCategoricalSplit
|
||||
{
|
||||
public:
|
||||
// No extra info needed for split.
|
||||
template<typename ElemType>
|
||||
class AuxiliarySplitInfo { };
|
||||
|
||||
/**
|
||||
@@ -64,8 +63,8 @@ class AllCategoricalSplit
|
||||
const WeightVecType& weights,
|
||||
const size_t minimumLeafSize,
|
||||
const double minimumGainSplit,
|
||||
arma::Col<typename VecType::elem_type>& classProbabilities,
|
||||
AuxiliarySplitInfo<typename VecType::elem_type>& aux);
|
||||
arma::vec& classProbabilities,
|
||||
AuxiliarySplitInfo& aux);
|
||||
|
||||
/**
|
||||
* Return the number of children in the split.
|
||||
@@ -73,9 +72,8 @@ class AllCategoricalSplit
|
||||
* @param classProbabilities Auxiliary information for the split.
|
||||
* @param * (aux) Auxiliary information for the split (Unused).
|
||||
*/
|
||||
template<typename ElemType>
|
||||
static size_t NumChildren(const arma::Col<ElemType>& classProbabilities,
|
||||
const AuxiliarySplitInfo<ElemType>& /* aux */);
|
||||
static size_t NumChildren(const arma::vec& classProbabilities,
|
||||
const AuxiliarySplitInfo& /* aux */);
|
||||
|
||||
/**
|
||||
* Calculate the direction a point should percolate to.
|
||||
@@ -87,8 +85,8 @@ class AllCategoricalSplit
|
||||
template<typename ElemType>
|
||||
static size_t CalculateDirection(
|
||||
const ElemType& point,
|
||||
const arma::Col<ElemType>& classProbabilities,
|
||||
const AuxiliarySplitInfo<ElemType>& /* aux */);
|
||||
const arma::vec& classProbabilities,
|
||||
const AuxiliarySplitInfo& /* aux */);
|
||||
};
|
||||
|
||||
} // namespace tree
|
||||
|
||||
@@ -26,8 +26,8 @@ double AllCategoricalSplit<FitnessFunction>::SplitIfBetter(
|
||||
const WeightVecType& weights,
|
||||
const size_t minimumLeafSize,
|
||||
const double minimumGainSplit,
|
||||
arma::Col<typename VecType::elem_type>& classProbabilities,
|
||||
AuxiliarySplitInfo<typename VecType::elem_type>& /* aux */)
|
||||
arma::vec& classProbabilities,
|
||||
AuxiliarySplitInfo& /* aux */)
|
||||
{
|
||||
// Count the number of elements in each potential child.
|
||||
const double epsilon = 1e-7; // Tolerance for floating-point errors.
|
||||
@@ -110,20 +110,19 @@ double AllCategoricalSplit<FitnessFunction>::SplitIfBetter(
|
||||
}
|
||||
|
||||
template<typename FitnessFunction>
|
||||
template<typename ElemType>
|
||||
size_t AllCategoricalSplit<FitnessFunction>::NumChildren(
|
||||
const arma::Col<ElemType>& classProbabilities,
|
||||
const AuxiliarySplitInfo<ElemType>& /* aux */)
|
||||
const arma::vec& classProbabilities,
|
||||
const AuxiliarySplitInfo& /* aux */)
|
||||
{
|
||||
return classProbabilities[0];
|
||||
return size_t(classProbabilities[0]);
|
||||
}
|
||||
|
||||
template<typename FitnessFunction>
|
||||
template<typename ElemType>
|
||||
size_t AllCategoricalSplit<FitnessFunction>::CalculateDirection(
|
||||
const ElemType& point,
|
||||
const arma::Col<ElemType>& /* classProbabilities */,
|
||||
const AuxiliarySplitInfo<ElemType>& /* aux */)
|
||||
const arma::vec& /* classProbabilities */,
|
||||
const AuxiliarySplitInfo& /* aux */)
|
||||
{
|
||||
return (size_t) point;
|
||||
}
|
||||
|
||||
@@ -28,7 +28,6 @@ class BestBinaryNumericSplit
|
||||
{
|
||||
public:
|
||||
// No extra info needed for split.
|
||||
template<typename ElemType>
|
||||
class AuxiliarySplitInfo { };
|
||||
|
||||
/**
|
||||
@@ -37,6 +36,10 @@ class BestBinaryNumericSplit
|
||||
* return the value 'bestGain'. If a split is made, then classProbabilities
|
||||
* and aux may be modified.
|
||||
*
|
||||
* It's not necessary that `ElemType` is the same as the type of the data in
|
||||
* `VecType`---if they are different, casting will be done to store the
|
||||
* auxiliary information.
|
||||
*
|
||||
* @param bestGain Best gain seen so far (we'll only split if we find gain
|
||||
* better than this).
|
||||
* @param data The dimension of data points to check for a split in.
|
||||
@@ -60,15 +63,14 @@ class BestBinaryNumericSplit
|
||||
const WeightVecType& weights,
|
||||
const size_t minimumLeafSize,
|
||||
const double minimumGainSplit,
|
||||
arma::Col<typename VecType::elem_type>& classProbabilities,
|
||||
AuxiliarySplitInfo<typename VecType::elem_type>& aux);
|
||||
arma::vec& classProbabilities,
|
||||
AuxiliarySplitInfo& aux);
|
||||
|
||||
/**
|
||||
* Returns 2, since the binary split always has two children.
|
||||
*/
|
||||
template<typename ElemType>
|
||||
static size_t NumChildren(const arma::Col<ElemType>& /* classProbabilities */,
|
||||
const AuxiliarySplitInfo<ElemType>& /* aux */)
|
||||
static size_t NumChildren(const arma::vec& /* classProbabilities */,
|
||||
const AuxiliarySplitInfo& /* aux */)
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
@@ -83,8 +85,8 @@ class BestBinaryNumericSplit
|
||||
template<typename ElemType>
|
||||
static size_t CalculateDirection(
|
||||
const ElemType& point,
|
||||
const arma::Col<ElemType>& classProbabilities,
|
||||
const AuxiliarySplitInfo<ElemType>& /* aux */);
|
||||
const arma::vec& classProbabilities,
|
||||
const AuxiliarySplitInfo& /* aux */);
|
||||
};
|
||||
|
||||
} // namespace tree
|
||||
|
||||
@@ -25,8 +25,8 @@ double BestBinaryNumericSplit<FitnessFunction>::SplitIfBetter(
|
||||
const WeightVecType& weights,
|
||||
const size_t minimumLeafSize,
|
||||
const double minimumGainSplit,
|
||||
arma::Col<typename VecType::elem_type>& classProbabilities,
|
||||
AuxiliarySplitInfo<typename VecType::elem_type>& /* aux */)
|
||||
arma::vec& classProbabilities,
|
||||
AuxiliarySplitInfo& /* aux */)
|
||||
{
|
||||
// First sanity check: if we don't have enough points, we can't split.
|
||||
if (data.n_elem < (minimumLeafSize * 2))
|
||||
@@ -189,8 +189,8 @@ template<typename FitnessFunction>
|
||||
template<typename ElemType>
|
||||
size_t BestBinaryNumericSplit<FitnessFunction>::CalculateDirection(
|
||||
const ElemType& point,
|
||||
const arma::Col<ElemType>& classProbabilities,
|
||||
const AuxiliarySplitInfo<ElemType>& /* aux */)
|
||||
const arma::vec& classProbabilities,
|
||||
const AuxiliarySplitInfo& /* aux */)
|
||||
{
|
||||
if (point <= classProbabilities[0])
|
||||
return 0; // Go left.
|
||||
|
||||
@@ -30,18 +30,20 @@ namespace tree {
|
||||
*
|
||||
* The class inherits from the auxiliary split information in order to prevent
|
||||
* an empty auxiliary split information struct from taking any extra size.
|
||||
*
|
||||
* Note that `ElemType` is a template parameter controlling the type that is
|
||||
* used to store split information. In general, you would want to set this to
|
||||
* be the same as the type of the data that you will be using, but it's not
|
||||
* required to do that.
|
||||
*/
|
||||
template<typename FitnessFunction = GiniGain,
|
||||
template<typename> class NumericSplitType = BestBinaryNumericSplit,
|
||||
template<typename> class CategoricalSplitType = AllCategoricalSplit,
|
||||
typename DimensionSelectionType = AllDimensionSelect,
|
||||
typename ElemType = double,
|
||||
bool NoRecursion = false>
|
||||
class DecisionTree :
|
||||
public NumericSplitType<FitnessFunction>::template
|
||||
AuxiliarySplitInfo<ElemType>,
|
||||
public CategoricalSplitType<FitnessFunction>::template
|
||||
AuxiliarySplitInfo<ElemType>
|
||||
public NumericSplitType<FitnessFunction>::AuxiliarySplitInfo,
|
||||
public CategoricalSplitType<FitnessFunction>::AuxiliarySplitInfo
|
||||
{
|
||||
public:
|
||||
//! Allow access to the numeric split type.
|
||||
@@ -500,9 +502,9 @@ class DecisionTree :
|
||||
//! Note that this class will also hold the members of the NumericSplit and
|
||||
//! CategoricalSplit AuxiliarySplitInfo classes, since it inherits from them.
|
||||
//! We'll define some convenience typedefs here.
|
||||
typedef typename NumericSplit::template AuxiliarySplitInfo<ElemType>
|
||||
typedef typename NumericSplit::AuxiliarySplitInfo
|
||||
NumericAuxiliarySplitInfo;
|
||||
typedef typename CategoricalSplit::template AuxiliarySplitInfo<ElemType>
|
||||
typedef typename CategoricalSplit::AuxiliarySplitInfo
|
||||
CategoricalAuxiliarySplitInfo;
|
||||
|
||||
/**
|
||||
@@ -578,13 +580,11 @@ class DecisionTree :
|
||||
template<typename FitnessFunction = GiniGain,
|
||||
template<typename> class NumericSplitType = BestBinaryNumericSplit,
|
||||
template<typename> class CategoricalSplitType = AllCategoricalSplit,
|
||||
typename DimensionSelectType = AllDimensionSelect,
|
||||
typename ElemType = double>
|
||||
typename DimensionSelectType = AllDimensionSelect>
|
||||
using DecisionStump = DecisionTree<FitnessFunction,
|
||||
NumericSplitType,
|
||||
CategoricalSplitType,
|
||||
DimensionSelectType,
|
||||
ElemType,
|
||||
false>;
|
||||
|
||||
/**
|
||||
@@ -595,7 +595,6 @@ typedef DecisionTree<InformationGain,
|
||||
BestBinaryNumericSplit,
|
||||
AllCategoricalSplit,
|
||||
AllDimensionSelect,
|
||||
double,
|
||||
true> ID3DecisionStump;
|
||||
} // namespace tree
|
||||
} // namespace mlpack
|
||||
|
||||
@@ -22,14 +22,12 @@ template<typename FitnessFunction,
|
||||
template<typename> class NumericSplitType,
|
||||
template<typename> class CategoricalSplitType,
|
||||
typename DimensionSelectionType,
|
||||
typename ElemType,
|
||||
bool NoRecursion>
|
||||
template<typename MatType, typename LabelsType>
|
||||
DecisionTree<FitnessFunction,
|
||||
NumericSplitType,
|
||||
CategoricalSplitType,
|
||||
DimensionSelectionType,
|
||||
ElemType,
|
||||
NoRecursion>::DecisionTree(
|
||||
MatType data,
|
||||
const data::DatasetInfo& datasetInfo,
|
||||
@@ -62,14 +60,12 @@ template<typename FitnessFunction,
|
||||
template<typename> class NumericSplitType,
|
||||
template<typename> class CategoricalSplitType,
|
||||
typename DimensionSelectionType,
|
||||
typename ElemType,
|
||||
bool NoRecursion>
|
||||
template<typename MatType, typename LabelsType>
|
||||
DecisionTree<FitnessFunction,
|
||||
NumericSplitType,
|
||||
CategoricalSplitType,
|
||||
DimensionSelectionType,
|
||||
ElemType,
|
||||
NoRecursion>::DecisionTree(
|
||||
MatType data,
|
||||
LabelsType labels,
|
||||
@@ -100,14 +96,12 @@ template<typename FitnessFunction,
|
||||
template<typename> class NumericSplitType,
|
||||
template<typename> class CategoricalSplitType,
|
||||
typename DimensionSelectionType,
|
||||
typename ElemType,
|
||||
bool NoRecursion>
|
||||
template<typename MatType, typename LabelsType, typename WeightsType>
|
||||
DecisionTree<FitnessFunction,
|
||||
NumericSplitType,
|
||||
CategoricalSplitType,
|
||||
DimensionSelectionType,
|
||||
ElemType,
|
||||
NoRecursion>::DecisionTree(
|
||||
MatType data,
|
||||
const data::DatasetInfo& datasetInfo,
|
||||
@@ -144,14 +138,12 @@ template<typename FitnessFunction,
|
||||
template<typename> class NumericSplitType,
|
||||
template<typename> class CategoricalSplitType,
|
||||
typename DimensionSelectionType,
|
||||
typename ElemType,
|
||||
bool NoRecursion>
|
||||
template<typename MatType, typename LabelsType, typename WeightsType>
|
||||
DecisionTree<FitnessFunction,
|
||||
NumericSplitType,
|
||||
CategoricalSplitType,
|
||||
DimensionSelectionType,
|
||||
ElemType,
|
||||
NoRecursion>::DecisionTree(
|
||||
const DecisionTree& other,
|
||||
MatType data,
|
||||
@@ -185,14 +177,12 @@ template<typename FitnessFunction,
|
||||
template<typename> class NumericSplitType,
|
||||
template<typename> class CategoricalSplitType,
|
||||
typename DimensionSelectionType,
|
||||
typename ElemType,
|
||||
bool NoRecursion>
|
||||
template<typename MatType, typename LabelsType, typename WeightsType>
|
||||
DecisionTree<FitnessFunction,
|
||||
NumericSplitType,
|
||||
CategoricalSplitType,
|
||||
DimensionSelectionType,
|
||||
ElemType,
|
||||
NoRecursion>::DecisionTree(
|
||||
MatType data,
|
||||
LabelsType labels,
|
||||
@@ -229,14 +219,12 @@ template<typename FitnessFunction,
|
||||
template<typename> class NumericSplitType,
|
||||
template<typename> class CategoricalSplitType,
|
||||
typename DimensionSelectionType,
|
||||
typename ElemType,
|
||||
bool NoRecursion>
|
||||
template<typename MatType, typename LabelsType, typename WeightsType>
|
||||
DecisionTree<FitnessFunction,
|
||||
NumericSplitType,
|
||||
CategoricalSplitType,
|
||||
DimensionSelectionType,
|
||||
ElemType,
|
||||
NoRecursion>::DecisionTree(
|
||||
const DecisionTree& other,
|
||||
MatType data,
|
||||
@@ -275,13 +263,11 @@ template<typename FitnessFunction,
|
||||
template<typename> class NumericSplitType,
|
||||
template<typename> class CategoricalSplitType,
|
||||
typename DimensionSelectionType,
|
||||
typename ElemType,
|
||||
bool NoRecursion>
|
||||
DecisionTree<FitnessFunction,
|
||||
NumericSplitType,
|
||||
CategoricalSplitType,
|
||||
DimensionSelectionType,
|
||||
ElemType,
|
||||
NoRecursion>::DecisionTree(const size_t numClasses) :
|
||||
splitDimension(0),
|
||||
dimensionTypeOrMajorityClass(0),
|
||||
@@ -296,13 +282,11 @@ template<typename FitnessFunction,
|
||||
template<typename> class NumericSplitType,
|
||||
template<typename> class CategoricalSplitType,
|
||||
typename DimensionSelectionType,
|
||||
typename ElemType,
|
||||
bool NoRecursion>
|
||||
DecisionTree<FitnessFunction,
|
||||
NumericSplitType,
|
||||
CategoricalSplitType,
|
||||
DimensionSelectionType,
|
||||
ElemType,
|
||||
NoRecursion>::DecisionTree(const DecisionTree& other) :
|
||||
NumericAuxiliarySplitInfo(other),
|
||||
CategoricalAuxiliarySplitInfo(other),
|
||||
@@ -320,13 +304,11 @@ template<typename FitnessFunction,
|
||||
template<typename> class NumericSplitType,
|
||||
template<typename> class CategoricalSplitType,
|
||||
typename DimensionSelectionType,
|
||||
typename ElemType,
|
||||
bool NoRecursion>
|
||||
DecisionTree<FitnessFunction,
|
||||
NumericSplitType,
|
||||
CategoricalSplitType,
|
||||
DimensionSelectionType,
|
||||
ElemType,
|
||||
NoRecursion>::DecisionTree(DecisionTree&& other) :
|
||||
NumericAuxiliarySplitInfo(std::move(other)),
|
||||
CategoricalAuxiliarySplitInfo(std::move(other)),
|
||||
@@ -344,19 +326,16 @@ template<typename FitnessFunction,
|
||||
template<typename> class NumericSplitType,
|
||||
template<typename> class CategoricalSplitType,
|
||||
typename DimensionSelectionType,
|
||||
typename ElemType,
|
||||
bool NoRecursion>
|
||||
DecisionTree<FitnessFunction,
|
||||
NumericSplitType,
|
||||
CategoricalSplitType,
|
||||
DimensionSelectionType,
|
||||
ElemType,
|
||||
NoRecursion>&
|
||||
DecisionTree<FitnessFunction,
|
||||
NumericSplitType,
|
||||
CategoricalSplitType,
|
||||
DimensionSelectionType,
|
||||
ElemType,
|
||||
NoRecursion>::operator=(const DecisionTree& other)
|
||||
{
|
||||
if (this == &other)
|
||||
@@ -388,19 +367,16 @@ template<typename FitnessFunction,
|
||||
template<typename> class NumericSplitType,
|
||||
template<typename> class CategoricalSplitType,
|
||||
typename DimensionSelectionType,
|
||||
typename ElemType,
|
||||
bool NoRecursion>
|
||||
DecisionTree<FitnessFunction,
|
||||
NumericSplitType,
|
||||
CategoricalSplitType,
|
||||
DimensionSelectionType,
|
||||
ElemType,
|
||||
NoRecursion>&
|
||||
DecisionTree<FitnessFunction,
|
||||
NumericSplitType,
|
||||
CategoricalSplitType,
|
||||
DimensionSelectionType,
|
||||
ElemType,
|
||||
NoRecursion>::operator=(DecisionTree&& other)
|
||||
{
|
||||
if (this == &other)
|
||||
@@ -432,13 +408,11 @@ template<typename FitnessFunction,
|
||||
template<typename> class NumericSplitType,
|
||||
template<typename> class CategoricalSplitType,
|
||||
typename DimensionSelectionType,
|
||||
typename ElemType,
|
||||
bool NoRecursion>
|
||||
DecisionTree<FitnessFunction,
|
||||
NumericSplitType,
|
||||
CategoricalSplitType,
|
||||
DimensionSelectionType,
|
||||
ElemType,
|
||||
NoRecursion>::~DecisionTree()
|
||||
{
|
||||
for (size_t i = 0; i < children.size(); ++i)
|
||||
@@ -450,14 +424,12 @@ template<typename FitnessFunction,
|
||||
template<typename> class NumericSplitType,
|
||||
template<typename> class CategoricalSplitType,
|
||||
typename DimensionSelectionType,
|
||||
typename ElemType,
|
||||
bool NoRecursion>
|
||||
template<typename MatType, typename LabelsType>
|
||||
double DecisionTree<FitnessFunction,
|
||||
NumericSplitType,
|
||||
CategoricalSplitType,
|
||||
DimensionSelectionType,
|
||||
ElemType,
|
||||
NoRecursion>::Train(
|
||||
MatType data,
|
||||
const data::DatasetInfo& datasetInfo,
|
||||
@@ -493,14 +465,12 @@ template<typename FitnessFunction,
|
||||
template<typename> class NumericSplitType,
|
||||
template<typename> class CategoricalSplitType,
|
||||
typename DimensionSelectionType,
|
||||
typename ElemType,
|
||||
bool NoRecursion>
|
||||
template<typename MatType, typename LabelsType>
|
||||
double DecisionTree<FitnessFunction,
|
||||
NumericSplitType,
|
||||
CategoricalSplitType,
|
||||
DimensionSelectionType,
|
||||
ElemType,
|
||||
NoRecursion>::Train(
|
||||
MatType data,
|
||||
LabelsType labels,
|
||||
@@ -535,14 +505,12 @@ template<typename FitnessFunction,
|
||||
template<typename> class NumericSplitType,
|
||||
template<typename> class CategoricalSplitType,
|
||||
typename DimensionSelectionType,
|
||||
typename ElemType,
|
||||
bool NoRecursion>
|
||||
template<typename MatType, typename LabelsType, typename WeightsType>
|
||||
double DecisionTree<FitnessFunction,
|
||||
NumericSplitType,
|
||||
CategoricalSplitType,
|
||||
DimensionSelectionType,
|
||||
ElemType,
|
||||
NoRecursion>::Train(
|
||||
MatType data,
|
||||
const data::DatasetInfo& datasetInfo,
|
||||
@@ -584,14 +552,12 @@ template<typename FitnessFunction,
|
||||
template<typename> class NumericSplitType,
|
||||
template<typename> class CategoricalSplitType,
|
||||
typename DimensionSelectionType,
|
||||
typename ElemType,
|
||||
bool NoRecursion>
|
||||
template<typename MatType, typename LabelsType, typename WeightsType>
|
||||
double DecisionTree<FitnessFunction,
|
||||
NumericSplitType,
|
||||
CategoricalSplitType,
|
||||
DimensionSelectionType,
|
||||
ElemType,
|
||||
NoRecursion>::Train(
|
||||
MatType data,
|
||||
LabelsType labels,
|
||||
@@ -632,14 +598,12 @@ template<typename FitnessFunction,
|
||||
template<typename> class NumericSplitType,
|
||||
template<typename> class CategoricalSplitType,
|
||||
typename DimensionSelectionType,
|
||||
typename ElemType,
|
||||
bool NoRecursion>
|
||||
template<bool UseWeights, typename MatType>
|
||||
double DecisionTree<FitnessFunction,
|
||||
NumericSplitType,
|
||||
CategoricalSplitType,
|
||||
DimensionSelectionType,
|
||||
ElemType,
|
||||
NoRecursion>::Train(
|
||||
MatType& data,
|
||||
const size_t begin,
|
||||
@@ -818,14 +782,12 @@ template<typename FitnessFunction,
|
||||
template<typename> class NumericSplitType,
|
||||
template<typename> class CategoricalSplitType,
|
||||
typename DimensionSelectionType,
|
||||
typename ElemType,
|
||||
bool NoRecursion>
|
||||
template<bool UseWeights, typename MatType>
|
||||
double DecisionTree<FitnessFunction,
|
||||
NumericSplitType,
|
||||
CategoricalSplitType,
|
||||
DimensionSelectionType,
|
||||
ElemType,
|
||||
NoRecursion>::Train(
|
||||
MatType& data,
|
||||
const size_t begin,
|
||||
@@ -976,14 +938,12 @@ template<typename FitnessFunction,
|
||||
template<typename> class NumericSplitType,
|
||||
template<typename> class CategoricalSplitType,
|
||||
typename DimensionSelectionType,
|
||||
typename ElemType,
|
||||
bool NoRecursion>
|
||||
template<typename VecType>
|
||||
size_t DecisionTree<FitnessFunction,
|
||||
NumericSplitType,
|
||||
CategoricalSplitType,
|
||||
DimensionSelectionType,
|
||||
ElemType,
|
||||
NoRecursion>::Classify(const VecType& point) const
|
||||
{
|
||||
if (children.size() == 0)
|
||||
@@ -1000,14 +960,12 @@ template<typename FitnessFunction,
|
||||
template<typename> class NumericSplitType,
|
||||
template<typename> class CategoricalSplitType,
|
||||
typename DimensionSelectionType,
|
||||
typename ElemType,
|
||||
bool NoRecursion>
|
||||
template<typename VecType>
|
||||
void DecisionTree<FitnessFunction,
|
||||
NumericSplitType,
|
||||
CategoricalSplitType,
|
||||
DimensionSelectionType,
|
||||
ElemType,
|
||||
NoRecursion>::Classify(const VecType& point,
|
||||
size_t& prediction,
|
||||
arma::vec& probabilities) const
|
||||
@@ -1028,14 +986,12 @@ template<typename FitnessFunction,
|
||||
template<typename> class NumericSplitType,
|
||||
template<typename> class CategoricalSplitType,
|
||||
typename DimensionSelectionType,
|
||||
typename ElemType,
|
||||
bool NoRecursion>
|
||||
template<typename MatType>
|
||||
void DecisionTree<FitnessFunction,
|
||||
NumericSplitType,
|
||||
CategoricalSplitType,
|
||||
DimensionSelectionType,
|
||||
ElemType,
|
||||
NoRecursion>::Classify(const MatType& data,
|
||||
arma::Row<size_t>& predictions) const
|
||||
{
|
||||
@@ -1056,14 +1012,12 @@ template<typename FitnessFunction,
|
||||
template<typename> class NumericSplitType,
|
||||
template<typename> class CategoricalSplitType,
|
||||
typename DimensionSelectionType,
|
||||
typename ElemType,
|
||||
bool NoRecursion>
|
||||
template<typename MatType>
|
||||
void DecisionTree<FitnessFunction,
|
||||
NumericSplitType,
|
||||
CategoricalSplitType,
|
||||
DimensionSelectionType,
|
||||
ElemType,
|
||||
NoRecursion>::Classify(const MatType& data,
|
||||
arma::Row<size_t>& predictions,
|
||||
arma::mat& probabilities) const
|
||||
@@ -1095,14 +1049,12 @@ template<typename FitnessFunction,
|
||||
template<typename> class NumericSplitType,
|
||||
template<typename> class CategoricalSplitType,
|
||||
typename DimensionSelectionType,
|
||||
typename ElemType,
|
||||
bool NoRecursion>
|
||||
template<typename Archive>
|
||||
void DecisionTree<FitnessFunction,
|
||||
NumericSplitType,
|
||||
CategoricalSplitType,
|
||||
DimensionSelectionType,
|
||||
ElemType,
|
||||
NoRecursion>::serialize(Archive& ar,
|
||||
const uint32_t /* version */)
|
||||
{
|
||||
@@ -1126,14 +1078,12 @@ template<typename FitnessFunction,
|
||||
template<typename> class NumericSplitType,
|
||||
template<typename> class CategoricalSplitType,
|
||||
typename DimensionSelectionType,
|
||||
typename ElemType,
|
||||
bool NoRecursion>
|
||||
template<typename VecType>
|
||||
size_t DecisionTree<FitnessFunction,
|
||||
NumericSplitType,
|
||||
CategoricalSplitType,
|
||||
DimensionSelectionType,
|
||||
ElemType,
|
||||
NoRecursion>::CalculateDirection(const VecType& point) const
|
||||
{
|
||||
if ((data::Datatype) dimensionTypeOrMajorityClass ==
|
||||
@@ -1150,13 +1100,11 @@ template<typename FitnessFunction,
|
||||
template<typename> class NumericSplitType,
|
||||
template<typename> class CategoricalSplitType,
|
||||
typename DimensionSelectionType,
|
||||
typename ElemType,
|
||||
bool NoRecursion>
|
||||
size_t DecisionTree<FitnessFunction,
|
||||
NumericSplitType,
|
||||
CategoricalSplitType,
|
||||
DimensionSelectionType,
|
||||
ElemType,
|
||||
NoRecursion>::NumClasses() const
|
||||
{
|
||||
// Recurse to the nearest child and return the number of elements in the
|
||||
@@ -1171,14 +1119,12 @@ template<typename FitnessFunction,
|
||||
template<typename> class NumericSplitType,
|
||||
template<typename> class CategoricalSplitType,
|
||||
typename DimensionSelectionType,
|
||||
typename ElemType,
|
||||
bool NoRecursion>
|
||||
template<bool UseWeights, typename RowType, typename WeightsRowType>
|
||||
void DecisionTree<FitnessFunction,
|
||||
NumericSplitType,
|
||||
CategoricalSplitType,
|
||||
DimensionSelectionType,
|
||||
ElemType,
|
||||
NoRecursion>::CalculateClassProbabilities(
|
||||
const RowType& labels,
|
||||
const size_t numClasses,
|
||||
|
||||
@@ -26,7 +26,7 @@ class InformationGain
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Evaluate the Gini impurity given a vector of class weight counts.
|
||||
* Evaluate the information gain given a vector of class weight counts.
|
||||
*/
|
||||
template<bool UseWeights, typename CountType>
|
||||
static double EvaluatePtr(const CountType* counts,
|
||||
|
||||
@@ -67,6 +67,37 @@ double DiagonalGMM::LogProbability(const arma::vec& observation) const
|
||||
return sum;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the log probability of the given observation GMM matrix.
|
||||
*
|
||||
* @param observation Observation matrix to compute log-probabilty.
|
||||
* @param logProbs Stores the value of log-probability for input.
|
||||
*/
|
||||
void DiagonalGMM::LogProbability(const arma::mat& observation,
|
||||
arma::vec& logProbs) const
|
||||
{
|
||||
// Sum the probability for each Gaussian in our mixture (and we have to
|
||||
// multiply by the prior for each Gaussian too).
|
||||
logProbs.set_size(observation.n_cols);
|
||||
|
||||
// Store log-probability value in a matrix.
|
||||
arma::mat logProb(observation.n_cols, gaussians);
|
||||
|
||||
// Assign value to the matrix.
|
||||
for (size_t i = 0; i < gaussians; i++)
|
||||
{
|
||||
arma::vec temp(logProb.colptr(i), observation.n_cols, false, true);
|
||||
dists[i].LogProbability(observation, temp);
|
||||
}
|
||||
|
||||
// Save log(weights) as a vector.
|
||||
arma::vec logWeights = arma::log(weights);
|
||||
|
||||
// Compute log-probability.
|
||||
logProb += repmat(logWeights.t(), logProb.n_rows, 1);
|
||||
math::LogSumExp(logProb, logProbs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the probability of the given observation being from this GMM.
|
||||
*/
|
||||
@@ -75,6 +106,20 @@ double DiagonalGMM::Probability(const arma::vec& observation) const
|
||||
return exp(LogProbability(observation));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the probability of the given observation GMM matrix.
|
||||
*
|
||||
* @param observation Observation matrix to compute probabilty.
|
||||
* @param probs Stores the value of probability for observation.
|
||||
*/
|
||||
void DiagonalGMM::Probability(const arma::mat& observation,
|
||||
arma::vec& probs) const
|
||||
{
|
||||
LogProbability(observation, probs);
|
||||
probs = exp(probs);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the log probability of the given observation being from the given
|
||||
* component in the mixture.
|
||||
|
||||
@@ -166,14 +166,30 @@ class DiagonalGMM
|
||||
*/
|
||||
double Probability(const arma::vec& observation) const;
|
||||
|
||||
/**
|
||||
* Return the probability that the given observation matrix.
|
||||
*
|
||||
* @param observation Observation to evaluate the probability of.
|
||||
* @param probs Stores the value of probability for observation.
|
||||
*/
|
||||
void Probability(const arma::mat& observation, arma::vec& probs) const;
|
||||
|
||||
/**
|
||||
* Return the log probability that the given observation came from this
|
||||
* distribution.
|
||||
*
|
||||
* @param observation Observation to evaluate the probability of.
|
||||
* @param observation Observation to evaluate the log-probability of.
|
||||
*/
|
||||
double LogProbability(const arma::vec& observation) const;
|
||||
|
||||
/**
|
||||
* Return the log probability that the given observation matrix.
|
||||
*
|
||||
* @param observation Observation to evaluate the log-probability of.
|
||||
* @param logProbs Stores the value of log-probability for observation.
|
||||
*/
|
||||
void LogProbability(const arma::mat& observation, arma::vec& logProbs) const;
|
||||
|
||||
/**
|
||||
* Return the probability that the given observation came from the given
|
||||
* Gaussian component in this distribution.
|
||||
|
||||
@@ -53,6 +53,8 @@ GMM& GMM::operator=(const GMM& other)
|
||||
|
||||
/**
|
||||
* Return the log probability of the given observation being from this GMM.
|
||||
*
|
||||
* @param observation Observation vector to compute log-probabilty.
|
||||
*/
|
||||
double GMM::LogProbability(const arma::vec& observation) const
|
||||
{
|
||||
@@ -66,17 +68,67 @@ double GMM::LogProbability(const arma::vec& observation) const
|
||||
return sum;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the log probability of the given observation GMM matrix.
|
||||
*
|
||||
* @param observation Observation matrix to compute log-probabilty.
|
||||
* @param logProbs Stores the value of log-probability for Observation.
|
||||
*/
|
||||
void GMM::LogProbability(const arma::mat& observation,
|
||||
arma::vec& logProbs) const
|
||||
{
|
||||
// Sum the probability for each Gaussian in our mixture (and we have to
|
||||
// multiply by the prior for each Gaussian too).
|
||||
logProbs.set_size(observation.n_cols);
|
||||
|
||||
// Store log-probability value in a matrix.
|
||||
arma::mat logProb(observation.n_cols, gaussians);
|
||||
|
||||
// Assign value to the matrix.
|
||||
for (size_t i = 0; i < gaussians; i++)
|
||||
{
|
||||
arma::vec temp(logProb.colptr(i), observation.n_cols, false, true);
|
||||
dists[i].LogProbability(observation, temp);
|
||||
}
|
||||
|
||||
// Save log(weights) as a vector.
|
||||
arma::vec logWeights = arma::log(weights);
|
||||
|
||||
// Compute log-probability.
|
||||
logProb += repmat(logWeights.t(), logProb.n_rows, 1);
|
||||
math::LogSumExp(logProb, logProbs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the probability of the given observation being from this GMM.
|
||||
*
|
||||
* @param observation Observation vector to compute probabilty.
|
||||
*/
|
||||
double GMM::Probability(const arma::vec& observation) const
|
||||
{
|
||||
return exp(LogProbability(observation));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the probability of the given observation GMM matrix.
|
||||
*
|
||||
* @param observation Observation matrix to compute probabilty.
|
||||
* @param probs Stores the value of probability for x.
|
||||
*/
|
||||
void GMM::Probability(const arma::mat& observation,
|
||||
arma::vec& probs) const
|
||||
{
|
||||
LogProbability(observation, probs);
|
||||
probs = exp(probs);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the log probability of the given observation being from the given
|
||||
* component in the mixture.
|
||||
*
|
||||
* @param observation Observation vector to compute log-probabilty.
|
||||
* @param component Calculate the log-probability for given observation vector.
|
||||
*/
|
||||
double GMM::LogProbability(const arma::vec& observation,
|
||||
const size_t component) const
|
||||
@@ -89,6 +141,9 @@ double GMM::LogProbability(const arma::vec& observation,
|
||||
/**
|
||||
* Return the probability of the given observation being from the given
|
||||
* component in the mixture.
|
||||
*
|
||||
* @param observation Observation matrix to compute probabilty.
|
||||
* @param component Calculate the probability for given component.
|
||||
*/
|
||||
double GMM::Probability(const arma::vec& observation,
|
||||
const size_t component) const
|
||||
@@ -129,6 +184,9 @@ arma::vec GMM::Random() const
|
||||
/**
|
||||
* Classify the given observations as being from an individual component in this
|
||||
* GMM.
|
||||
*
|
||||
* @param observation Observation matrix for classification.
|
||||
* @param labels Save the labels for the given observation matrix.
|
||||
*/
|
||||
void GMM::Classify(const arma::mat& observations,
|
||||
arma::Row<size_t>& labels) const
|
||||
@@ -158,6 +216,10 @@ void GMM::Classify(const arma::mat& observations,
|
||||
|
||||
/**
|
||||
* Get the log-likelihood of this data's fit to the model.
|
||||
*
|
||||
* @param data Data matrix to compute log-likelihood.
|
||||
* @parma distsL Vector of Gaussian distribution.
|
||||
* @param weightsL Vector of weights for computing likelihoods.
|
||||
*/
|
||||
double GMM::LogLikelihood(
|
||||
const arma::mat& data,
|
||||
|
||||
@@ -160,18 +160,34 @@ class GMM
|
||||
* Return the probability that the given observation came from this
|
||||
* distribution.
|
||||
*
|
||||
* @param observation Observation to evaluate the probability of.
|
||||
* @param observation Observation vector to evaluate the probability of.
|
||||
*/
|
||||
double Probability(const arma::vec& observation) const;
|
||||
|
||||
/**
|
||||
* Return the probability of the given observation matrix.
|
||||
*
|
||||
* @param observation Observation matrix.
|
||||
* @param probs Vector to store probability value of observation x.
|
||||
*/
|
||||
void Probability(const arma::mat& observation, arma::vec& probs) const;
|
||||
|
||||
/**
|
||||
* Return the log probability that the given observation came from this
|
||||
* distribution.
|
||||
*
|
||||
* @param observation Observation to evaluate the probability of.
|
||||
* @param observation Observation vector to evaluate the probability of.
|
||||
*/
|
||||
double LogProbability(const arma::vec& observation) const;
|
||||
|
||||
/**
|
||||
* Return the log-probability of the given observation (x) matrix.
|
||||
*
|
||||
* @param observation Observation matrix.
|
||||
* @param logProbs Vector to store log-probability value of observation.
|
||||
*/
|
||||
void LogProbability(const arma::mat& observation, arma::vec& logProbs) const;
|
||||
|
||||
/**
|
||||
* Return the probability that the given observation came from the given
|
||||
* Gaussian component in this distribution.
|
||||
|
||||
@@ -316,8 +316,8 @@ class HMM
|
||||
*
|
||||
* @param emissionLogProb emission probability at time t.
|
||||
* @param logLikelihood Log-likelihood of the given sequence of emission
|
||||
* probability up to time t-1. This will be overwritten with the log-likelihood
|
||||
* of the given emission probability up to time t.
|
||||
* probability up to time t-1. This will be overwritten with the
|
||||
* log-likelihood of the given emission probability up to time t.
|
||||
* @param forwardLogProb Vector in which forward probabilities will be saved.
|
||||
* Passing forwardLogProb as an empty vector indicates the start of the
|
||||
* sequence (i.e. time t=0).
|
||||
@@ -446,9 +446,8 @@ class HMM
|
||||
* @param logScales Vector in which the log of scaling factors will be saved.
|
||||
* @return Forward probabilities
|
||||
*/
|
||||
arma::vec ForwardAtT0(
|
||||
const arma::vec& emissionLogProb,
|
||||
double& logScales) const;
|
||||
arma::vec ForwardAtT0(const arma::vec& emissionLogProb,
|
||||
double& logScales) const;
|
||||
|
||||
/**
|
||||
* Given emission probabilities, computes forward probabilities for time t>0.
|
||||
@@ -458,10 +457,9 @@ class HMM
|
||||
* @param prevForwardLogProb Previous forward probabilities.
|
||||
* @return Forward probabilities
|
||||
*/
|
||||
arma::vec ForwardAtTn(
|
||||
const arma::vec& emissionLogProb,
|
||||
double& logScales,
|
||||
const arma::vec& prevForwardLogProb) const;
|
||||
arma::vec ForwardAtTn(const arma::vec& emissionLogProb,
|
||||
double& logScales,
|
||||
const arma::vec& prevForwardLogProb) const;
|
||||
|
||||
// Helper functions.
|
||||
/**
|
||||
@@ -476,7 +474,8 @@ class HMM
|
||||
*/
|
||||
void Forward(const arma::mat& dataSeq,
|
||||
arma::vec& logScales,
|
||||
arma::mat& forwardLogProb) const;
|
||||
arma::mat& forwardLogProb,
|
||||
arma::mat& logProbs) const;
|
||||
|
||||
/**
|
||||
* The Backward algorithm (part of the Forward-Backward algorithm). Computes
|
||||
@@ -491,7 +490,8 @@ class HMM
|
||||
*/
|
||||
void Backward(const arma::mat& dataSeq,
|
||||
const arma::vec& logScales,
|
||||
arma::mat& backwardLogProb) const;
|
||||
arma::mat& backwardLogProb,
|
||||
arma::mat& logProbs) const;
|
||||
|
||||
//! Set of emission probability distributions; one for each state.
|
||||
std::vector<Distribution> emission;
|
||||
|
||||
@@ -149,8 +149,19 @@ double HMM<Distribution>::Train(const std::vector<arma::mat>& dataSeq)
|
||||
backwardLog, logScales);
|
||||
|
||||
// Add to estimate of initial probability for state j.
|
||||
for (size_t j = 0; j < logTransition.n_cols; ++j)
|
||||
newLogInitial[j] = math::LogAdd(newLogInitial[j], stateLogProb(j, 0));
|
||||
math::LogSumExp<arma::vec, true>(stateLogProb.unsafe_col(0),
|
||||
newLogInitial);
|
||||
|
||||
// Define a variable to store the value of log-probability for data.
|
||||
arma::mat logProbs(dataSeq[seq].n_cols, logTransition.n_rows);
|
||||
// Save the values of log-probability to logProbs.
|
||||
for (size_t i = 0; i < logTransition.n_rows; i++)
|
||||
{
|
||||
// Define alias of desired column.
|
||||
arma::vec alias(logProbs.colptr(i), logProbs.n_rows, false, true);
|
||||
// Use advanced constructor for using logProbs directly.
|
||||
emission[i].LogProbability(dataSeq[seq], alias);
|
||||
}
|
||||
|
||||
// Now re-estimate the parameters. This is the M-step.
|
||||
// pi_i = sum_d ((1 / P(seq[d])) sum_t (f(i, 0) b(i, 0))
|
||||
@@ -160,25 +171,31 @@ double HMM<Distribution>::Train(const std::vector<arma::mat>& dataSeq)
|
||||
// We store the new estimates in a different matrix.
|
||||
for (size_t t = 0; t < dataSeq[seq].n_cols; ++t)
|
||||
{
|
||||
for (size_t j = 0; j < logTransition.n_cols; ++j)
|
||||
// Assemble temporary vector that's used in log-sum computation.
|
||||
if (t < dataSeq[seq].n_cols - 1)
|
||||
{
|
||||
if (t < dataSeq[seq].n_cols - 1)
|
||||
{
|
||||
// Estimate of T_ij (probability of transition from state j to state
|
||||
// i). We postpone multiplication of the old T_ij until later.
|
||||
for (size_t i = 0; i < logTransition.n_rows; i++)
|
||||
{
|
||||
newLogTransition(i, j) = math::LogAdd(newLogTransition(i, j),
|
||||
forwardLog(j, t) + backwardLog(i, t + 1) +
|
||||
emission[i].LogProbability(dataSeq[seq].unsafe_col(t + 1)) -
|
||||
logScales[t + 1]);
|
||||
}
|
||||
}
|
||||
// This term is the same across all states, so compute it once and
|
||||
// cache it.
|
||||
const arma::vec tmp = backwardLog.col(t + 1) +
|
||||
logProbs.row(t + 1).t() - logScales[t + 1];
|
||||
arma::vec output;
|
||||
math::LogSumExp(tmp, output);
|
||||
|
||||
// Add to list of emission observations, for Distribution::Train().
|
||||
emissionList.col(sumTime) = dataSeq[seq].col(t);
|
||||
emissionProb[j][sumTime] = exp(stateLogProb(j, t));
|
||||
for (size_t j = 0; j < logTransition.n_cols; ++j)
|
||||
{
|
||||
// Compute the estimate of T_ij (probability of transition from
|
||||
// state j to state i). We postpone multiplication of the old T_ij
|
||||
// until later.
|
||||
arma::vec tmp2 = output + forwardLog(j, t);
|
||||
arma::vec alias = newLogTransition.unsafe_col(j);
|
||||
math::LogSumExp<arma::vec, true>(tmp2, alias);
|
||||
}
|
||||
}
|
||||
|
||||
// Add to list of emission observations, for Distribution::Train().
|
||||
for (size_t j = 0; j < logTransition.n_cols; ++j)
|
||||
emissionProb[j][sumTime] = exp(stateLogProb(j, t));
|
||||
emissionList.col(sumTime) = dataSeq[seq].col(t);
|
||||
sumTime++;
|
||||
}
|
||||
}
|
||||
@@ -337,9 +354,20 @@ double HMM<Distribution>::LogEstimate(const arma::mat& dataSeq,
|
||||
arma::mat& backwardLogProb,
|
||||
arma::vec& logScales) const
|
||||
{
|
||||
arma::mat logProbs(dataSeq.n_cols, logTransition.n_rows);
|
||||
|
||||
// Save the values of log-probability to logProbs.
|
||||
for (size_t i = 0; i < logTransition.n_rows; i++)
|
||||
{
|
||||
// Define alias of desired column.
|
||||
arma::vec alias(logProbs.colptr(i), logProbs.n_rows, false, true);
|
||||
// Use advanced constructor for using logProbs directly.
|
||||
emission[i].LogProbability(dataSeq, alias);
|
||||
}
|
||||
|
||||
// First run the forward-backward algorithm.
|
||||
Forward(dataSeq, logScales, forwardLogProb);
|
||||
Backward(dataSeq, logScales, backwardLogProb);
|
||||
Forward(dataSeq, logScales, forwardLogProb, logProbs);
|
||||
Backward(dataSeq, logScales, backwardLogProb, logProbs);
|
||||
|
||||
// Now assemble the state probability matrix based on the forward and backward
|
||||
// probabilities.
|
||||
@@ -481,6 +509,19 @@ double HMM<Distribution>::Predict(const arma::mat& dataSeq,
|
||||
|
||||
// Store the best first state.
|
||||
arma::uword index;
|
||||
|
||||
// Define a variable to store the value of log-probability for dataSeq.
|
||||
arma::mat logProbs(dataSeq.n_cols, logTransition.n_rows);
|
||||
|
||||
// Save the values of log-probability to logProbs.
|
||||
for (size_t i = 0; i < logTransition.n_rows; i++)
|
||||
{
|
||||
// Define alias of desired column.
|
||||
arma::vec alias(logProbs.colptr(i), logProbs.n_rows, false, true);
|
||||
// Use advanced constructor for using logProbs directly.
|
||||
emission[i].LogProbability(dataSeq, alias);
|
||||
}
|
||||
|
||||
for (size_t t = 1; t < dataSeq.n_cols; t++)
|
||||
{
|
||||
// Assemble the state probability for this element.
|
||||
@@ -489,8 +530,7 @@ double HMM<Distribution>::Predict(const arma::mat& dataSeq,
|
||||
for (size_t j = 0; j < logTransition.n_rows; j++)
|
||||
{
|
||||
arma::vec prob = logStateProb.col(t - 1) + logTransition.row(j).t();
|
||||
logStateProb(j, t) = prob.max(index) +
|
||||
emission[j].LogProbability(dataSeq.unsafe_col(t));
|
||||
logStateProb(j, t) = prob.max(index) + logProbs(t, j);
|
||||
stateSeqBack(j, t) = index;
|
||||
}
|
||||
}
|
||||
@@ -516,7 +556,19 @@ double HMM<Distribution>::LogLikelihood(const arma::mat& dataSeq) const
|
||||
arma::mat forwardLog;
|
||||
arma::vec logScales;
|
||||
|
||||
Forward(dataSeq, logScales, forwardLog);
|
||||
// This is needed here.
|
||||
arma::mat logProbs(dataSeq.n_cols, logTransition.n_rows);
|
||||
|
||||
// Save the values of log-probability to logProbs.
|
||||
for (size_t i = 0; i < logTransition.n_rows; i++)
|
||||
{
|
||||
// Define alias of desired column.
|
||||
arma::vec alias(logProbs.colptr(i), logProbs.n_rows, false, true);
|
||||
// Use advanced constructor for using logProbs directly.
|
||||
emission[i].LogProbability(dataSeq, alias);
|
||||
}
|
||||
|
||||
Forward(dataSeq, logScales, forwardLog, logProbs);
|
||||
|
||||
// The log-likelihood is the log of the scales for each time step.
|
||||
return accu(logScales);
|
||||
@@ -557,8 +609,7 @@ double HMM<Distribution>::EmissionLogLikelihood(
|
||||
arma::vec& forwardLogProb) const
|
||||
{
|
||||
bool isStartOfSeq = forwardLogProb.empty();
|
||||
double curLogScale = EmissionLogScaleFactor(emissionLogProb,
|
||||
forwardLogProb);
|
||||
double curLogScale = EmissionLogScaleFactor(emissionLogProb, forwardLogProb);
|
||||
logLikelihood = isStartOfSeq ? curLogScale : curLogScale + logLikelihood;
|
||||
return logLikelihood;
|
||||
}
|
||||
@@ -607,7 +658,19 @@ void HMM<Distribution>::Filter(const arma::mat& dataSeq,
|
||||
// First run the forward algorithm.
|
||||
arma::mat forwardLogProb;
|
||||
arma::vec logScales;
|
||||
Forward(dataSeq, logScales, forwardLogProb);
|
||||
// This is needed here.
|
||||
arma::mat logProbs(dataSeq.n_cols, logTransition.n_rows);
|
||||
|
||||
// Save the values of log-probability to logProbs.
|
||||
for (size_t i = 0; i < logTransition.n_rows; i++)
|
||||
{
|
||||
// Define alias of desired column.
|
||||
arma::vec alias(logProbs.colptr(i), logProbs.n_rows, false, true);
|
||||
// Use advanced constructor for using logProbs directly.
|
||||
emission[i].LogProbability(dataSeq, alias);
|
||||
}
|
||||
|
||||
Forward(dataSeq, logScales, forwardLogProb, logProbs);
|
||||
|
||||
// Propagate state ahead.
|
||||
if (ahead != 0)
|
||||
@@ -655,14 +718,12 @@ arma::vec HMM<Distribution>::ForwardAtT0(const arma::vec& emissionLogProb,
|
||||
// P(X_k | o_{1:k}) for all possible states X_k, for each time point k.
|
||||
ConvertToLogSpace();
|
||||
|
||||
arma::vec forwardLogProb(logTransition.n_rows);
|
||||
forwardLogProb.fill(-std::numeric_limits<double>::infinity());
|
||||
// The first entry in the forward algorithm uses the initial state
|
||||
// probabilities. Note that MATLAB assumes that the starting state (at
|
||||
// t = -1) is state 0; this is not our assumption here. To force that
|
||||
// behavior, you could append a single starting state to every single data
|
||||
// sequence and that should produce results in line with MATLAB.
|
||||
forwardLogProb = logInitial + emissionLogProb;
|
||||
arma::vec forwardLogProb = logInitial + emissionLogProb;
|
||||
|
||||
// Normalize probability.
|
||||
logScales = math::AccuLog(forwardLogProb);
|
||||
@@ -677,22 +738,23 @@ arma::vec HMM<Distribution>::ForwardAtT0(const arma::vec& emissionLogProb,
|
||||
*/
|
||||
template<typename Distribution>
|
||||
arma::vec HMM<Distribution>::ForwardAtTn(const arma::vec& emissionLogProb,
|
||||
double& logScales,
|
||||
const arma::vec& prevForwardLogProb) const
|
||||
double& logScales,
|
||||
const arma::vec& prevForwardLogProb)
|
||||
const
|
||||
{
|
||||
// Our goal is to calculate the forward probabilities:
|
||||
// P(X_k | o_{1:k}) for all possible states X_k, for each time point k.
|
||||
|
||||
arma::vec forwardLogProb(logTransition.n_rows);
|
||||
forwardLogProb.fill(-std::numeric_limits<double>::infinity());
|
||||
// Now compute the probabilities for each successive observation.
|
||||
for (size_t state = 0; state < logTransition.n_rows; state++) {
|
||||
// The forward probability of state j at time t is the sum over all
|
||||
// states of the probability of the previous state transitioning to
|
||||
// the current state and emitting the given observation.
|
||||
arma::vec tmp = prevForwardLogProb + logTransition.row(state).t();
|
||||
forwardLogProb(state) = math::AccuLog(tmp) + emissionLogProb(state);
|
||||
}
|
||||
// The forward probability of state j at time t is the sum over all states of
|
||||
// the probability of the previous state transitioning to the current state
|
||||
// and emitting the given observation. To do this computation in log-space,
|
||||
// we can use LogSumExp().
|
||||
arma::vec forwardLogProb;
|
||||
arma::mat tmp = logTransition + repmat(prevForwardLogProb.t(),
|
||||
logTransition.n_rows, 1);
|
||||
math::LogSumExp(tmp, forwardLogProb);
|
||||
forwardLogProb += emissionLogProb;
|
||||
|
||||
// Normalize probability.
|
||||
logScales = math::AccuLog(forwardLogProb);
|
||||
if (std::isfinite(logScales))
|
||||
@@ -707,7 +769,8 @@ arma::vec HMM<Distribution>::ForwardAtTn(const arma::vec& emissionLogProb,
|
||||
template<typename Distribution>
|
||||
void HMM<Distribution>::Forward(const arma::mat& dataSeq,
|
||||
arma::vec& logScales,
|
||||
arma::mat& forwardLogProb) const
|
||||
arma::mat& forwardLogProb,
|
||||
arma::mat& logProbs) const
|
||||
{
|
||||
// Our goal is to calculate the forward probabilities:
|
||||
// P(X_k | o_{1:k}) for all possible states X_k, for each time point k.
|
||||
@@ -722,33 +785,21 @@ void HMM<Distribution>::Forward(const arma::mat& dataSeq,
|
||||
// behavior, you could append a single starting state to every single data
|
||||
// sequence and that should produce results in line with MATLAB.
|
||||
|
||||
arma::vec emissionLogProb(logTransition.n_rows);
|
||||
for (size_t state = 0; state < logTransition.n_rows; state++)
|
||||
{
|
||||
emissionLogProb(state) =
|
||||
emission[state].LogProbability(dataSeq.unsafe_col(0));
|
||||
}
|
||||
|
||||
forwardLogProb.col(0) = ForwardAtT0(emissionLogProb, logScales(0));
|
||||
forwardLogProb.col(0) = ForwardAtT0(logProbs.row(0).t(), logScales(0));
|
||||
|
||||
// Now compute the probabilities for each successive observation.
|
||||
for (size_t t = 1; t < dataSeq.n_cols; t++)
|
||||
{
|
||||
for (size_t state = 0; state < logTransition.n_rows; state++)
|
||||
{
|
||||
emissionLogProb(state) =
|
||||
emission[state].LogProbability(dataSeq.unsafe_col(t));
|
||||
}
|
||||
|
||||
forwardLogProb.col(t) =
|
||||
ForwardAtTn(emissionLogProb, logScales(t), forwardLogProb.col(t-1));
|
||||
forwardLogProb.col(t) = ForwardAtTn(logProbs.row(t).t(), logScales(t),
|
||||
forwardLogProb.col(t - 1));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Distribution>
|
||||
void HMM<Distribution>::Backward(const arma::mat& dataSeq,
|
||||
const arma::vec& logScales,
|
||||
arma::mat& backwardLogProb) const
|
||||
arma::mat& backwardLogProb,
|
||||
arma::mat& logProbs) const
|
||||
{
|
||||
// Our goal is to calculate the backward probabilities:
|
||||
// P(X_k | o_{k + 1:T}) for all possible states X_k, for each time point k.
|
||||
@@ -761,23 +812,20 @@ void HMM<Distribution>::Backward(const arma::mat& dataSeq,
|
||||
// Now step backwards through all other observations.
|
||||
for (size_t t = dataSeq.n_cols - 2; t + 1 > 0; t--)
|
||||
{
|
||||
for (size_t j = 0; j < logTransition.n_rows; j++)
|
||||
{
|
||||
// The backward probability of state j at time t is the sum over all state
|
||||
// of the probability of the next state having been a transition from the
|
||||
// current state multiplied by the probability of each of those states
|
||||
// emitting the given observation.
|
||||
for (size_t state = 0; state < logTransition.n_rows; state++)
|
||||
{
|
||||
backwardLogProb(j, t) = math::LogAdd(backwardLogProb(j, t),
|
||||
logTransition(state, j) + backwardLogProb(state, t + 1)
|
||||
+ emission[state].LogProbability(dataSeq.unsafe_col(t + 1)));
|
||||
}
|
||||
// The backward probability of state j at time t is the sum over all
|
||||
// states of the probability of the next state having been a transition
|
||||
// from the current state multiplied by the probability of each of those
|
||||
// states emitting the given observation. To compute this in log-space, we
|
||||
// can use LogSumExpT().
|
||||
const arma::mat tmp = logTransition +
|
||||
repmat(backwardLogProb.col(t + 1), 1, logTransition.n_cols) +
|
||||
repmat(logProbs.row(t + 1).t(), 1, logTransition.n_cols);
|
||||
arma::vec alias = backwardLogProb.unsafe_col(t);
|
||||
math::LogSumExpT<arma::mat, true>(tmp, alias);
|
||||
|
||||
// Normalize by the weights from the forward algorithm.
|
||||
if (std::isfinite(logScales[t + 1]))
|
||||
backwardLogProb(j, t) -= logScales[t + 1];
|
||||
}
|
||||
// Normalize by the weights from the forward algorithm.
|
||||
if (std::isfinite(logScales[t + 1]))
|
||||
backwardLogProb.col(t) -= logScales[t + 1];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,23 +19,39 @@
|
||||
namespace mlpack {
|
||||
namespace tree {
|
||||
|
||||
/**
|
||||
* The RandomForest class provides an implementation of random forests,
|
||||
* described in Breiman's seminal paper:
|
||||
*
|
||||
* @code
|
||||
* @article{breiman2001random,
|
||||
* title={Random forests},
|
||||
* author={Breiman, Leo},
|
||||
* journal={Machine Learning},
|
||||
* volume={45},
|
||||
* number={1},
|
||||
* pages={5--32},
|
||||
* year={2001},
|
||||
* publisher={Springer}
|
||||
* }
|
||||
* @endcode
|
||||
*/
|
||||
template<typename FitnessFunction = GiniGain,
|
||||
typename DimensionSelectionType = MultipleRandomDimensionSelect,
|
||||
template<typename> class NumericSplitType = BestBinaryNumericSplit,
|
||||
template<typename> class CategoricalSplitType = AllCategoricalSplit,
|
||||
typename ElemType = double>
|
||||
template<typename> class CategoricalSplitType = AllCategoricalSplit>
|
||||
class RandomForest
|
||||
{
|
||||
public:
|
||||
//! Allow access to the underlying decision tree type.
|
||||
typedef DecisionTree<FitnessFunction, NumericSplitType, CategoricalSplitType,
|
||||
DimensionSelectionType, ElemType> DecisionTreeType;
|
||||
DimensionSelectionType> DecisionTreeType;
|
||||
|
||||
/**
|
||||
* Construct the random forest without any training or specifying the number
|
||||
* of trees. Predict() will throw an exception until Train() is called.
|
||||
*/
|
||||
RandomForest() { }
|
||||
RandomForest();
|
||||
|
||||
/**
|
||||
* Create a random forest, training on the given labeled training data with
|
||||
@@ -167,6 +183,8 @@ class RandomForest
|
||||
* @param minimumLeafSize Minimum number of points in each tree's leaf nodes.
|
||||
* @param minimumGainSplit Minimum gain for splitting a decision tree node.
|
||||
* @param maximumDepth Maximum depth for the tree.
|
||||
* @param warmStart When set to `true`, it adds `numTrees` new trees to the
|
||||
* existing random forest otherwise a new forest is trained from scratch.
|
||||
* @param dimensionSelector Instantiated dimension selection policy.
|
||||
* @return The average entropy of all the decision trees trained under forest.
|
||||
*/
|
||||
@@ -178,6 +196,7 @@ class RandomForest
|
||||
const size_t minimumLeafSize = 1,
|
||||
const double minimumGainSplit = 1e-7,
|
||||
const size_t maximumDepth = 0,
|
||||
const bool warmStart = false,
|
||||
DimensionSelectionType dimensionSelector =
|
||||
DimensionSelectionType());
|
||||
|
||||
@@ -198,6 +217,8 @@ class RandomForest
|
||||
* @param minimumLeafSize Minimum number of points in each tree's leaf nodes.
|
||||
* @param minimumGainSplit Minimum gain for splitting a decision tree node.
|
||||
* @param maximumDepth Maximum depth for the tree.
|
||||
* @param warmStart When set to `true`, it adds `numTrees` new trees to the
|
||||
* existing random forest else a new forest is trained from scratch.
|
||||
* @param dimensionSelector Instantiated dimension selection policy.
|
||||
* @return The average entropy of all the decision trees trained under forest.
|
||||
*/
|
||||
@@ -210,6 +231,7 @@ class RandomForest
|
||||
const size_t minimumLeafSize = 1,
|
||||
const double minimumGainSplit = 1e-7,
|
||||
const size_t maximumDepth = 0,
|
||||
const bool warmStart = false,
|
||||
DimensionSelectionType dimensionSelector =
|
||||
DimensionSelectionType());
|
||||
|
||||
@@ -228,6 +250,8 @@ class RandomForest
|
||||
* @param minimumLeafSize Minimum number of points in each tree's leaf nodes.
|
||||
* @param minimumGainSplit Minimum gain for splitting a decision tree node.
|
||||
* @param maximumDepth Maximum depth for the tree.
|
||||
* @param warmStart When set to `true`, it adds `numTrees` new trees to the
|
||||
* existing random forest else a new forest is trained from scratch.
|
||||
* @param dimensionSelector Instantiated dimension selection policy.
|
||||
* @return The average entropy of all the decision trees trained under forest.
|
||||
*/
|
||||
@@ -240,6 +264,7 @@ class RandomForest
|
||||
const size_t minimumLeafSize = 1,
|
||||
const double minimumGainSplit = 1e-7,
|
||||
const size_t maximumDepth = 0,
|
||||
const bool warmStart = false,
|
||||
DimensionSelectionType dimensionSelector =
|
||||
DimensionSelectionType());
|
||||
|
||||
@@ -260,6 +285,8 @@ class RandomForest
|
||||
* @param minimumLeafSize Minimum number of points in each tree's leaf nodes.
|
||||
* @param minimumGainSplit Minimum gain for splitting a decision tree node.
|
||||
* @param maximumDepth Maximum depth for the tree.
|
||||
* @param warmStart When set to `true`, it adds `numTrees` new trees to the
|
||||
* existing random forest else a new forest is trained from scratch.
|
||||
* @param dimensionSelector Instantiated dimension selection policy.
|
||||
* @return The average entropy of all the decision trees trained under forest.
|
||||
*/
|
||||
@@ -273,6 +300,7 @@ class RandomForest
|
||||
const size_t minimumLeafSize = 1,
|
||||
const double minimumGainSplit = 1e-7,
|
||||
const size_t maximumDepth = 0,
|
||||
const bool warmStart = false,
|
||||
DimensionSelectionType dimensionSelector =
|
||||
DimensionSelectionType());
|
||||
|
||||
@@ -354,6 +382,8 @@ class RandomForest
|
||||
* @param minimumGainSplit Minimum gain for splitting a decision tree node.
|
||||
* @param maximumDepth Maximum depth for the tree.
|
||||
* @param dimensionSelector Instantiated dimension selection policy.
|
||||
* @param warmStart When set to `true`, it fits new trees and add them to the
|
||||
* previous forest else a new forest is trained from scratch.
|
||||
* @tparam UseWeights Whether or not to use the weights parameter.
|
||||
* @tparam UseDatasetInfo Whether or not to use the datasetInfo parameter.
|
||||
* @tparam MatType The type of data matrix (i.e. arma::mat).
|
||||
@@ -369,10 +399,14 @@ class RandomForest
|
||||
const size_t minimumLeafSize,
|
||||
const double minimumGainSplit,
|
||||
const size_t maximumDepth,
|
||||
DimensionSelectionType& dimensionSelector);
|
||||
DimensionSelectionType& dimensionSelector,
|
||||
const bool warmStart = false);
|
||||
|
||||
//! The trees in the forest.
|
||||
std::vector<DecisionTreeType> trees;
|
||||
|
||||
//! The average gain of the forest.
|
||||
double avgGain;
|
||||
};
|
||||
|
||||
} // namespace tree
|
||||
|
||||
@@ -22,16 +22,31 @@ template<
|
||||
typename FitnessFunction,
|
||||
typename DimensionSelectionType,
|
||||
template<typename> class NumericSplitType,
|
||||
template<typename> class CategoricalSplitType,
|
||||
typename ElemType
|
||||
template<typename> class CategoricalSplitType
|
||||
>
|
||||
RandomForest<
|
||||
FitnessFunction,
|
||||
DimensionSelectionType,
|
||||
NumericSplitType,
|
||||
CategoricalSplitType
|
||||
>::RandomForest() :
|
||||
avgGain(0.0)
|
||||
{
|
||||
// Nothing to do here.
|
||||
}
|
||||
|
||||
template<
|
||||
typename FitnessFunction,
|
||||
typename DimensionSelectionType,
|
||||
template<typename> class NumericSplitType,
|
||||
template<typename> class CategoricalSplitType
|
||||
>
|
||||
template<typename MatType>
|
||||
RandomForest<
|
||||
FitnessFunction,
|
||||
DimensionSelectionType,
|
||||
NumericSplitType,
|
||||
CategoricalSplitType,
|
||||
ElemType
|
||||
CategoricalSplitType
|
||||
>::RandomForest(const MatType& dataset,
|
||||
const arma::Row<size_t>& labels,
|
||||
const size_t numClasses,
|
||||
@@ -39,29 +54,29 @@ RandomForest<
|
||||
const size_t minimumLeafSize,
|
||||
const double minimumGainSplit,
|
||||
const size_t maximumDepth,
|
||||
DimensionSelectionType dimensionSelector)
|
||||
DimensionSelectionType dimensionSelector) :
|
||||
avgGain(0.0)
|
||||
{
|
||||
// Pass off work to the Train() method.
|
||||
data::DatasetInfo info; // Ignored.
|
||||
arma::rowvec weights; // Fake weights, not used.
|
||||
Train<false, false>(dataset, info, labels, numClasses, weights, numTrees,
|
||||
minimumLeafSize, minimumGainSplit, maximumDepth, dimensionSelector);
|
||||
minimumLeafSize, minimumGainSplit, maximumDepth, dimensionSelector,
|
||||
false);
|
||||
}
|
||||
|
||||
template<
|
||||
typename FitnessFunction,
|
||||
typename DimensionSelectionType,
|
||||
template<typename> class NumericSplitType,
|
||||
template<typename> class CategoricalSplitType,
|
||||
typename ElemType
|
||||
template<typename> class CategoricalSplitType
|
||||
>
|
||||
template<typename MatType>
|
||||
RandomForest<
|
||||
FitnessFunction,
|
||||
DimensionSelectionType,
|
||||
NumericSplitType,
|
||||
CategoricalSplitType,
|
||||
ElemType
|
||||
CategoricalSplitType
|
||||
>::RandomForest(const MatType& dataset,
|
||||
const data::DatasetInfo& datasetInfo,
|
||||
const arma::Row<size_t>& labels,
|
||||
@@ -70,29 +85,28 @@ RandomForest<
|
||||
const size_t minimumLeafSize,
|
||||
const double minimumGainSplit,
|
||||
const size_t maximumDepth,
|
||||
DimensionSelectionType dimensionSelector)
|
||||
DimensionSelectionType dimensionSelector):
|
||||
avgGain(0.0)
|
||||
{
|
||||
// Pass off work to the Train() method.
|
||||
arma::rowvec weights; // Fake weights, not used.
|
||||
Train<false, true>(dataset, datasetInfo, labels, numClasses, weights,
|
||||
numTrees, minimumLeafSize, minimumGainSplit, maximumDepth,
|
||||
dimensionSelector);
|
||||
dimensionSelector, false);
|
||||
}
|
||||
|
||||
template<
|
||||
typename FitnessFunction,
|
||||
typename DimensionSelectionType,
|
||||
template<typename> class NumericSplitType,
|
||||
template<typename> class CategoricalSplitType,
|
||||
typename ElemType
|
||||
template<typename> class CategoricalSplitType
|
||||
>
|
||||
template<typename MatType>
|
||||
RandomForest<
|
||||
FitnessFunction,
|
||||
DimensionSelectionType,
|
||||
NumericSplitType,
|
||||
CategoricalSplitType,
|
||||
ElemType
|
||||
CategoricalSplitType
|
||||
>::RandomForest(const MatType& dataset,
|
||||
const arma::Row<size_t>& labels,
|
||||
const size_t numClasses,
|
||||
@@ -101,28 +115,28 @@ RandomForest<
|
||||
const size_t minimumLeafSize,
|
||||
const double minimumGainSplit,
|
||||
const size_t maximumDepth,
|
||||
DimensionSelectionType dimensionSelector)
|
||||
DimensionSelectionType dimensionSelector) :
|
||||
avgGain(0.0)
|
||||
{
|
||||
// Pass off work to the Train() method.
|
||||
data::DatasetInfo info; // Ignored by Train().
|
||||
Train<true, false>(dataset, info, labels, numClasses, weights, numTrees,
|
||||
minimumLeafSize, minimumGainSplit, maximumDepth, dimensionSelector);
|
||||
minimumLeafSize, minimumGainSplit, maximumDepth, dimensionSelector,
|
||||
false);
|
||||
}
|
||||
|
||||
template<
|
||||
typename FitnessFunction,
|
||||
typename DimensionSelectionType,
|
||||
template<typename> class NumericSplitType,
|
||||
template<typename> class CategoricalSplitType,
|
||||
typename ElemType
|
||||
template<typename> class CategoricalSplitType
|
||||
>
|
||||
template<typename MatType>
|
||||
RandomForest<
|
||||
FitnessFunction,
|
||||
DimensionSelectionType,
|
||||
NumericSplitType,
|
||||
CategoricalSplitType,
|
||||
ElemType
|
||||
CategoricalSplitType
|
||||
>::RandomForest(const MatType& dataset,
|
||||
const data::DatasetInfo& datasetInfo,
|
||||
const arma::Row<size_t>& labels,
|
||||
@@ -132,27 +146,27 @@ RandomForest<
|
||||
const size_t minimumLeafSize,
|
||||
const double minimumGainSplit,
|
||||
const size_t maximumDepth,
|
||||
DimensionSelectionType dimensionSelector)
|
||||
DimensionSelectionType dimensionSelector) :
|
||||
avgGain(0.0)
|
||||
{
|
||||
// Pass off work to the Train() method.
|
||||
Train<true, true>(dataset, datasetInfo, labels, numClasses, weights, numTrees,
|
||||
minimumLeafSize, minimumGainSplit, maximumDepth, dimensionSelector);
|
||||
Train<true, true>(dataset, datasetInfo, labels, numClasses, weights,
|
||||
numTrees, minimumLeafSize, minimumGainSplit, maximumDepth,
|
||||
dimensionSelector, false);
|
||||
}
|
||||
|
||||
template<
|
||||
typename FitnessFunction,
|
||||
typename DimensionSelectionType,
|
||||
template<typename> class NumericSplitType,
|
||||
template<typename> class CategoricalSplitType,
|
||||
typename ElemType
|
||||
template<typename> class CategoricalSplitType
|
||||
>
|
||||
template<typename MatType>
|
||||
double RandomForest<
|
||||
FitnessFunction,
|
||||
DimensionSelectionType,
|
||||
NumericSplitType,
|
||||
CategoricalSplitType,
|
||||
ElemType
|
||||
CategoricalSplitType
|
||||
>::Train(const MatType& dataset,
|
||||
const arma::Row<size_t>& labels,
|
||||
const size_t numClasses,
|
||||
@@ -160,30 +174,29 @@ double RandomForest<
|
||||
const size_t minimumLeafSize,
|
||||
const double minimumGainSplit,
|
||||
const size_t maximumDepth,
|
||||
const bool warmStart,
|
||||
DimensionSelectionType dimensionSelector)
|
||||
{
|
||||
// Pass off to Train().
|
||||
data::DatasetInfo info; // Ignored by Train().
|
||||
data::DatasetInfo datasetInfo; // Ignored by Train().
|
||||
arma::rowvec weights; // Ignored by Train().
|
||||
return Train<false, false>(dataset, info, labels, numClasses, weights,
|
||||
return Train<false, false>(dataset, datasetInfo, labels, numClasses, weights,
|
||||
numTrees, minimumLeafSize, minimumGainSplit, maximumDepth,
|
||||
dimensionSelector);
|
||||
dimensionSelector, warmStart);
|
||||
}
|
||||
|
||||
template<
|
||||
typename FitnessFunction,
|
||||
typename DimensionSelectionType,
|
||||
template<typename> class NumericSplitType,
|
||||
template<typename> class CategoricalSplitType,
|
||||
typename ElemType
|
||||
template<typename> class CategoricalSplitType
|
||||
>
|
||||
template<typename MatType>
|
||||
double RandomForest<
|
||||
FitnessFunction,
|
||||
DimensionSelectionType,
|
||||
NumericSplitType,
|
||||
CategoricalSplitType,
|
||||
ElemType
|
||||
CategoricalSplitType
|
||||
>::Train(const MatType& dataset,
|
||||
const data::DatasetInfo& datasetInfo,
|
||||
const arma::Row<size_t>& labels,
|
||||
@@ -192,29 +205,28 @@ double RandomForest<
|
||||
const size_t minimumLeafSize,
|
||||
const double minimumGainSplit,
|
||||
const size_t maximumDepth,
|
||||
const bool warmStart,
|
||||
DimensionSelectionType dimensionSelector)
|
||||
{
|
||||
// Pass off to Train().
|
||||
arma::rowvec weights; // Ignored by Train().
|
||||
return Train<false, true>(dataset, datasetInfo, labels, numClasses, weights,
|
||||
numTrees, minimumLeafSize, minimumGainSplit, maximumDepth,
|
||||
dimensionSelector);
|
||||
dimensionSelector, warmStart);
|
||||
}
|
||||
|
||||
template<
|
||||
typename FitnessFunction,
|
||||
typename DimensionSelectionType,
|
||||
template<typename> class NumericSplitType,
|
||||
template<typename> class CategoricalSplitType,
|
||||
typename ElemType
|
||||
template<typename> class CategoricalSplitType
|
||||
>
|
||||
template<typename MatType>
|
||||
double RandomForest<
|
||||
FitnessFunction,
|
||||
DimensionSelectionType,
|
||||
NumericSplitType,
|
||||
CategoricalSplitType,
|
||||
ElemType
|
||||
CategoricalSplitType
|
||||
>::Train(const MatType& dataset,
|
||||
const arma::Row<size_t>& labels,
|
||||
const size_t numClasses,
|
||||
@@ -223,29 +235,28 @@ double RandomForest<
|
||||
const size_t minimumLeafSize,
|
||||
const double minimumGainSplit,
|
||||
const size_t maximumDepth,
|
||||
const bool warmStart,
|
||||
DimensionSelectionType dimensionSelector)
|
||||
{
|
||||
// Pass off to Train().
|
||||
data::DatasetInfo info; // Ignored by Train().
|
||||
return Train<false, false>(dataset, info, labels, numClasses, weights,
|
||||
data::DatasetInfo datasetInfo; // Ignored by Train().
|
||||
return Train<false, false>(dataset, datasetInfo, labels, numClasses, weights,
|
||||
numTrees, minimumLeafSize, minimumGainSplit, maximumDepth,
|
||||
dimensionSelector);
|
||||
dimensionSelector, warmStart);
|
||||
}
|
||||
|
||||
template<
|
||||
typename FitnessFunction,
|
||||
typename DimensionSelectionType,
|
||||
template<typename> class NumericSplitType,
|
||||
template<typename> class CategoricalSplitType,
|
||||
typename ElemType
|
||||
template<typename> class CategoricalSplitType
|
||||
>
|
||||
template<typename MatType>
|
||||
double RandomForest<
|
||||
FitnessFunction,
|
||||
DimensionSelectionType,
|
||||
NumericSplitType,
|
||||
CategoricalSplitType,
|
||||
ElemType
|
||||
CategoricalSplitType
|
||||
>::Train(const MatType& dataset,
|
||||
const data::DatasetInfo& datasetInfo,
|
||||
const arma::Row<size_t>& labels,
|
||||
@@ -255,28 +266,27 @@ double RandomForest<
|
||||
const size_t minimumLeafSize,
|
||||
const double minimumGainSplit,
|
||||
const size_t maximumDepth,
|
||||
const bool warmStart,
|
||||
DimensionSelectionType dimensionSelector)
|
||||
{
|
||||
// Pass off to Train().
|
||||
return Train<true, true>(dataset, datasetInfo, labels, numClasses, weights,
|
||||
numTrees, minimumLeafSize, minimumGainSplit, maximumDepth,
|
||||
dimensionSelector);
|
||||
dimensionSelector, warmStart);
|
||||
}
|
||||
|
||||
template<
|
||||
typename FitnessFunction,
|
||||
typename DimensionSelectionType,
|
||||
template<typename> class NumericSplitType,
|
||||
template<typename> class CategoricalSplitType,
|
||||
typename ElemType
|
||||
template<typename> class CategoricalSplitType
|
||||
>
|
||||
template<typename VecType>
|
||||
size_t RandomForest<
|
||||
FitnessFunction,
|
||||
DimensionSelectionType,
|
||||
NumericSplitType,
|
||||
CategoricalSplitType,
|
||||
ElemType
|
||||
CategoricalSplitType
|
||||
>::Classify(const VecType& point) const
|
||||
{
|
||||
// Pass off to another Classify() overload.
|
||||
@@ -291,16 +301,14 @@ template<
|
||||
typename FitnessFunction,
|
||||
typename DimensionSelectionType,
|
||||
template<typename> class NumericSplitType,
|
||||
template<typename> class CategoricalSplitType,
|
||||
typename ElemType
|
||||
template<typename> class CategoricalSplitType
|
||||
>
|
||||
template<typename VecType>
|
||||
void RandomForest<
|
||||
FitnessFunction,
|
||||
DimensionSelectionType,
|
||||
NumericSplitType,
|
||||
CategoricalSplitType,
|
||||
ElemType
|
||||
CategoricalSplitType
|
||||
>::Classify(const VecType& point,
|
||||
size_t& prediction,
|
||||
arma::vec& probabilities) const
|
||||
@@ -338,16 +346,14 @@ template<
|
||||
typename FitnessFunction,
|
||||
typename DimensionSelectionType,
|
||||
template<typename> class NumericSplitType,
|
||||
template<typename> class CategoricalSplitType,
|
||||
typename ElemType
|
||||
template<typename> class CategoricalSplitType
|
||||
>
|
||||
template<typename MatType>
|
||||
void RandomForest<
|
||||
FitnessFunction,
|
||||
DimensionSelectionType,
|
||||
NumericSplitType,
|
||||
CategoricalSplitType,
|
||||
ElemType
|
||||
CategoricalSplitType
|
||||
>::Classify(const MatType& data,
|
||||
arma::Row<size_t>& predictions) const
|
||||
{
|
||||
@@ -373,16 +379,14 @@ template<
|
||||
typename FitnessFunction,
|
||||
typename DimensionSelectionType,
|
||||
template<typename> class NumericSplitType,
|
||||
template<typename> class CategoricalSplitType,
|
||||
typename ElemType
|
||||
template<typename> class CategoricalSplitType
|
||||
>
|
||||
template<typename MatType>
|
||||
void RandomForest<
|
||||
FitnessFunction,
|
||||
DimensionSelectionType,
|
||||
NumericSplitType,
|
||||
CategoricalSplitType,
|
||||
ElemType
|
||||
CategoricalSplitType
|
||||
>::Classify(const MatType& data,
|
||||
arma::Row<size_t>& predictions,
|
||||
arma::mat& probabilities) const
|
||||
@@ -411,16 +415,14 @@ template<
|
||||
typename FitnessFunction,
|
||||
typename DimensionSelectionType,
|
||||
template<typename> class NumericSplitType,
|
||||
template<typename> class CategoricalSplitType,
|
||||
typename ElemType
|
||||
template<typename> class CategoricalSplitType
|
||||
>
|
||||
template<typename Archive>
|
||||
void RandomForest<
|
||||
FitnessFunction,
|
||||
DimensionSelectionType,
|
||||
NumericSplitType,
|
||||
CategoricalSplitType,
|
||||
ElemType
|
||||
CategoricalSplitType
|
||||
>::serialize(Archive& ar, const uint32_t /* version */)
|
||||
{
|
||||
size_t numTrees;
|
||||
@@ -436,22 +438,21 @@ void RandomForest<
|
||||
trees.resize(numTrees);
|
||||
|
||||
ar(CEREAL_NVP(trees));
|
||||
ar(CEREAL_NVP(avgGain));
|
||||
}
|
||||
|
||||
template<
|
||||
typename FitnessFunction,
|
||||
typename DimensionSelectionType,
|
||||
template<typename> class NumericSplitType,
|
||||
template<typename> class CategoricalSplitType,
|
||||
typename ElemType
|
||||
template<typename> class CategoricalSplitType
|
||||
>
|
||||
template<bool UseWeights, bool UseDatasetInfo, typename MatType>
|
||||
double RandomForest<
|
||||
FitnessFunction,
|
||||
DimensionSelectionType,
|
||||
NumericSplitType,
|
||||
CategoricalSplitType,
|
||||
ElemType
|
||||
CategoricalSplitType
|
||||
>::Train(const MatType& dataset,
|
||||
const data::DatasetInfo& datasetInfo,
|
||||
const arma::Row<size_t>& labels,
|
||||
@@ -461,13 +462,20 @@ double RandomForest<
|
||||
const size_t minimumLeafSize,
|
||||
const double minimumGainSplit,
|
||||
const size_t maximumDepth,
|
||||
DimensionSelectionType& dimensionSelector)
|
||||
DimensionSelectionType& dimensionSelector,
|
||||
const bool warmStart)
|
||||
{
|
||||
// Train each tree individually.
|
||||
trees.resize(numTrees); // This will fill the vector with untrained trees.
|
||||
double avgGain = 0.0;
|
||||
// Reset the forest if we are not doing a warm-start.
|
||||
if (!warmStart)
|
||||
trees.clear();
|
||||
const size_t oldNumTrees = trees.size();
|
||||
trees.resize(trees.size() + numTrees);
|
||||
|
||||
#pragma omp parallel for reduction( + : avgGain)
|
||||
// Convert avgGain to total gain.
|
||||
double totalGain = avgGain * oldNumTrees;
|
||||
|
||||
// Train each tree individually.
|
||||
#pragma omp parallel for reduction( + : totalGain)
|
||||
for (omp_size_t i = 0; i < numTrees; ++i)
|
||||
{
|
||||
Timer::Start("bootstrap");
|
||||
@@ -478,40 +486,44 @@ double RandomForest<
|
||||
bootstrapLabels, bootstrapWeights);
|
||||
Timer::Stop("bootstrap");
|
||||
|
||||
// Now build the decision tree.
|
||||
Timer::Start("train_tree");
|
||||
if (UseWeights)
|
||||
{
|
||||
if (UseDatasetInfo)
|
||||
{
|
||||
avgGain += trees[i].Train(bootstrapDataset, datasetInfo,
|
||||
bootstrapLabels, numClasses, bootstrapWeights, minimumLeafSize,
|
||||
minimumGainSplit, maximumDepth, dimensionSelector);
|
||||
totalGain += trees[oldNumTrees + i].Train(bootstrapDataset,
|
||||
datasetInfo, bootstrapLabels, numClasses, bootstrapWeights,
|
||||
minimumLeafSize, minimumGainSplit, maximumDepth,
|
||||
dimensionSelector);
|
||||
}
|
||||
else
|
||||
{
|
||||
avgGain += trees[i].Train(bootstrapDataset, bootstrapLabels, numClasses,
|
||||
bootstrapWeights, minimumLeafSize, minimumGainSplit, maximumDepth,
|
||||
dimensionSelector);
|
||||
totalGain += trees[oldNumTrees + i].Train(bootstrapDataset,
|
||||
bootstrapLabels, numClasses, bootstrapWeights, minimumLeafSize,
|
||||
minimumGainSplit, maximumDepth, dimensionSelector);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (UseDatasetInfo)
|
||||
{
|
||||
avgGain += trees[i].Train(bootstrapDataset, datasetInfo,
|
||||
bootstrapLabels, numClasses, minimumLeafSize, minimumGainSplit,
|
||||
maximumDepth, dimensionSelector);
|
||||
totalGain += trees[oldNumTrees + i].Train(bootstrapDataset,
|
||||
datasetInfo, bootstrapLabels, numClasses, minimumLeafSize,
|
||||
minimumGainSplit, maximumDepth, dimensionSelector);
|
||||
}
|
||||
else
|
||||
{
|
||||
avgGain += trees[i].Train(bootstrapDataset, bootstrapLabels, numClasses,
|
||||
minimumLeafSize, minimumGainSplit, maximumDepth, dimensionSelector);
|
||||
totalGain += trees[oldNumTrees + i].Train(bootstrapDataset,
|
||||
bootstrapLabels, numClasses, minimumLeafSize, minimumGainSplit,
|
||||
maximumDepth, dimensionSelector);
|
||||
}
|
||||
}
|
||||
|
||||
Timer::Stop("train_tree");
|
||||
}
|
||||
return avgGain / numTrees;
|
||||
|
||||
avgGain = totalGain / trees.size();
|
||||
return avgGain;
|
||||
}
|
||||
|
||||
} // namespace tree
|
||||
|
||||
@@ -130,6 +130,8 @@ PARAM_INT_IN("subspace_dim", "Dimensionality of random subspace to use for "
|
||||
"d", 0);
|
||||
|
||||
PARAM_INT_IN("seed", "Random seed. If 0, 'std::time(NULL)' is used.", "s", 0);
|
||||
PARAM_FLAG("warm_start", "If true and passed along with `training` and "
|
||||
"`input_model` then trains more trees on top of existing model.", "w");
|
||||
|
||||
/**
|
||||
* This is the class that we will serialize. It is a pretty simple wrapper
|
||||
@@ -167,7 +169,11 @@ static void mlpackMain()
|
||||
math::RandomSeed((size_t) std::time(NULL));
|
||||
|
||||
// Check for incompatible input parameters.
|
||||
RequireOnlyOnePassed({ "training", "input_model" }, true);
|
||||
if (!IO::HasParam("warm_start"))
|
||||
RequireOnlyOnePassed({ "training", "input_model" }, true);
|
||||
else
|
||||
// When warm_start is passed, training and input_model must also be passed.
|
||||
RequireNoneOrAllPassed({"warm_start", "training", "input_model"}, true);
|
||||
|
||||
ReportIgnoredParam({{ "training", false }}, "print_training_accuracy");
|
||||
ReportIgnoredParam({{ "test", false }}, "test_labels");
|
||||
@@ -201,10 +207,17 @@ static void mlpackMain()
|
||||
ReportIgnoredParam({{ "training", false }}, "minimum_leaf_size");
|
||||
|
||||
RandomForestModel* rfModel;
|
||||
// Input model is loaded when we are either doing warm-started training or
|
||||
// else we are making predictions only or both.
|
||||
if (IO::HasParam("input_model"))
|
||||
rfModel = IO::GetParam<RandomForestModel*>("input_model");
|
||||
// Handles the case when we are training new forest from scratch.
|
||||
else
|
||||
rfModel = new RandomForestModel();
|
||||
|
||||
if (IO::HasParam("training"))
|
||||
{
|
||||
Timer::Start("rf_training");
|
||||
rfModel = new RandomForestModel();
|
||||
|
||||
// Train the model on the given input data.
|
||||
arma::mat data = std::move(IO::GetParam<arma::mat>("training"));
|
||||
@@ -233,7 +246,8 @@ static void mlpackMain()
|
||||
|
||||
// Train the model.
|
||||
rfModel->rf.Train(data, labels, numClasses, numTrees, minimumLeafSize,
|
||||
minimumGainSplit, maxDepth, mrds);
|
||||
minimumGainSplit, maxDepth, IO::HasParam("warm_start"), mrds);
|
||||
|
||||
Timer::Stop("rf_training");
|
||||
|
||||
// Did we want training accuracy?
|
||||
@@ -251,11 +265,6 @@ static void mlpackMain()
|
||||
Timer::Stop("rf_prediction");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Then we must be loading a model.
|
||||
rfModel = IO::GetParam<RandomForestModel*>("input_model");
|
||||
}
|
||||
|
||||
if (IO::HasParam("test"))
|
||||
{
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include <mlpack/methods/ann/activation_functions/poisson1_function.hpp>
|
||||
#include <mlpack/methods/ann/activation_functions/gaussian_function.hpp>
|
||||
#include <mlpack/methods/ann/activation_functions/hard_swish_function.hpp>
|
||||
#include <mlpack/methods/ann/activation_functions/tanh_exponential_function.hpp>
|
||||
|
||||
#include "catch.hpp"
|
||||
|
||||
@@ -1220,3 +1221,23 @@ TEST_CASE("HardSwishFunctionTest", "[ActivationFunctionsTest]")
|
||||
CheckDerivativeCorrect<HardSwishFunction>
|
||||
(desiredActivations, desiredDerivatives);
|
||||
}
|
||||
|
||||
/**
|
||||
* Basic test of the TanhExp function.
|
||||
*/
|
||||
TEST_CASE("TanhExpFunctionTest", "[ActivationFunctionsTest]")
|
||||
{
|
||||
|
||||
const arma::colvec activationData("-2 3.2 4.5 1 -1 2 0");
|
||||
|
||||
// Hand-calculated values.
|
||||
const arma::colvec desiredActivations("-0.26903 3.20000 4.50000 \
|
||||
0.991329 -0.352135 2.0 0.0000");
|
||||
|
||||
// Hand-calculated values.
|
||||
const arma::colvec desiredDerivatives("0.523051 1.0000 1.0000 \
|
||||
1.03924 0.449818 1.00002 0.761594");
|
||||
|
||||
CheckActivationCorrect<TanhExpFunction>(activationData, desiredActivations);
|
||||
CheckDerivativeCorrect<TanhExpFunction>(desiredActivations, desiredDerivatives);
|
||||
}
|
||||
|
||||
@@ -3883,6 +3883,57 @@ TEST_CASE("LpMaxPoolingTestCase", "[ANNLayerTest]")
|
||||
REQUIRE(output.n_elem == 4);
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple test for Mean Pooling layer.
|
||||
*/
|
||||
TEST_CASE("MeanPoolingTestCase", "[ANNLayerTest]")
|
||||
{
|
||||
// For rectangular input to pooling layers.
|
||||
arma::mat input = arma::mat(28, 1);
|
||||
input.zeros();
|
||||
input(0) = input(16) = 1;
|
||||
input(1) = input(17) = 2;
|
||||
input(2) = input(18) = 3;
|
||||
input(3) = input(19) = 4;
|
||||
input(4) = input(20) = 5;
|
||||
input(5) = input(23) = 6;
|
||||
input(6) = input(24) = 7;
|
||||
input(14) = input(25) = 8;
|
||||
input(15) = input(26) = 9;
|
||||
|
||||
MeanPooling<> module1(2, 2, 2, 2, false);
|
||||
MeanPooling<> module2(2, 2, 2, 2, true);
|
||||
module1.InputWidth() = 7;
|
||||
module1.InputHeight() = 4;
|
||||
module2.InputWidth() = 7;
|
||||
module2.InputHeight() = 4;
|
||||
|
||||
// Calculated using torch.nn.MeanPool2d().
|
||||
arma::mat result1, result2;
|
||||
result1 << 0.7500 << 4.2500 << arma::endr
|
||||
<< 1.7500 << 4.0000 << arma::endr
|
||||
<< 2.7500 << 6.0000 << arma::endr
|
||||
<< 3.5000 << 2.5000 << arma::endr;
|
||||
|
||||
result2 << 0.7500 << 4.2500 << arma::endr
|
||||
<< 1.7500 << 4.0000 << arma::endr
|
||||
<< 2.7500 << 6.0000 << arma::endr;
|
||||
|
||||
arma::mat output1, output2;
|
||||
module1.Forward(input, output1);
|
||||
module2.Forward(input, output2);
|
||||
output1.reshape(4, 2);
|
||||
output2.reshape(3, 2);
|
||||
CheckMatrices(output1, result1, 1e-1);
|
||||
CheckMatrices(output2, result2, 1e-1);
|
||||
|
||||
arma::mat delta1, delta2;
|
||||
module1.Backward(input, output1, delta1);
|
||||
REQUIRE(arma::accu(delta1) == 25.5);
|
||||
module2.Backward(input, output2, delta2);
|
||||
REQUIRE(arma::accu(delta2) == 19.5);
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple test for Max Pooling layer.
|
||||
*/
|
||||
@@ -4155,7 +4206,7 @@ TEST_CASE("AdaptiveMeanPoolingTestCase", "[ANNLayerTest]")
|
||||
REQUIRE(output.n_cols == 1);
|
||||
// Test the Backward Function.
|
||||
module1.Backward(input, output, delta);
|
||||
REQUIRE(arma::accu(delta) == 7.0);
|
||||
REQUIRE(arma::accu(delta) == 19.75);
|
||||
|
||||
// For Square input.
|
||||
input = arma::mat(9, 1);
|
||||
@@ -4177,7 +4228,7 @@ TEST_CASE("AdaptiveMeanPoolingTestCase", "[ANNLayerTest]")
|
||||
REQUIRE(output.n_cols == 1);
|
||||
// Test the Backward Function.
|
||||
module2.Backward(input, output, delta);
|
||||
REQUIRE(arma::accu(delta) == 0.0);
|
||||
REQUIRE(arma::accu(delta) == 4.50);
|
||||
|
||||
// For Square input.
|
||||
input = arma::mat(16, 1);
|
||||
@@ -4219,7 +4270,7 @@ TEST_CASE("AdaptiveMeanPoolingTestCase", "[ANNLayerTest]")
|
||||
REQUIRE(output.n_cols == 1);
|
||||
// Test the Backward Function.
|
||||
module4.Backward(input, output, delta);
|
||||
REQUIRE(arma::accu(delta) == 1.5);
|
||||
REQUIRE(arma::accu(delta) == 2.25);
|
||||
}
|
||||
|
||||
TEST_CASE("TransposedConvolutionalLayerOptionalParameterTest", "[ANNLayerTest]")
|
||||
|
||||
+222
-166
@@ -1,9 +1,9 @@
|
||||
/*
|
||||
* Catch v2.13.4
|
||||
* Generated: 2020-12-29 14:48:00.116107
|
||||
* Catch v2.13.5
|
||||
* Generated: 2021-04-10 23:43:17.560525
|
||||
* ----------------------------------------------------------
|
||||
* This file has been merged from multiple headers. Please don't edit it directly
|
||||
* Copyright (c) 2020 Two Blue Cubes Ltd. All rights reserved.
|
||||
* Copyright (c) 2021 Two Blue Cubes Ltd. All rights reserved.
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
#define CATCH_VERSION_MAJOR 2
|
||||
#define CATCH_VERSION_MINOR 13
|
||||
#define CATCH_VERSION_PATCH 4
|
||||
#define CATCH_VERSION_PATCH 5
|
||||
|
||||
#ifdef __clang__
|
||||
# pragma clang system_header
|
||||
@@ -66,13 +66,16 @@
|
||||
#if !defined(CATCH_CONFIG_IMPL_ONLY)
|
||||
// start catch_platform.h
|
||||
|
||||
// See e.g.:
|
||||
// https://opensource.apple.com/source/CarbonHeaders/CarbonHeaders-18.1/TargetConditionals.h.auto.html
|
||||
#ifdef __APPLE__
|
||||
# include <TargetConditionals.h>
|
||||
# if TARGET_OS_OSX == 1
|
||||
# define CATCH_PLATFORM_MAC
|
||||
# elif TARGET_OS_IPHONE == 1
|
||||
# define CATCH_PLATFORM_IPHONE
|
||||
# endif
|
||||
# include <TargetConditionals.h>
|
||||
# if (defined(TARGET_OS_OSX) && TARGET_OS_OSX == 1) || \
|
||||
(defined(TARGET_OS_MAC) && TARGET_OS_MAC == 1)
|
||||
# define CATCH_PLATFORM_MAC
|
||||
# elif (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE == 1)
|
||||
# define CATCH_PLATFORM_IPHONE
|
||||
# endif
|
||||
|
||||
#elif defined(linux) || defined(__linux) || defined(__linux__)
|
||||
# define CATCH_PLATFORM_LINUX
|
||||
@@ -132,9 +135,9 @@ namespace Catch {
|
||||
|
||||
#endif
|
||||
|
||||
// We have to avoid both ICC and Clang, because they try to mask themselves
|
||||
// as gcc, and we want only GCC in this block
|
||||
#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) && !defined(__CUDACC__)
|
||||
// Only GCC compiler should be used in this block, so other compilers trying to
|
||||
// mask themselves as GCC should be ignored.
|
||||
#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) && !defined(__CUDACC__) && !defined(__LCC__)
|
||||
# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic push" )
|
||||
# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic pop" )
|
||||
|
||||
@@ -7054,8 +7057,8 @@ namespace Catch {
|
||||
double b2 = bias - z1;
|
||||
double a1 = a(b1);
|
||||
double a2 = a(b2);
|
||||
auto lo = std::max(cumn(a1), 0);
|
||||
auto hi = std::min(cumn(a2), n - 1);
|
||||
auto lo = (std::max)(cumn(a1), 0);
|
||||
auto hi = (std::min)(cumn(a2), n - 1);
|
||||
|
||||
return { point, resample[lo], resample[hi], confidence_level };
|
||||
}
|
||||
@@ -7124,7 +7127,9 @@ namespace Catch {
|
||||
}
|
||||
template <typename Clock>
|
||||
EnvironmentEstimate<FloatDuration<Clock>> estimate_clock_cost(FloatDuration<Clock> resolution) {
|
||||
auto time_limit = std::min(resolution * clock_cost_estimation_tick_limit, FloatDuration<Clock>(clock_cost_estimation_time_limit));
|
||||
auto time_limit = (std::min)(
|
||||
resolution * clock_cost_estimation_tick_limit,
|
||||
FloatDuration<Clock>(clock_cost_estimation_time_limit));
|
||||
auto time_clock = [](int k) {
|
||||
return Detail::measure<Clock>([k] {
|
||||
for (int i = 0; i < k; ++i) {
|
||||
@@ -7771,7 +7776,7 @@ namespace Catch {
|
||||
double sb = stddev.point;
|
||||
double mn = mean.point / n;
|
||||
double mg_min = mn / 2.;
|
||||
double sg = std::min(mg_min / 4., sb / std::sqrt(n));
|
||||
double sg = (std::min)(mg_min / 4., sb / std::sqrt(n));
|
||||
double sg2 = sg * sg;
|
||||
double sb2 = sb * sb;
|
||||
|
||||
@@ -7790,7 +7795,7 @@ namespace Catch {
|
||||
return (nc / n) * (sb2 - nc * sg2);
|
||||
};
|
||||
|
||||
return std::min(var_out(1), var_out(std::min(c_max(0.), c_max(mg_min)))) / sb2;
|
||||
return (std::min)(var_out(1), var_out((std::min)(c_max(0.), c_max(mg_min)))) / sb2;
|
||||
}
|
||||
|
||||
bootstrap_analysis analyse_samples(double confidence_level, int n_resamples, std::vector<double>::iterator first, std::vector<double>::iterator last) {
|
||||
@@ -7980,86 +7985,58 @@ namespace Catch {
|
||||
|
||||
// start catch_fatal_condition.h
|
||||
|
||||
// start catch_windows_h_proxy.h
|
||||
|
||||
|
||||
#if defined(CATCH_PLATFORM_WINDOWS)
|
||||
|
||||
#if !defined(NOMINMAX) && !defined(CATCH_CONFIG_NO_NOMINMAX)
|
||||
# define CATCH_DEFINED_NOMINMAX
|
||||
# define NOMINMAX
|
||||
#endif
|
||||
#if !defined(WIN32_LEAN_AND_MEAN) && !defined(CATCH_CONFIG_NO_WIN32_LEAN_AND_MEAN)
|
||||
# define CATCH_DEFINED_WIN32_LEAN_AND_MEAN
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
|
||||
#ifdef __AFXDLL
|
||||
#include <AfxWin.h>
|
||||
#else
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#ifdef CATCH_DEFINED_NOMINMAX
|
||||
# undef NOMINMAX
|
||||
#endif
|
||||
#ifdef CATCH_DEFINED_WIN32_LEAN_AND_MEAN
|
||||
# undef WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
|
||||
#endif // defined(CATCH_PLATFORM_WINDOWS)
|
||||
|
||||
// end catch_windows_h_proxy.h
|
||||
#if defined( CATCH_CONFIG_WINDOWS_SEH )
|
||||
#include <cassert>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
struct FatalConditionHandler {
|
||||
|
||||
static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo);
|
||||
FatalConditionHandler();
|
||||
static void reset();
|
||||
~FatalConditionHandler();
|
||||
|
||||
private:
|
||||
static bool isSet;
|
||||
static ULONG guaranteeSize;
|
||||
static PVOID exceptionHandlerHandle;
|
||||
};
|
||||
|
||||
} // namespace Catch
|
||||
|
||||
#elif defined ( CATCH_CONFIG_POSIX_SIGNALS )
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
struct FatalConditionHandler {
|
||||
|
||||
static bool isSet;
|
||||
static struct sigaction oldSigActions[];
|
||||
static stack_t oldSigStack;
|
||||
static char altStackMem[];
|
||||
|
||||
static void handleSignal( int sig );
|
||||
// Wrapper for platform-specific fatal error (signals/SEH) handlers
|
||||
//
|
||||
// Tries to be cooperative with other handlers, and not step over
|
||||
// other handlers. This means that unknown structured exceptions
|
||||
// are passed on, previous signal handlers are called, and so on.
|
||||
//
|
||||
// Can only be instantiated once, and assumes that once a signal
|
||||
// is caught, the binary will end up terminating. Thus, there
|
||||
class FatalConditionHandler {
|
||||
bool m_started = false;
|
||||
|
||||
// Install/disengage implementation for specific platform.
|
||||
// Should be if-defed to work on current platform, can assume
|
||||
// engage-disengage 1:1 pairing.
|
||||
void engage_platform();
|
||||
void disengage_platform();
|
||||
public:
|
||||
// Should also have platform-specific implementations as needed
|
||||
FatalConditionHandler();
|
||||
~FatalConditionHandler();
|
||||
static void reset();
|
||||
|
||||
void engage() {
|
||||
assert(!m_started && "Handler cannot be installed twice.");
|
||||
m_started = true;
|
||||
engage_platform();
|
||||
}
|
||||
|
||||
void disengage() {
|
||||
assert(m_started && "Handler cannot be uninstalled without being installed first");
|
||||
m_started = false;
|
||||
disengage_platform();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Catch
|
||||
|
||||
#else
|
||||
|
||||
namespace Catch {
|
||||
struct FatalConditionHandler {
|
||||
void reset();
|
||||
//! Simple RAII guard for (dis)engaging the FatalConditionHandler
|
||||
class FatalConditionHandlerGuard {
|
||||
FatalConditionHandler* m_handler;
|
||||
public:
|
||||
FatalConditionHandlerGuard(FatalConditionHandler* handler):
|
||||
m_handler(handler) {
|
||||
m_handler->engage();
|
||||
}
|
||||
~FatalConditionHandlerGuard() {
|
||||
m_handler->disengage();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
} // end namespace Catch
|
||||
|
||||
// end catch_fatal_condition.h
|
||||
#include <string>
|
||||
@@ -8185,6 +8162,7 @@ namespace Catch {
|
||||
std::vector<SectionEndInfo> m_unfinishedSections;
|
||||
std::vector<ITracker*> m_activeSections;
|
||||
TrackerContext m_trackerContext;
|
||||
FatalConditionHandler m_fatalConditionhandler;
|
||||
bool m_lastAssertionPassed = false;
|
||||
bool m_shouldReportUnexpected = true;
|
||||
bool m_includeSuccessfulResults;
|
||||
@@ -10057,6 +10035,36 @@ namespace Catch {
|
||||
}
|
||||
|
||||
// end catch_errno_guard.h
|
||||
// start catch_windows_h_proxy.h
|
||||
|
||||
|
||||
#if defined(CATCH_PLATFORM_WINDOWS)
|
||||
|
||||
#if !defined(NOMINMAX) && !defined(CATCH_CONFIG_NO_NOMINMAX)
|
||||
# define CATCH_DEFINED_NOMINMAX
|
||||
# define NOMINMAX
|
||||
#endif
|
||||
#if !defined(WIN32_LEAN_AND_MEAN) && !defined(CATCH_CONFIG_NO_WIN32_LEAN_AND_MEAN)
|
||||
# define CATCH_DEFINED_WIN32_LEAN_AND_MEAN
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
|
||||
#ifdef __AFXDLL
|
||||
#include <AfxWin.h>
|
||||
#else
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#ifdef CATCH_DEFINED_NOMINMAX
|
||||
# undef NOMINMAX
|
||||
#endif
|
||||
#ifdef CATCH_DEFINED_WIN32_LEAN_AND_MEAN
|
||||
# undef WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
|
||||
#endif // defined(CATCH_PLATFORM_WINDOWS)
|
||||
|
||||
// end catch_windows_h_proxy.h
|
||||
#include <sstream>
|
||||
|
||||
namespace Catch {
|
||||
@@ -10573,7 +10581,7 @@ namespace Catch {
|
||||
// Extracts the actual name part of an enum instance
|
||||
// In other words, it returns the Blue part of Bikeshed::Colour::Blue
|
||||
StringRef extractInstanceName(StringRef enumInstance) {
|
||||
// Find last occurence of ":"
|
||||
// Find last occurrence of ":"
|
||||
size_t name_start = enumInstance.size();
|
||||
while (name_start > 0 && enumInstance[name_start - 1] != ':') {
|
||||
--name_start;
|
||||
@@ -10735,25 +10743,47 @@ namespace Catch {
|
||||
// end catch_exception_translator_registry.cpp
|
||||
// start catch_fatal_condition.cpp
|
||||
|
||||
#if defined(__GNUC__)
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wmissing-field-initializers"
|
||||
#endif
|
||||
#include <algorithm>
|
||||
|
||||
#if !defined( CATCH_CONFIG_WINDOWS_SEH ) && !defined( CATCH_CONFIG_POSIX_SIGNALS )
|
||||
|
||||
namespace Catch {
|
||||
|
||||
// If neither SEH nor signal handling is required, the handler impls
|
||||
// do not have to do anything, and can be empty.
|
||||
FatalConditionHandler::engage_platform() {}
|
||||
FatalConditionHandler::disengage_platform() {}
|
||||
FatalConditionHandler::FatalConditionHandler() = default;
|
||||
FatalConditionHandler::~FatalConditionHandler() = default;
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
#endif // !CATCH_CONFIG_WINDOWS_SEH && !CATCH_CONFIG_POSIX_SIGNALS
|
||||
|
||||
#if defined( CATCH_CONFIG_WINDOWS_SEH ) && defined( CATCH_CONFIG_POSIX_SIGNALS )
|
||||
#error "Inconsistent configuration: Windows' SEH handling and POSIX signals cannot be enabled at the same time"
|
||||
#endif // CATCH_CONFIG_WINDOWS_SEH && CATCH_CONFIG_POSIX_SIGNALS
|
||||
|
||||
#if defined( CATCH_CONFIG_WINDOWS_SEH ) || defined( CATCH_CONFIG_POSIX_SIGNALS )
|
||||
|
||||
namespace {
|
||||
// Report the error condition
|
||||
//! Signals fatal error message to the run context
|
||||
void reportFatal( char const * const message ) {
|
||||
Catch::getCurrentContext().getResultCapture()->handleFatalErrorCondition( message );
|
||||
}
|
||||
}
|
||||
|
||||
#endif // signals/SEH handling
|
||||
//! Minimal size Catch2 needs for its own fatal error handling.
|
||||
//! Picked anecdotally, so it might not be sufficient on all
|
||||
//! platforms, and for all configurations.
|
||||
constexpr std::size_t minStackSizeForErrors = 32 * 1024;
|
||||
} // end unnamed namespace
|
||||
|
||||
#endif // CATCH_CONFIG_WINDOWS_SEH || CATCH_CONFIG_POSIX_SIGNALS
|
||||
|
||||
#if defined( CATCH_CONFIG_WINDOWS_SEH )
|
||||
|
||||
namespace Catch {
|
||||
|
||||
struct SignalDefs { DWORD id; const char* name; };
|
||||
|
||||
// There is no 1-1 mapping between signals and windows exceptions.
|
||||
@@ -10766,7 +10796,7 @@ namespace Catch {
|
||||
{ static_cast<DWORD>(EXCEPTION_INT_DIVIDE_BY_ZERO), "Divide by zero error" },
|
||||
};
|
||||
|
||||
LONG CALLBACK FatalConditionHandler::handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) {
|
||||
static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) {
|
||||
for (auto const& def : signalDefs) {
|
||||
if (ExceptionInfo->ExceptionRecord->ExceptionCode == def.id) {
|
||||
reportFatal(def.name);
|
||||
@@ -10777,38 +10807,50 @@ namespace Catch {
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
FatalConditionHandler::FatalConditionHandler() {
|
||||
isSet = true;
|
||||
// 32k seems enough for Catch to handle stack overflow,
|
||||
// but the value was found experimentally, so there is no strong guarantee
|
||||
guaranteeSize = 32 * 1024;
|
||||
exceptionHandlerHandle = nullptr;
|
||||
// Register as first handler in current chain
|
||||
exceptionHandlerHandle = AddVectoredExceptionHandler(1, handleVectoredException);
|
||||
// Pass in guarantee size to be filled
|
||||
SetThreadStackGuarantee(&guaranteeSize);
|
||||
}
|
||||
// Since we do not support multiple instantiations, we put these
|
||||
// into global variables and rely on cleaning them up in outlined
|
||||
// constructors/destructors
|
||||
static PVOID exceptionHandlerHandle = nullptr;
|
||||
|
||||
void FatalConditionHandler::reset() {
|
||||
if (isSet) {
|
||||
RemoveVectoredExceptionHandler(exceptionHandlerHandle);
|
||||
SetThreadStackGuarantee(&guaranteeSize);
|
||||
exceptionHandlerHandle = nullptr;
|
||||
isSet = false;
|
||||
// For MSVC, we reserve part of the stack memory for handling
|
||||
// memory overflow structured exception.
|
||||
FatalConditionHandler::FatalConditionHandler() {
|
||||
ULONG guaranteeSize = static_cast<ULONG>(minStackSizeForErrors);
|
||||
if (!SetThreadStackGuarantee(&guaranteeSize)) {
|
||||
// We do not want to fully error out, because needing
|
||||
// the stack reserve should be rare enough anyway.
|
||||
Catch::cerr()
|
||||
<< "Failed to reserve piece of stack."
|
||||
<< " Stack overflows will not be reported successfully.";
|
||||
}
|
||||
}
|
||||
|
||||
FatalConditionHandler::~FatalConditionHandler() {
|
||||
reset();
|
||||
// We do not attempt to unset the stack guarantee, because
|
||||
// Windows does not support lowering the stack size guarantee.
|
||||
FatalConditionHandler::~FatalConditionHandler() = default;
|
||||
|
||||
void FatalConditionHandler::engage_platform() {
|
||||
// Register as first handler in current chain
|
||||
exceptionHandlerHandle = AddVectoredExceptionHandler(1, handleVectoredException);
|
||||
if (!exceptionHandlerHandle) {
|
||||
CATCH_RUNTIME_ERROR("Could not register vectored exception handler");
|
||||
}
|
||||
}
|
||||
|
||||
bool FatalConditionHandler::isSet = false;
|
||||
ULONG FatalConditionHandler::guaranteeSize = 0;
|
||||
PVOID FatalConditionHandler::exceptionHandlerHandle = nullptr;
|
||||
void FatalConditionHandler::disengage_platform() {
|
||||
if (!RemoveVectoredExceptionHandler(exceptionHandlerHandle)) {
|
||||
CATCH_RUNTIME_ERROR("Could not unregister vectored exception handler");
|
||||
}
|
||||
exceptionHandlerHandle = nullptr;
|
||||
}
|
||||
|
||||
} // namespace Catch
|
||||
} // end namespace Catch
|
||||
|
||||
#elif defined( CATCH_CONFIG_POSIX_SIGNALS )
|
||||
#endif // CATCH_CONFIG_WINDOWS_SEH
|
||||
|
||||
#if defined( CATCH_CONFIG_POSIX_SIGNALS )
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
@@ -10817,10 +10859,6 @@ namespace Catch {
|
||||
const char* name;
|
||||
};
|
||||
|
||||
// 32kb for the alternate stack seems to be sufficient. However, this value
|
||||
// is experimentally determined, so that's not guaranteed.
|
||||
static constexpr std::size_t sigStackSize = 32768 >= MINSIGSTKSZ ? 32768 : MINSIGSTKSZ;
|
||||
|
||||
static SignalDefs signalDefs[] = {
|
||||
{ SIGINT, "SIGINT - Terminal interrupt signal" },
|
||||
{ SIGILL, "SIGILL - Illegal instruction signal" },
|
||||
@@ -10830,7 +10868,32 @@ namespace Catch {
|
||||
{ SIGABRT, "SIGABRT - Abort (abnormal termination) signal" }
|
||||
};
|
||||
|
||||
void FatalConditionHandler::handleSignal( int sig ) {
|
||||
// Older GCCs trigger -Wmissing-field-initializers for T foo = {}
|
||||
// which is zero initialization, but not explicit. We want to avoid
|
||||
// that.
|
||||
#if defined(__GNUC__)
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wmissing-field-initializers"
|
||||
#endif
|
||||
|
||||
static char* altStackMem = nullptr;
|
||||
static std::size_t altStackSize = 0;
|
||||
static stack_t oldSigStack{};
|
||||
static struct sigaction oldSigActions[sizeof(signalDefs) / sizeof(SignalDefs)]{};
|
||||
|
||||
static void restorePreviousSignalHandlers() {
|
||||
// We set signal handlers back to the previous ones. Hopefully
|
||||
// nobody overwrote them in the meantime, and doesn't expect
|
||||
// their signal handlers to live past ours given that they
|
||||
// installed them after ours..
|
||||
for (std::size_t i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i) {
|
||||
sigaction(signalDefs[i].id, &oldSigActions[i], nullptr);
|
||||
}
|
||||
// Return the old stack
|
||||
sigaltstack(&oldSigStack, nullptr);
|
||||
}
|
||||
|
||||
static void handleSignal( int sig ) {
|
||||
char const * name = "<unknown signal>";
|
||||
for (auto const& def : signalDefs) {
|
||||
if (sig == def.id) {
|
||||
@@ -10838,16 +10901,33 @@ namespace Catch {
|
||||
break;
|
||||
}
|
||||
}
|
||||
reset();
|
||||
reportFatal(name);
|
||||
// We need to restore previous signal handlers and let them do
|
||||
// their thing, so that the users can have the debugger break
|
||||
// when a signal is raised, and so on.
|
||||
restorePreviousSignalHandlers();
|
||||
reportFatal( name );
|
||||
raise( sig );
|
||||
}
|
||||
|
||||
FatalConditionHandler::FatalConditionHandler() {
|
||||
isSet = true;
|
||||
assert(!altStackMem && "Cannot initialize POSIX signal handler when one already exists");
|
||||
if (altStackSize == 0) {
|
||||
altStackSize = std::max(static_cast<size_t>(SIGSTKSZ), minStackSizeForErrors);
|
||||
}
|
||||
altStackMem = new char[altStackSize]();
|
||||
}
|
||||
|
||||
FatalConditionHandler::~FatalConditionHandler() {
|
||||
delete[] altStackMem;
|
||||
// We signal that another instance can be constructed by zeroing
|
||||
// out the pointer.
|
||||
altStackMem = nullptr;
|
||||
}
|
||||
|
||||
void FatalConditionHandler::engage_platform() {
|
||||
stack_t sigStack;
|
||||
sigStack.ss_sp = altStackMem;
|
||||
sigStack.ss_size = sigStackSize;
|
||||
sigStack.ss_size = altStackSize;
|
||||
sigStack.ss_flags = 0;
|
||||
sigaltstack(&sigStack, &oldSigStack);
|
||||
struct sigaction sa = { };
|
||||
@@ -10859,40 +10939,17 @@ namespace Catch {
|
||||
}
|
||||
}
|
||||
|
||||
FatalConditionHandler::~FatalConditionHandler() {
|
||||
reset();
|
||||
}
|
||||
|
||||
void FatalConditionHandler::reset() {
|
||||
if( isSet ) {
|
||||
// Set signals back to previous values -- hopefully nobody overwrote them in the meantime
|
||||
for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) {
|
||||
sigaction(signalDefs[i].id, &oldSigActions[i], nullptr);
|
||||
}
|
||||
// Return the old stack
|
||||
sigaltstack(&oldSigStack, nullptr);
|
||||
isSet = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool FatalConditionHandler::isSet = false;
|
||||
struct sigaction FatalConditionHandler::oldSigActions[sizeof(signalDefs)/sizeof(SignalDefs)] = {};
|
||||
stack_t FatalConditionHandler::oldSigStack = {};
|
||||
char FatalConditionHandler::altStackMem[sigStackSize] = {};
|
||||
|
||||
} // namespace Catch
|
||||
|
||||
#else
|
||||
|
||||
namespace Catch {
|
||||
void FatalConditionHandler::reset() {}
|
||||
}
|
||||
|
||||
#endif // signals/SEH handling
|
||||
|
||||
#if defined(__GNUC__)
|
||||
# pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
void FatalConditionHandler::disengage_platform() {
|
||||
restorePreviousSignalHandlers();
|
||||
}
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
#endif // CATCH_CONFIG_POSIX_SIGNALS
|
||||
// end catch_fatal_condition.cpp
|
||||
// start catch_generators.cpp
|
||||
|
||||
@@ -11447,7 +11504,8 @@ namespace {
|
||||
return lhs == rhs;
|
||||
}
|
||||
|
||||
auto ulpDiff = std::abs(lc - rc);
|
||||
// static cast as a workaround for IBM XLC
|
||||
auto ulpDiff = std::abs(static_cast<FP>(lc - rc));
|
||||
return static_cast<uint64_t>(ulpDiff) <= maxUlpDiff;
|
||||
}
|
||||
|
||||
@@ -11621,7 +11679,6 @@ Floating::WithinRelMatcher WithinRel(float target) {
|
||||
|
||||
} // namespace Matchers
|
||||
} // namespace Catch
|
||||
|
||||
// end catch_matchers_floating.cpp
|
||||
// start catch_matchers_generic.cpp
|
||||
|
||||
@@ -12955,9 +13012,8 @@ namespace Catch {
|
||||
}
|
||||
|
||||
void RunContext::invokeActiveTestCase() {
|
||||
FatalConditionHandler fatalConditionHandler; // Handle signals
|
||||
FatalConditionHandlerGuard _(&m_fatalConditionhandler);
|
||||
m_activeTestCase->invoke();
|
||||
fatalConditionHandler.reset();
|
||||
}
|
||||
|
||||
void RunContext::handleUnfinishedSections() {
|
||||
@@ -15320,7 +15376,7 @@ namespace Catch {
|
||||
}
|
||||
|
||||
Version const& libraryVersion() {
|
||||
static Version version( 2, 13, 4, "", 0 );
|
||||
static Version version( 2, 13, 5, "", 0 );
|
||||
return version;
|
||||
}
|
||||
|
||||
|
||||
@@ -289,7 +289,7 @@ TEST_CASE("BestBinaryNumericSplitSimpleSplitTest", "[DecisionTreeTest]")
|
||||
weights.ones();
|
||||
|
||||
arma::vec classProbabilities;
|
||||
BestBinaryNumericSplit<GiniGain>::template AuxiliarySplitInfo<double> aux;
|
||||
BestBinaryNumericSplit<GiniGain>::AuxiliarySplitInfo aux;
|
||||
|
||||
// Call the method to do the splitting.
|
||||
const double bestGain = GiniGain::Evaluate<false>(labels, 2, weights);
|
||||
@@ -327,7 +327,7 @@ TEST_CASE("BestBinaryNumericSplitMinSamplesTest", "[DecisionTreeTest]")
|
||||
arma::rowvec weights(labels.n_elem);
|
||||
|
||||
arma::vec classProbabilities;
|
||||
BestBinaryNumericSplit<GiniGain>::template AuxiliarySplitInfo<double> aux;
|
||||
BestBinaryNumericSplit<GiniGain>::AuxiliarySplitInfo aux;
|
||||
|
||||
// Call the method to do the splitting.
|
||||
const double bestGain = GiniGain::Evaluate<false>(labels, 2, weights);
|
||||
@@ -363,7 +363,7 @@ TEST_CASE("BestBinaryNumericSplitNoGainTest", "[DecisionTreeTest]")
|
||||
}
|
||||
|
||||
arma::vec classProbabilities;
|
||||
BestBinaryNumericSplit<GiniGain>::template AuxiliarySplitInfo<double> aux;
|
||||
BestBinaryNumericSplit<GiniGain>::AuxiliarySplitInfo aux;
|
||||
|
||||
// Call the method to do the splitting.
|
||||
const double bestGain = GiniGain::Evaluate<false>(labels, 2, weights);
|
||||
@@ -388,7 +388,7 @@ TEST_CASE("AllCategoricalSplitSimpleSplitTest", "[DecisionTreeTest]")
|
||||
weights.ones();
|
||||
|
||||
arma::vec classProbabilities;
|
||||
AllCategoricalSplit<GiniGain>::template AuxiliarySplitInfo<double> aux;
|
||||
AllCategoricalSplit<GiniGain>::AuxiliarySplitInfo aux;
|
||||
|
||||
// Call the method to do the splitting.
|
||||
const double bestGain = GiniGain::Evaluate<false>(labels, 3, weights);
|
||||
@@ -424,7 +424,7 @@ TEST_CASE("AllCategoricalSplitMinSamplesTest", "[DecisionTreeTest]")
|
||||
weights.ones();
|
||||
|
||||
arma::vec classProbabilities;
|
||||
AllCategoricalSplit<GiniGain>::template AuxiliarySplitInfo<double> aux;
|
||||
AllCategoricalSplit<GiniGain>::AuxiliarySplitInfo aux;
|
||||
|
||||
// Call the method to do the splitting.
|
||||
const double bestGain = GiniGain::Evaluate<false>(labels, 3, weights);
|
||||
@@ -457,7 +457,7 @@ TEST_CASE("AllCategoricalSplitNoGainTest", "[DecisionTreeTest]")
|
||||
}
|
||||
|
||||
arma::vec classProbabilities;
|
||||
AllCategoricalSplit<GiniGain>::template AuxiliarySplitInfo<double> aux;
|
||||
AllCategoricalSplit<GiniGain>::AuxiliarySplitInfo aux;
|
||||
|
||||
// Call the method to do the splitting.
|
||||
const double bestGain = GiniGain::Evaluate<false>(labels, 3, weights);
|
||||
@@ -701,6 +701,66 @@ TEST_CASE("SimpleGeneralizationTest", "[DecisionTreeTest]")
|
||||
REQUIRE(wdcorrect > 0.75);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that the decision tree generalizes reasonably when built on float data.
|
||||
*/
|
||||
TEST_CASE("SimpleGeneralizationFMatTest", "[DecisionTreeTest]")
|
||||
{
|
||||
arma::fmat inputData;
|
||||
if (!data::Load("vc2.csv", inputData))
|
||||
FAIL("Cannot load test dataset vc2.csv!");
|
||||
|
||||
arma::Row<size_t> labels;
|
||||
if (!data::Load("vc2_labels.txt", labels))
|
||||
FAIL("Cannot load labels for vc2_labels.txt");
|
||||
|
||||
// Initialize an all-ones weight matrix.
|
||||
arma::rowvec weights(labels.n_cols, arma::fill::ones);
|
||||
|
||||
// Build decision tree.
|
||||
DecisionTree<> d(inputData, labels, 3, 10 /* Leaf size of 10. */);
|
||||
DecisionTree<> wd(inputData, labels, 3, weights, 10 /* Leaf size of 10. */);
|
||||
|
||||
// Load testing data.
|
||||
arma::mat testData;
|
||||
if (!data::Load("vc2_test.csv", testData))
|
||||
FAIL("Cannot load test dataset vc2_test.csv!");
|
||||
|
||||
arma::Mat<size_t> trueTestLabels;
|
||||
if (!data::Load("vc2_test_labels.txt", trueTestLabels))
|
||||
FAIL("Cannot load labels for vc2_test_labels.txt");
|
||||
|
||||
// Get the predicted test labels.
|
||||
arma::Row<size_t> predictions;
|
||||
d.Classify(testData, predictions);
|
||||
|
||||
REQUIRE(predictions.n_elem == testData.n_cols);
|
||||
|
||||
// Figure out the accuracy.
|
||||
double correct = 0.0;
|
||||
for (size_t i = 0; i < predictions.n_elem; ++i)
|
||||
if (predictions[i] == trueTestLabels[i])
|
||||
++correct;
|
||||
correct /= predictions.n_elem;
|
||||
|
||||
REQUIRE(correct > 0.75);
|
||||
|
||||
// Reset the prediction.
|
||||
predictions.zeros();
|
||||
wd.Classify(testData, predictions);
|
||||
|
||||
REQUIRE(predictions.n_elem == testData.n_cols);
|
||||
|
||||
// Figure out the accuracy.
|
||||
double wdcorrect = 0.0;
|
||||
for (size_t i = 0; i < predictions.n_elem; ++i)
|
||||
if (predictions[i] == trueTestLabels[i])
|
||||
++wdcorrect;
|
||||
wdcorrect /= predictions.n_elem;
|
||||
|
||||
REQUIRE(wdcorrect > 0.75);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that we can build a decision tree on a simple categorical dataset.
|
||||
*/
|
||||
|
||||
@@ -27,7 +27,7 @@ using namespace mlpack;
|
||||
using namespace mlpack::gmm;
|
||||
|
||||
/**
|
||||
* Test GMM::Probability() for a single observation for a few cases.
|
||||
* Test GMM::Probability() with a single observation at a time for a few cases.
|
||||
*/
|
||||
|
||||
TEST_CASE("GMMProbabilityTest", "[GMMTest]")
|
||||
|
||||
@@ -1079,10 +1079,11 @@ TEST_CASE("GaussianHMMPredictTest", "[HMMTest]")
|
||||
{
|
||||
double loglikelihood = 0;
|
||||
arma::vec forwardLogProb;
|
||||
for (size_t t = 0; t<emissionProb.size(); ++t)
|
||||
for (size_t t = 0; t < emissionProb.size(); ++t)
|
||||
{
|
||||
loglikelihood = hmm.EmissionLogLikelihood(emissionProb.at(t),
|
||||
loglikelihood, forwardLogProb);
|
||||
loglikelihood,
|
||||
forwardLogProb);
|
||||
}
|
||||
REQUIRE(loglikelihood == Approx(loglikelihoodRef).epsilon(1e-1));
|
||||
}
|
||||
|
||||
@@ -2485,3 +2485,22 @@ TEST_CASE("DatasetMapperNonUniqueTest", "[LoadSaveTest]")
|
||||
REQUIRE(dm.UnmapString(nan, 0, 1) == "goodbye");
|
||||
REQUIRE(dm.UnmapString(nan, 0, 2) == "cheese");
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure if we load a CSV with a header, that that header doesn't get loaded
|
||||
* as a point.
|
||||
*/
|
||||
TEST_CASE("LoadCSVHeaderTest", "[LoadSaveTest]")
|
||||
{
|
||||
fstream f;
|
||||
f.open("test.csv", fstream::out);
|
||||
f << "a, b, c, d" << endl;
|
||||
f << "1, 2, 3, 4" << endl;
|
||||
f << "5, 6, 7, 8" << endl;
|
||||
|
||||
arma::mat dataset;
|
||||
data::Load("test.csv", dataset);
|
||||
|
||||
REQUIRE(dataset.n_rows == 4);
|
||||
REQUIRE(dataset.n_cols == 2);
|
||||
}
|
||||
|
||||
@@ -204,7 +204,8 @@ TEST_CASE_METHOD(RandomForestTestFixture, "RandomForestMaximumDepthTest",
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure only one of training data or pre-trained model is passed.
|
||||
* Make sure only one of training data or pre-trained model is passed, when
|
||||
* warm_start is not passed.
|
||||
*/
|
||||
TEST_CASE_METHOD(RandomForestTestFixture, "RandomForestTrainingVerTest",
|
||||
"[RandomForestMainTest][BindingTests]")
|
||||
@@ -453,3 +454,74 @@ TEST_CASE_METHOD(RandomForestTestFixture, "RandomForestDiffMaxDepthTest",
|
||||
delete rf2;
|
||||
delete rf3;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure that training and input_model are both passed when warm_start is
|
||||
* false.
|
||||
*/
|
||||
TEST_CASE_METHOD(RandomForestTestFixture, "RandomForestTrainingModelWarmStart",
|
||||
"[RandomForestMainTest][BindingTests]")
|
||||
{
|
||||
arma::mat inputData;
|
||||
if (!data::Load("vc2.csv", inputData))
|
||||
FAIL("Cannot load train dataset vc2.csv!");
|
||||
|
||||
arma::Row<size_t> labels;
|
||||
if (!data::Load("vc2_labels.txt", labels))
|
||||
FAIL("Cannot load labels for vc2_labels.txt");
|
||||
|
||||
// Input training data.
|
||||
SetInputParam("training", std::move(inputData));
|
||||
SetInputParam("labels", std::move(labels));
|
||||
|
||||
mlpackMain();
|
||||
|
||||
// Setting warm_start flag.
|
||||
SetInputParam("warm_start", false);
|
||||
|
||||
Log::Fatal.ignoreInput = true;
|
||||
REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error);
|
||||
Log::Fatal.ignoreInput = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensuring that model does gets trained on top of existing one when warm_start
|
||||
* and input_model are both passed.
|
||||
*/
|
||||
TEST_CASE_METHOD(RandomForestTestFixture, "RandomForestWarmStart",
|
||||
"[RandomForestMainTest][BindingTests]")
|
||||
{
|
||||
arma::mat inputData;
|
||||
if (!data::Load("vc2.csv", inputData))
|
||||
FAIL("Cannot load train dataset vc2.csv!");
|
||||
|
||||
arma::Row<size_t> labels;
|
||||
if (!data::Load("vc2_labels.txt", labels))
|
||||
FAIL("Cannot load labels for vc2_labels.txt");
|
||||
|
||||
// Input training data.
|
||||
SetInputParam("training", inputData);
|
||||
SetInputParam("labels", labels);
|
||||
|
||||
mlpackMain();
|
||||
|
||||
// Old number of trees in the model.
|
||||
size_t oldNumTrees =
|
||||
IO::GetParam<RandomForestModel*>("output_model")->rf.NumTrees();
|
||||
|
||||
// Input training data.
|
||||
SetInputParam("training", std::move(inputData));
|
||||
SetInputParam("labels", std::move(labels));
|
||||
SetInputParam("warm_start", true);
|
||||
|
||||
// Input pre-trained model.
|
||||
SetInputParam("input_model",
|
||||
IO::GetParam<RandomForestModel*>("output_model"));
|
||||
|
||||
mlpackMain();
|
||||
|
||||
size_t newNumTrees =
|
||||
IO::GetParam<RandomForestModel*>("output_model")->rf.NumTrees();
|
||||
|
||||
REQUIRE(oldNumTrees + 10 == newNumTrees);
|
||||
}
|
||||
|
||||
@@ -457,14 +457,14 @@ TEST_CASE("RandomForestCategoricalTrainReturnEntropy", "[RandomForestTest]")
|
||||
// Test random forest on unweighted categorical dataset.
|
||||
RandomForest<> rf;
|
||||
double entropy = rf.Train(fullData, di, fullLabels, 5, 15 /* 15 trees */, 1,
|
||||
1e-7, 0, MultipleRandomDimensionSelect(3));
|
||||
1e-7, 0, false, MultipleRandomDimensionSelect(3));
|
||||
|
||||
REQUIRE(std::isfinite(entropy) == true);
|
||||
|
||||
// Test random forest on weighted categorical dataset.
|
||||
RandomForest<> wrf;
|
||||
entropy = wrf.Train(fullData, di, fullLabels, 5, weights, 15 /* 15 trees */,
|
||||
1, 1e-7, 0, MultipleRandomDimensionSelect(3));
|
||||
1, 1e-7, 0, false, MultipleRandomDimensionSelect(3));
|
||||
|
||||
REQUIRE(std::isfinite(entropy) == true);
|
||||
}
|
||||
@@ -498,3 +498,63 @@ TEST_CASE("DifferentTreesTest", "[RandomForestTest]")
|
||||
|
||||
REQUIRE(success == true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that RandomForest::Train() when passed warmStart = True trains on top
|
||||
* of exixting forest and adds the newly trained trees to the previously
|
||||
* exixting forest.
|
||||
*/
|
||||
TEST_CASE("WarmStartTreesTest", "[RandomForestTest]")
|
||||
{
|
||||
arma::mat trainingData;
|
||||
arma::Row<size_t> trainingLabels;
|
||||
data::DatasetInfo di;
|
||||
MockCategoricalData(trainingData, trainingLabels, di);
|
||||
|
||||
// Train a random forest.
|
||||
RandomForest<> rf(trainingData, di, trainingLabels, 5, 25 /* 25 trees */, 1,
|
||||
1e-7, 0, MultipleRandomDimensionSelect(4));
|
||||
|
||||
REQUIRE(rf.NumTrees() == 25);
|
||||
|
||||
rf.Train(trainingData, di, trainingLabels, 5, 20 /* 20 trees */, 1, 1e-7, 0,
|
||||
true /* warmStart */, MultipleRandomDimensionSelect(4));
|
||||
|
||||
REQUIRE(rf.NumTrees() == 25 + 20);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that RandomForest::Train() when passed warmStart = True does not drop
|
||||
* prediction quality on train data. Note that prediction quality may drop due
|
||||
* to overfitting in some cases.
|
||||
*/
|
||||
TEST_CASE("WarmStartTreesPredictionsQualityTest", "[RandomForestTest]")
|
||||
{
|
||||
arma::mat trainingData;
|
||||
arma::Row<size_t> trainingLabels;
|
||||
data::DatasetInfo di;
|
||||
MockCategoricalData(trainingData, trainingLabels, di);
|
||||
|
||||
// Train a random forest.
|
||||
RandomForest<> rf(trainingData, di, trainingLabels, 5, 3 /* 3 trees */, 1,
|
||||
1e-7, 0, MultipleRandomDimensionSelect(4));
|
||||
|
||||
// Get performance statistics on train data.
|
||||
arma::Row<size_t> oldPredictions;
|
||||
rf.Classify(trainingData, oldPredictions);
|
||||
|
||||
// Calculate the number of correct points.
|
||||
size_t oldCorrect = arma::accu(oldPredictions == trainingLabels);
|
||||
|
||||
rf.Train(trainingData, di, trainingLabels, 5, 20 /* 20 trees */, 1, 1e-7, 0,
|
||||
true /* warmStart */, MultipleRandomDimensionSelect(4));
|
||||
|
||||
// Get performance statistics on train data.
|
||||
arma::Row<size_t> newPredictions;
|
||||
rf.Classify(trainingData, newPredictions);
|
||||
|
||||
// Calculate the number of correct points.
|
||||
size_t newCorrect = arma::accu(newPredictions == trainingLabels);
|
||||
|
||||
REQUIRE(newCorrect - oldCorrect >= 0);
|
||||
}
|
||||
|
||||
@@ -223,9 +223,9 @@ TEST_CASE("ZeroRatioStratifiedSplitData", "[SplitDataTest]")
|
||||
|
||||
// Set the labels to 5 0s and 10 1s.
|
||||
const Row<size_t> labels = { 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
|
||||
const double test_ratio = 0;
|
||||
const double testRatio = 0;
|
||||
|
||||
const auto value = Split(input, labels, test_ratio, false, true);
|
||||
const auto value = Split(input, labels, testRatio, false, true);
|
||||
REQUIRE(std::get<0>(value).n_cols == 15);
|
||||
REQUIRE(std::get<1>(value).n_cols == 0);
|
||||
REQUIRE(std::get<2>(value).n_cols == 15);
|
||||
@@ -242,9 +242,9 @@ TEST_CASE("TotalRatioStratifiedSplitData", "[SplitDataTest]")
|
||||
|
||||
// Set the labels to 5 0s and 10 1s.
|
||||
const Row<size_t> labels = { 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
|
||||
const double test_ratio = 1;
|
||||
const double testRatio = 1;
|
||||
|
||||
const auto value = Split(input, labels, test_ratio, false, true);
|
||||
const auto value = Split(input, labels, testRatio, false, true);
|
||||
REQUIRE(std::get<0>(value).n_cols == 0);
|
||||
REQUIRE(std::get<1>(value).n_cols == 15);
|
||||
REQUIRE(std::get<2>(value).n_cols == 0);
|
||||
@@ -263,9 +263,9 @@ TEST_CASE("StratifiedSplitDataResultTest", "[SplitDataTest]")
|
||||
const Row<size_t> labels = { 0, 0, 0, 0,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 };
|
||||
const double test_ratio = 0.25;
|
||||
const double testRatio = 0.25;
|
||||
|
||||
const auto value = Split(input, labels, test_ratio, true, true);
|
||||
const auto value = Split(input, labels, testRatio, true, true);
|
||||
REQUIRE(static_cast<uvec>(find(std::get<2>(value) == 0)).n_rows == 3);
|
||||
REQUIRE(static_cast<uvec>(find(std::get<2>(value) == 1)).n_rows == 6);
|
||||
REQUIRE(static_cast<uvec>(find(std::get<2>(value) == 2)).n_rows == 9);
|
||||
@@ -293,22 +293,22 @@ TEST_CASE("StratifiedSplitLargerDataResultTest", "[SplitDataTest]")
|
||||
input.randu();
|
||||
|
||||
// 256 0s, 128 1s, 64 2s and 32 3s.
|
||||
Row<size_t> zero_label(256);
|
||||
Row<size_t> one_label(128);
|
||||
Row<size_t> two_label(64);
|
||||
Row<size_t> three_label(32);
|
||||
Row<size_t> zeroLabel(256);
|
||||
Row<size_t> oneLabel(128);
|
||||
Row<size_t> twoLabel(64);
|
||||
Row<size_t> threeLabel(32);
|
||||
|
||||
zero_label.fill(0);
|
||||
one_label.fill(1);
|
||||
two_label.fill(2);
|
||||
three_label.fill(3);
|
||||
zeroLabel.fill(0);
|
||||
oneLabel.fill(1);
|
||||
twoLabel.fill(2);
|
||||
threeLabel.fill(3);
|
||||
|
||||
Row<size_t> labels = arma::join_rows(zero_label, one_label);
|
||||
labels = arma::join_rows(labels, two_label);
|
||||
labels = arma::join_rows(labels, three_label);
|
||||
const double test_ratio = 0.3;
|
||||
Row<size_t> labels = arma::join_rows(zeroLabel, oneLabel);
|
||||
labels = arma::join_rows(labels, twoLabel);
|
||||
labels = arma::join_rows(labels, threeLabel);
|
||||
const double testRatio = 0.3;
|
||||
|
||||
const auto value = Split(input, labels, test_ratio, false, true);
|
||||
const auto value = Split(input, labels, testRatio, false, true);
|
||||
REQUIRE(static_cast<uvec>(find(std::get<2>(value) == 0)).n_rows == 180);
|
||||
REQUIRE(static_cast<uvec>(find(std::get<2>(value) == 1)).n_rows == 90);
|
||||
REQUIRE(static_cast<uvec>(find(std::get<2>(value) == 2)).n_rows == 45);
|
||||
@@ -322,3 +322,102 @@ TEST_CASE("StratifiedSplitLargerDataResultTest", "[SplitDataTest]")
|
||||
mat concat = arma::join_rows(std::get<0>(value), std::get<1>(value));
|
||||
CheckMatEqual(input, concat);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that Split() with stratifyData true throws a runtime error if labels
|
||||
* are not of type arma::Row<>.
|
||||
*/
|
||||
TEST_CASE("StratifiedSplitRunTimeErrorTest", "[SplitDataTest]")
|
||||
{
|
||||
mat input(3, 480);
|
||||
mat labels(2, 480);
|
||||
input.randu();
|
||||
labels.randu();
|
||||
|
||||
const double testRatio = 0.3;
|
||||
|
||||
REQUIRE_THROWS_AS(Split(input, labels, testRatio, false, true),
|
||||
std::runtime_error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Split with input of type field<mat>.
|
||||
*/
|
||||
TEST_CASE("SplitDataResultField", "[SplitDataTest]")
|
||||
{
|
||||
field<mat> input(1, 2);
|
||||
|
||||
mat matA(2, 10);
|
||||
mat matB(2, 10);
|
||||
|
||||
size_t count = 0; // Counter for unique sequential values.
|
||||
matA.imbue([&count]() { return ++count; });
|
||||
matB.imbue([&count]() { return ++count; });
|
||||
|
||||
input(0, 0) = matA;
|
||||
input(0, 1) = matB;
|
||||
|
||||
const auto value = Split(input, 0.5, false);
|
||||
REQUIRE(std::get<0>(value).n_cols == 1); // Train data.
|
||||
REQUIRE(std::get<1>(value).n_cols == 1); // Test data.
|
||||
|
||||
field<mat> concat = {std::get<0>(value)(0), std::get<1>(value)(0)};
|
||||
// Order matters here.
|
||||
CheckFields(input, concat);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for Split() with labels of type arma::Mat with shuffleData = False.
|
||||
*/
|
||||
TEST_CASE("SplitMatrixLabeledData", "[SplitDataTest]")
|
||||
{
|
||||
const mat input(2, 10, fill::randu);
|
||||
const mat labels(2, 10, fill::randu);
|
||||
|
||||
const auto value = Split(input, labels, 0.2, false);
|
||||
REQUIRE(std::get<0>(value).n_cols == 8);
|
||||
REQUIRE(std::get<1>(value).n_cols == 2);
|
||||
REQUIRE(std::get<2>(value).n_cols == 8);
|
||||
REQUIRE(std::get<3>(value).n_cols == 2);
|
||||
|
||||
mat inputConcat = arma::join_rows(std::get<0>(value), std::get<1>(value));
|
||||
mat labelsConcat = arma::join_rows(std::get<2>(value), std::get<3>(value));
|
||||
|
||||
// Order matters here.
|
||||
CheckMatrices(input, inputConcat);
|
||||
CheckMatrices(labels, labelsConcat);
|
||||
}
|
||||
|
||||
/**
|
||||
* Split with input of type field<mat> and label of type field<vec>.
|
||||
*/
|
||||
TEST_CASE("SplitLabeledDataResultField", "[SplitDataTest]")
|
||||
{
|
||||
field<mat> input(1, 2);
|
||||
field<vec> label(1, 2);
|
||||
|
||||
mat matA(2, 10, fill::randu);
|
||||
mat matB(2, 10, fill::randu);
|
||||
|
||||
vec vecA(10, fill::randu);
|
||||
vec vecB(10, fill::randu);
|
||||
|
||||
input(0, 0) = matA;
|
||||
input(0, 1) = matB;
|
||||
|
||||
label(0, 0) = vecA;
|
||||
label(0, 1) = vecB;
|
||||
|
||||
const auto value = Split(input, label, 0.5, false);
|
||||
REQUIRE(std::get<0>(value).n_cols == 1); // Train data.
|
||||
REQUIRE(std::get<1>(value).n_cols == 1); // Test data.
|
||||
REQUIRE(std::get<2>(value).n_cols == 1); // Train label.
|
||||
REQUIRE(std::get<3>(value).n_cols == 1); // Test label.
|
||||
|
||||
field<mat> inputConcat = {std::get<0>(value)(0), std::get<1>(value)(0)};
|
||||
field<vec> labelConcat = {std::get<2>(value)(0), std::get<3>(value)(0)};
|
||||
|
||||
// Order matters here.
|
||||
CheckFields(input, inputConcat);
|
||||
CheckFields(label, labelConcat);
|
||||
}
|
||||
|
||||
@@ -50,6 +50,20 @@ inline void CheckMatrices(const arma::Mat<size_t>& a,
|
||||
REQUIRE(a[i] == b[i]);
|
||||
}
|
||||
|
||||
template <typename FieldType,
|
||||
typename = std::enable_if_t<
|
||||
arma::is_arma_type<typename FieldType::object_type>::value>>
|
||||
// Check the values of two field types.
|
||||
inline void CheckFields(const FieldType& a,
|
||||
const FieldType& b)
|
||||
{
|
||||
REQUIRE(a.n_rows == b.n_rows);
|
||||
REQUIRE(a.n_cols == b.n_cols);
|
||||
|
||||
for (size_t i = 0; i < a.n_slices; ++i)
|
||||
CheckMatrices(a(i), b(i));
|
||||
}
|
||||
|
||||
// Check the values of two cubes.
|
||||
inline void CheckMatrices(const arma::cube& a,
|
||||
const arma::cube& b,
|
||||
|
||||
@@ -31,7 +31,7 @@ using namespace mlpack::metric;
|
||||
// weird things and will cause bizarre problems.
|
||||
|
||||
// Test the defaults.
|
||||
TEST_CASE("DefaultsTraitsTest", "[TreeTraitsTestt]")
|
||||
TEST_CASE("DefaultsTraitsTest", "[TreeTraitsTest]")
|
||||
{
|
||||
// An irrelevant non-tree type class is used here so that the default
|
||||
// implementation of TreeTraits is chosen.
|
||||
@@ -48,7 +48,7 @@ TEST_CASE("DefaultsTraitsTest", "[TreeTraitsTestt]")
|
||||
}
|
||||
|
||||
// Test the binary space tree traits.
|
||||
TEST_CASE("BinarySpaceTreeTraitsTest", "[TreeTraitsTestt]")
|
||||
TEST_CASE("BinarySpaceTreeTraitsTest", "[TreeTraitsTest]")
|
||||
{
|
||||
typedef BinarySpaceTree<LMetric<2, false>> TreeType;
|
||||
|
||||
@@ -74,7 +74,7 @@ TEST_CASE("BinarySpaceTreeTraitsTest", "[TreeTraitsTestt]")
|
||||
}
|
||||
|
||||
// Test the cover tree traits.
|
||||
TEST_CASE("CoverTreeTraitsTest", "[TreeTraitsTestt]")
|
||||
TEST_CASE("CoverTreeTraitsTest", "[TreeTraitsTest]")
|
||||
{
|
||||
// Children may be overlapping.
|
||||
bool b = TreeTraits<CoverTree<>>::HasOverlappingChildren;
|
||||
|
||||
Reference in New Issue
Block a user