Merge branch 'master' into Fix-solaris-winndows-r

This commit is contained in:
Yashwant Singh Parihar
2021-03-14 10:05:56 +05:30
committed by GitHub
196 changed files with 7846 additions and 5576 deletions
-219
View File
@@ -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 -1
View File
@@ -21,7 +21,7 @@ steps:
unset BOOST_ROOT
echo "##vso[task.setvariable variable=BOOST_ROOT]"$BOOST_ROOT
sudo apt-get install -y --allow-unauthenticated libopenblas-dev liblapack-dev g++ libboost1.70-dev libarmadillo-dev xz-utils
sudo apt-get install -y --allow-unauthenticated libopenblas-dev g++ libboost1.70-dev xz-utils
if [ "$(binding)" == "python" ]; then
export PYBIN=$(which python)
+3 -3
View File
@@ -14,7 +14,7 @@ steps:
set -e
sudo xcode-select --switch /Applications/Xcode_12.2.app/Contents/Developer
unset BOOST_ROOT
brew install openblas armadillo boost cereal
brew install libomp openblas armadillo boost cereal
if [ "$(binding)" == "python" ]; then
pip install --upgrade pip
@@ -22,7 +22,7 @@ steps:
fi
if [ "a$(julia.version)" != "a" ]; then
brew cask install julia
brew install --cask julia
fi
git clone --depth 1 https://github.com/mlpack/jenkins-conf.git conf
@@ -65,4 +65,4 @@ steps:
inputs:
pathtoPublish: 'build/Testing/'
artifactName: 'Tests'
displayName: 'Publish artifacts test results'
displayName: 'Publish artifacts test results'
-110
View File
@@ -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
)
-135
View File
@@ -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
+3 -35
View File
@@ -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)
@@ -467,6 +432,9 @@ if (OPENMP_FOUND)
add_definitions(-DHAS_OPENMP)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
if(OpenMP_CXX_FOUND)
set(MLPACK_LIBRARIES ${MLPACK_LIBRARIES} ${OpenMP_CXX_LIBRARIES})
endif ()
else ()
# Disable warnings for all the unknown OpenMP pragmas.
if (NOT MSVC)
+2 -1
View File
@@ -7,7 +7,7 @@ Source:
Files: *
Copyright:
Copyright 2008-2020, Ryan Curtin <ryan@ratml.org>
Copyright 2008-2021, Ryan Curtin <ryan@ratml.org>
Copyright 2008-2013, Bill March <march@gatech.edu>
Copyright 2008-2012, Dongryeol Lee <dongryel@cc.gatech.edu>
Copyright 2008-2013, Nishant Mehta <niche@cc.gatech.edu>
@@ -141,6 +141,7 @@ Copyright:
Copyright 2020, Alex Nguyen <alexvn.edu@gmail.com>
Copyright 2020, Gaurav Ghati <gauravghatii@gmail.com>
Copyright 2020, Anmolpreet Singh <anmol323c@gmail.com>
Copyright 2021, Tru Hoang <trugiahoang@gmail.com>
License: BSD-3-clause
All rights reserved.
+22 -2
View File
@@ -1,5 +1,10 @@
### mlpack ?.?.?
###### ????-??-??
* Added Pixel Shuffle layer (#2563).
* Add "check_input_matrices" option to python bindings that checks
for NaN and inf values in all the input matrices (#2787).
* Add Adjusted R squared functionality to R2Score::Evaluate (#2624).
* Disabled all the bindings by default in CMake (#2782).
@@ -12,10 +17,26 @@
* Add Triplet Margin Loss function (#2762).
* Add finalizers to Julia binding model types to fix memory handling (#2756).
* HMM: add functions to calculate likelihood for data stream with/without
pre-calculated emission probability (#2142).
* Replace Boost serialization library with Cereal (#2458).
* Add `PYTHON_INSTALL_PREFIX` CMake option to specify installation root for
Python bindings (#2797).
* Removed `boost::visitor` from model classes for `knn`, `kfn`, `cf`,
`range_search`, `krann`, and `kde` bindings (#2803).
* Add k-means++ initialization strategy (#2813).
* `NegativeLogLikelihood<>` now expects classes in the range `0` to
`numClasses - 1` (#2534).
* Add `Lambda1()`, `Lambda2()`, `UseCholesky()`, and `Tolerance()` members to
`LARS` so parameters for training can be modified (#2861).
### mlpack 3.4.2
###### 2020-10-26
* Added Mean Absolute Percentage Error.
@@ -36,7 +57,6 @@
### mlpack 3.4.0
###### 2020-09-01
* Issue warnings when metrics produce NaNs in KFoldCV (#2595).
* Added bindings for _R_ during Google Summer of Code (#2556).
+1 -1
View File
@@ -15,7 +15,6 @@ src="https://cdn.rawgit.com/mlpack/mlpack.org/e7d36ed8/mlpack-black.svg" style="
<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://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>
@@ -203,6 +202,7 @@ Options are specified with the -D flag. The allowed options include:
BUILD_CLI_EXECUTABLES=(ON/OFF): whether or not to build command-line programs
BUILD_PYTHON_BINDINGS=(ON/OFF): whether or not to build Python bindings
PYTHON_EXECUTABLE=(/path/to/python_version): Path to specific Python executable
PYTHON_INSTALL_PREFIX=(/path/to/python/): Path to root of Python installation
BUILD_JULIA_BINDINGS=(ON/OFF): whether or not to build Julia bindings
JULIA_EXECUTABLE=(/path/to/julia): Path to specific Julia executable
BUILD_GO_BINDINGS=(ON/OFF): whether or not to build Go bindings
+7 -4
View File
@@ -175,9 +175,13 @@ The full list of options mlpack allows:
(i.e. \c mlpack_knn, \c mlpack_kfn, \c mlpack_logistic_regression, etc.)
(default ON)
- BUILD_PYTHON_BINDINGS=(ON/OFF): compile the bindings for Python, if the
necessary Python libraries are available (default ON except on Windows)
necessary Python libraries are available (default OFF)
- BUILD_R_BINDINGS=(ON/OFF): compile the bindings for R, if R is found
(default OFF)
- BUILD_GO_BINDINGS=(ON/OFF): compile Go bindings, if Go and the necessary Go
and Gonum exist. (default OFF)
- BUILD_JULIA_BINDINGS=(ON/OFF): compile Julia bindings, if Julia is found
(default ON)
(default OFF)
- BUILD_SHARED_LIBS=(ON/OFF): compile shared libraries as opposed to
static libraries (default ON)
- TEST_VERBOSE=(ON/OFF): run test cases in \c mlpack_test with verbose output
@@ -187,9 +191,8 @@ 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
- BUILD_MARKDOWN_BINDINGS=(ON/OFF): Build Markdown bindings for website
documentation (default OFF)
+7 -6
View File
@@ -210,8 +210,9 @@ int main()
data::Load("thyroid_test.csv", testData, true);
// Split the labels from the training set and testing set respectively.
arma::mat trainLabels = trainData.row(trainData.n_rows - 1);
arma::mat testLabels = testData.row(testData.n_rows - 1);
// Decrement the labels by 1, so they are in the range 0 to (numClasses - 1).
arma::mat trainLabels = trainData.row(trainData.n_rows - 1) - 1;
arma::mat testLabels = testData.row(testData.n_rows - 1) - 1;
trainData.shed_row(trainData.n_rows - 1);
testData.shed_row(testData.n_rows - 1);
@@ -246,9 +247,8 @@ int main()
// Find index of max prediction for each data point and store in "prediction"
for (size_t i = 0; i < predictionTemp.n_cols; ++i)
{
// we add 1 to the max index, so that it matches the actual test labels.
prediction(i) = arma::as_scalar(arma::find(
arma::max(predictionTemp.col(i)) == predictionTemp.col(i), 1)) + 1;
arma::max(predictionTemp.col(i)) == predictionTemp.col(i), 1));
}
/*
@@ -311,7 +311,7 @@ void RNNModel()
for (size_t i = 0; i < labelsTemp.n_cols; ++i)
{
const int value = arma::as_scalar(arma::find(
arma::max(labelsTemp.col(i)) == labelsTemp.col(i), 1)) + 1;
arma::max(labelsTemp.col(i)) == labelsTemp.col(i), 1));
labels.col(i).fill(value);
}
@@ -589,8 +589,9 @@ arma::mat trainData = dataset.submat(0, 0, dataset.n_rows - 4,
dataset.n_cols - 1);
// Split the data from the training set.
// Subtract 1 so the labels are the range from 0 to (numClasses - 1).
arma::mat trainLabels = dataset.submat(dataset.n_rows - 3, 0,
dataset.n_rows - 1, dataset.n_cols - 1);
dataset.n_rows - 1, dataset.n_cols - 1) - 1;
// Initialize the network.
FFN<> model;
+106 -25
View File
@@ -87,6 +87,93 @@ if (BUILD_R_BINDINGS)
string(TIMESTAMP PACKAGE_DATE "%Y-%m-%d")
# We need to generate an Authors@R list using every single contributor in
# COPYRIGHT.txt. That takes a little bit of processing.
file(READ "${CMAKE_SOURCE_DIR}/COPYRIGHT.txt" COPYRIGHT_TXT_CONTENTS)
string(REGEX MATCHALL " Copyright [0-9-]*, ([^\n]*)\n" CONTRIBUTORS_LIST
"${COPYRIGHT_TXT_CONTENTS}")
# These are the authors meant to be listed as 'authors' and not
# 'contributors'. If you contributed specifically to the R bindings, you
# should probably be listed here, so if you're not, open a PR to fix it! :)
set(SPECIAL_AUTHORS "Yashwant Singh Parihar" "Ryan Curtin" "Dirk Eddelbuettel"
"James Balamuta")
string(CONCAT AUTHORS_R "c(\n"
" person(\"Yashwant\", \"Singh Parihar\", "
"email = \"yashwantsingh.sngh@gmail.com\", "
"role = c(\"aut\", \"ctb\", \"cph\")),\n"
" person(\"Ryan\", \"Curtin\", email = \"ryan@ratml.org\", "
"role = c(\"aut\", \"ctb\", \"cph\", \"cre\")),\n"
" person(\"Dirk\", \"Eddelbuettel\", email = \"edd@debian.org\", "
"role = c(\"aut\", \"ctb\", \"cph\")),\n"
" person(\"James\", \"Balamuta\", "
"email = \"james.balamuta@gmail.com\", "
"role = c(\"aut\", \"ctb\", \"cph\")),")
foreach (CONTRIBUTOR_LINE ${CONTRIBUTORS_LIST})
# Strip 'Copyright XXXX-YYYY, '.
string(REGEX REPLACE "^ Copyright [0-9-]*, (.*)\n$" "\\1"
CONTRIBUTOR_FILTERED "${CONTRIBUTOR_LINE}")
# Extract the email if it exists.
string(REGEX MATCH "^[^<]*<(.*)>.*$" HAS_EMAIL "${CONTRIBUTOR_FILTERED}")
# The first name is just the first space-delimited word. (That may not
# always be right, but we have no way to know what is a first name and last
# name and therefore must assume.)
string(REGEX REPLACE "^([^ ]*) .*$" "\\1" CONTRIBUTOR_FIRST_NAME
"${CONTRIBUTOR_FILTERED}")
# Extracting the last name is just the rest of the tokens, but the regex is
# different depending on whether we managed to get an email.
if (HAS_EMAIL)
string(REGEX REPLACE "^[^<]*<(.*)>.*$" "\\1" CONTRIBUTOR_EMAIL
"${CONTRIBUTOR_FILTERED}")
string(REGEX MATCH "^[^ ]* (.*) <.*$" CONTRIBUTOR_LAST_NAME
"${CONTRIBUTOR_FILTERED}")
if (NOT CONTRIBUTOR_LAST_NAME)
set (CONTRIBUTOR_LAST_NAME "")
else ()
string(REGEX REPLACE "^[^ ]* (.*) <.*$" "\\1" CONTRIBUTOR_LAST_NAME
"${CONTRIBUTOR_FILTERED}")
endif ()
# Skip anyone already listed as an author.
if ("${CONTRIBUTOR_FIRST_NAME} ${CONTRIBUTOR_LAST_NAME}" IN_LIST
SPECIAL_AUTHORS)
continue()
endif ()
string(CONCAT AUTHORS_R "${AUTHORS_R}\n "
"person(\"${CONTRIBUTOR_FIRST_NAME}\", \"${CONTRIBUTOR_LAST_NAME}\", "
"email = \"${CONTRIBUTOR_EMAIL}\", role = c(\"ctb\", \"cph\")),")
else ()
# No email is available. So just get the last name.
string(REGEX MATCH "^[^ ]* (.*)$" CONTRIBUTOR_LAST_NAME
"${CONTRIBUTOR_FILTERED}")
if (NOT CONTRIBUTOR_LAST_NAME)
set (CONTRIBUTOR_LAST_NAME "")
else ()
string(REGEX REPLACE "^[^ ]* (.*)$" "\\1" CONTRIBUTOR_LAST_NAME
"${CONTRIBUTOR_FILTERED}")
endif ()
# Skip anyone already listed as an author.
if ("${CONTRIBUTOR_FIRST_NAME} ${CONTRIBUTOR_LAST_NAME}" IN_LIST
SPECIAL_AUTHORS)
continue()
endif ()
string(CONCAT AUTHORS_R "${AUTHORS_R}\n "
"person(\"${CONTRIBUTOR_FIRST_NAME}\", \"${CONTRIBUTOR_LAST_NAME}\", "
"role = c(\"ctb\", \"cph\")),")
endif ()
endforeach ()
# We also have to remove the final comma...
string(REGEX REPLACE ",$" "" AUTHORS_R_OUT "${AUTHORS_R}")
set(AUTHORS_R "${AUTHORS_R_OUT})")
configure_file(${CMAKE_SOURCE_DIR}/src/mlpack/bindings/R/mlpack/DESCRIPTION.in
${CMAKE_CURRENT_BINARY_DIR}/mlpack/DESCRIPTION
@ONLY)
@@ -136,9 +223,11 @@ if (BUILD_R_BINDINGS)
"${CMAKE_CURRENT_SOURCE_DIR}/mlpack/tests/testthat.R"
)
set(LICENSE_SOURCES
"${CMAKE_SOURCE_DIR}/LICENSE.txt"
)
# Configure the license file.
string(TIMESTAMP LICENSE_YEAR "%Y")
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/mlpack/LICENSE.in"
"${CMAKE_CURRENT_BINARY_DIR}/mlpack/LICENSE")
add_custom_target(r_copy ALL)
# First we have to create all the required directories for copy.
@@ -160,22 +249,22 @@ if (BUILD_R_BINDINGS)
# Copy all necessary files for building package.
foreach(cpp_file ${CPP_SOURCES})
add_custom_command(TARGET r_copy PRE_BUILD
COMMAND ${CMAKE_COMMAND} ARGS -E copy_if_different
${cpp_file}
${CMAKE_CURRENT_BINARY_DIR}/mlpack/src/)
add_custom_command(TARGET r_copy PRE_BUILD
COMMAND ${CMAKE_COMMAND} ARGS -E copy_if_different
${cpp_file}
${CMAKE_CURRENT_BINARY_DIR}/mlpack/src/)
endforeach()
foreach(r_file ${R_SOURCES})
add_custom_command(TARGET r_copy PRE_BUILD
COMMAND ${CMAKE_COMMAND} ARGS -E copy_if_different
${r_file}
${CMAKE_CURRENT_BINARY_DIR}/mlpack/R/)
add_custom_command(TARGET r_copy PRE_BUILD
COMMAND ${CMAKE_COMMAND} ARGS -E copy_if_different
${r_file}
${CMAKE_CURRENT_BINARY_DIR}/mlpack/R/)
endforeach()
foreach(bindings_file ${BINDINGS_SOURCES})
add_custom_command(TARGET r_copy PRE_BUILD
COMMAND ${CMAKE_COMMAND} ARGS -E copy_if_different
${bindings_file}
${CMAKE_CURRENT_BINARY_DIR}/mlpack/src/mlpack/bindings/R)
add_custom_command(TARGET r_copy PRE_BUILD
COMMAND ${CMAKE_COMMAND} ARGS -E copy_if_different
${bindings_file}
${CMAKE_CURRENT_BINARY_DIR}/mlpack/src/mlpack/bindings/R)
endforeach()
add_custom_command(TARGET r_copy PRE_BUILD
COMMAND ${CMAKE_COMMAND} ARGS -E copy_if_different
@@ -185,14 +274,6 @@ if (BUILD_R_BINDINGS)
COMMAND ${CMAKE_COMMAND} ARGS -E copy_if_different
${R_TESTS_SOURCES}
${CMAKE_CURRENT_BINARY_DIR}/mlpack/tests)
add_custom_command(TARGET r_copy PRE_BUILD
COMMAND ${CMAKE_COMMAND} ARGS -E copy_if_different
${LICENSE_SOURCES}
${CMAKE_CURRENT_BINARY_DIR}/mlpack)
add_custom_command(TARGET r_copy PRE_BUILD
COMMAND ${CMAKE_COMMAND} ARGS -E rename
"${CMAKE_CURRENT_BINARY_DIR}/mlpack/LICENSE.txt"
"${CMAKE_CURRENT_BINARY_DIR}/mlpack/LICENSE")
# This file will take care of multiple definition of functions in .cpp files.
add_custom_command(TARGET r_copy PRE_BUILD
COMMAND ${CMAKE_COMMAND} ARGS -E touch
@@ -234,8 +315,8 @@ if (BUILD_R_BINDINGS)
# Installation script for the packagae.
install(CODE
"execute_process(
COMMAND R CMD INSTALL mlpack_${PACKAGE_VERSION}.tar.gz
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}"
COMMAND ${R_EXECUTABLE} CMD INSTALL mlpack_${PACKAGE_VERSION}.tar.gz
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})"
)
add_dependencies(R r_build)
+5 -5
View File
@@ -2,11 +2,11 @@ Package: mlpack
Title: 'Rcpp' Integration for the 'mlpack' Library
Version: @PACKAGE_VERSION@
Date: @PACKAGE_DATE@
Author: mlpack Team
Maintainer: Ryan Curtin <ryan@ratml.org>
Description: 'mlpack' is a fast, flexible machine learning library, written
in C++, that aims to provide fast, extensible implementations of
cutting-edge machine learning algorithms.
Authors@R: @AUTHORS_R@
Description: A fast, flexible machine learning library, written in C++, that
aims to provide fast, extensible implementations of cutting-edge
machine learning algorithms. See also Curtin et al. (2018)
<doi:10.21105/joss.00726>.
SystemRequirements: A C++11 compiler. Versions 4.8.*, 4.9.* or later of GCC
will be fine.
License: BSD_3_clause + file LICENSE
+3
View File
@@ -0,0 +1,3 @@
YEAR: ${LICENSE_YEAR}
COPYRIGHT HOLDER: mlpack Team
ORGANIZATION: mlpack
@@ -84,7 +84,7 @@ std::string PrintTypeDoc(
*/
template<typename T>
std::string PrintTypeDoc(
util::ParamData& data,
util::ParamData& /* data */,
const typename std::enable_if<arma::is_arma_type<T>::value>::type*)
{
if (T::is_col || T::is_row)
+12 -2
View File
@@ -36,8 +36,18 @@ void PrintHeaders(const std::string& bindingName,
{
BindingInfo::Language() = languages[i];
cout << " - [" << GetBindingName(bindingName) << "](#" << languages[i]
<< "_" << bindingName << "){: .language-link #" << languages[i] << " }"
// Get the name of the binding in the target language, and convert it to
// lowercase (since the anchor link will be in lowercase).
const std::string langBindingName = GetBindingName(bindingName);
std::string anchorName = langBindingName;
std::transform(anchorName.begin(), anchorName.end(), anchorName.begin(),
[](unsigned char c) { return std::tolower(c); });
// Strip '()' from the end if needed.
if (anchorName.substr(anchorName.size() - 2, 2) == "()")
anchorName = anchorName.substr(0, anchorName.size() - 2);
cout << " - [" << langBindingName << "](#" << languages[i]
<< "_" << anchorName << "){: .language-link #" << languages[i] << " }"
<< endl;
}
}
+8 -2
View File
@@ -214,14 +214,20 @@ add_custom_command(TARGET python POST_BUILD
add_dependencies(python python_configured)
# Configure installation script file.
if (NOT PYTHON_INSTALL_PREFIX)
set(PYTHON_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}")
endif ()
execute_process(COMMAND ${PYTHON_EXECUTABLE}
"${CMAKE_CURRENT_SOURCE_DIR}/print_python_version.py" "${CMAKE_INSTALL_PREFIX}"
"${CMAKE_CURRENT_SOURCE_DIR}/print_python_version.py"
"${PYTHON_INSTALL_PREFIX}"
OUTPUT_VARIABLE CMAKE_PYTHON_PATH)
string(STRIP "${CMAKE_PYTHON_PATH}" CMAKE_PYTHON_PATH)
install(CODE "set(ENV{PYTHONPATH} ${CMAKE_PYTHON_PATH})")
install(CODE "set(PYTHON_EXECUTABLE \"${PYTHON_EXECUTABLE}\")")
install(CODE "set(CMAKE_BINARY_DIR \"${CMAKE_BINARY_DIR}\")")
install(CODE "set(CMAKE_INSTALL_PREFIX \"${CMAKE_INSTALL_PREFIX}\")")
install(CODE "set(PYTHON_INSTALL_PREFIX \"${PYTHON_INSTALL_PREFIX}\")")
install(CODE "execute_process(COMMAND mkdir -p $ENV{DESTDIR}${CMAKE_PYTHON_PATH})")
install(SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/PythonInstall.cmake")
@@ -5,13 +5,13 @@
if (DEFINED ENV{DESTDIR})
execute_process(COMMAND ${PYTHON_EXECUTABLE}
"${CMAKE_BINARY_DIR}/src/mlpack/bindings/python/setup.py" install
--prefix=${CMAKE_INSTALL_PREFIX} --root=$ENV{DESTDIR}
--prefix=${PYTHON_INSTALL_PREFIX} --root=$ENV{DESTDIR}
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/src/mlpack/bindings/python/"
RESULT_VARIABLE setup_res)
else ()
execute_process(COMMAND ${PYTHON_EXECUTABLE}
"${CMAKE_BINARY_DIR}/src/mlpack/bindings/python/setup.py" install
--prefix=${CMAKE_INSTALL_PREFIX}
--prefix=${PYTHON_INSTALL_PREFIX}
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/src/mlpack/bindings/python/"
RESULT_VARIABLE setup_res)
endif ()
+3
View File
@@ -38,6 +38,9 @@ cdef extern from "<mlpack/core/util/io.hpp>" namespace "mlpack" nogil:
@staticmethod
void ClearSettings() nogil except +
@staticmethod
void CheckInputMatrices() nogil except +
cdef extern from "<mlpack/bindings/python/mlpack/io_util.hpp>" \
namespace "mlpack::util" nogil:
void SetParam[T](string, T&) nogil except +
+10
View File
@@ -224,6 +224,16 @@ void PrintPYX(const util::BindingDetails& doc,
cout << " IO.SetPassed(<const string> '" << d.name << "')" << endl;
}
// Checking the type of check_input_matrices parameter.
cout << " if not isinstance(check_input_matrices, bool):" << endl;
cout << " raise TypeError(" <<"\"'check_input_matrices\' must have type "
<< "\'bool'!\")" << endl;
cout << endl;
// Before calling mlpackMain(), we check input matrices for NaN values if needed.
cout << " if check_input_matrices:" << endl;
cout << " IO.CheckInputMatrices()" << endl;
// Call the method.
cout << " # Call the mlpack program." << endl;
cout << " mlpackMain()" << endl;
+4 -2
View File
@@ -64,8 +64,10 @@ class PyOption
data.required = required;
data.input = input;
data.loaded = false;
// Only "verbose" and "copy_all_inputs" will be persistent.
if (identifier == "verbose" || identifier == "copy_all_inputs")
// Only "verbose", "copy_all_inputs" and "check_input_matrices"
// will be persistent.
if (identifier == "verbose" || identifier == "copy_all_inputs" ||
identifier == "check_input_matrices")
data.persistent = true;
else
data.persistent = false;
@@ -1336,5 +1336,101 @@ class TestPythonBinding(unittest.TestCase):
self.assertEqual(output2['model_bw_out'], 20.0)
self.assertEqual(output3['model_bw_out'], 20.0)
def testCheckInputMatricesNaN(self):
"""
Checks that an exception is thrown if the input matrix contains
NaN values.
"""
x = np.random.rand(100, 5)
a = np.random.randint(low=0, high=100)
b = np.random.randint(low=0, high=5)
x[a][b] = np.nan
self.assertRaises(RuntimeError,
lambda : test_python_binding(string_in="hello",
int_in=12,
double_in=4.0,
mat_req_in=[[1.0]],
col_req_in=[1.0],
matrix_in=x,
check_input_matrices=True))
x_vec = np.random.rand(100)
a = np.random.randint(low=0, high=100)
x_vec[a] = np.nan
self.assertRaises(RuntimeError,
lambda : test_python_binding(string_in="hello",
int_in=12,
double_in=4.0,
mat_req_in=[[1.0]],
col_req_in=[1.0],
row_in=x_vec,
check_input_matrices=True))
self.assertRaises(RuntimeError,
lambda : test_python_binding(string_in="hello",
int_in=12,
double_in=4.0,
mat_req_in=[[1.0]],
col_req_in=[1.0],
col_in=x_vec,
check_input_matrices=True))
self.assertRaises(RuntimeError,
lambda : test_python_binding(string_in="hello",
int_in=12,
double_in=4.0,
mat_req_in=[[1.0]],
col_req_in=[1.0],
matrix_and_info_in=x,
check_input_matrices=True))
def testCheckInputMatricesInf(self):
"""
Checks that an exception is thrown if the input matrix contains
inf values.
"""
x = np.random.rand(100, 5)
a = np.random.randint(low=0, high=100)
b = np.random.randint(low=0, high=5)
x[a][b] = np.inf
self.assertRaises(RuntimeError,
lambda : test_python_binding(string_in="hello",
int_in=12,
double_in=4.0,
mat_req_in=[[1.0]],
col_req_in=[1.0],
matrix_in=x,
check_input_matrices=True))
x_vec = np.random.rand(100)
a = np.random.randint(low=0, high=100)
x_vec[a] = np.inf
self.assertRaises(RuntimeError,
lambda : test_python_binding(string_in="hello",
int_in=12,
double_in=4.0,
mat_req_in=[[1.0]],
col_req_in=[1.0],
row_in=x_vec,
check_input_matrices=True))
self.assertRaises(RuntimeError,
lambda : test_python_binding(string_in="hello",
int_in=12,
double_in=4.0,
mat_req_in=[[1.0]],
col_req_in=[1.0],
col_in=x_vec,
check_input_matrices=True))
self.assertRaises(RuntimeError,
lambda : test_python_binding(string_in="hello",
int_in=12,
double_in=4.0,
mat_req_in=[[1.0]],
col_req_in=[1.0],
matrix_and_info_in=x,
check_input_matrices=True))
if __name__ == '__main__':
unittest.main()
+1
View File
@@ -89,6 +89,7 @@
#include <mlpack/core/dists/gamma_distribution.hpp>
#include <mlpack/core/dists/diagonal_gaussian_distribution.hpp>
#include <mlpack/core/data/confusion_matrix.hpp>
#include <mlpack/core/data/one_hot_encoding.hpp>
// mlpack::backtrace only for linux
#ifdef HAS_BFD_DL
+6 -16
View File
@@ -12,6 +12,8 @@
#ifndef MLPACK_CORE_CV_CV_BASE_IMPL_HPP
#define MLPACK_CORE_CV_CV_BASE_IMPL_HPP
#include <mlpack/prereqs.hpp>
namespace mlpack {
namespace cv {
@@ -106,14 +108,8 @@ void CVBase<MLAlgorithm,
WeightsType>::AssertDataConsistency(const MatType& xs,
const PredictionsType& ys)
{
if (xs.n_cols != ys.n_cols)
{
std::ostringstream oss;
oss << "CVBase::AssertDataConsistency(): number of data points ("
<< xs.n_cols << ") does not match number of predictions (" << ys.n_cols
<< ")!" << std::endl;
throw std::invalid_argument(oss.str());
}
util::CheckSameSizes(xs, (size_t) ys.n_cols, "CVBase::AssertDataConsistency()",
"predictions");
}
template<typename MLAlgorithm,
@@ -129,14 +125,8 @@ void CVBase<MLAlgorithm,
static_assert(MIE::SupportsWeights,
"The given MLAlgorithm does not support weighted learning");
if (weights.n_elem != xs.n_cols)
{
std::ostringstream oss;
oss << "CVBase::AssertWeightsConsistency(): number of weights ("
<< weights.n_elem << ") does not match number of data points ("
<< xs.n_cols << ")!" << std::endl;
throw std::invalid_argument(oss.str());
}
util::CheckSameSizes(xs, weights, "CVBase::AssertWeightsConsistency()",
"weights");
}
template<typename MLAlgorithm,
+1
View File
@@ -13,6 +13,7 @@
#define MLPACK_CORE_CV_METRICS_ACCURACY_HPP
#include <mlpack/core.hpp>
#include <mlpack/prereqs.hpp>
namespace mlpack {
namespace cv {
+1 -3
View File
@@ -12,8 +12,6 @@
#ifndef MLPACK_CORE_CV_METRICS_ACCURACY_IMPL_HPP
#define MLPACK_CORE_CV_METRICS_ACCURACY_IMPL_HPP
#include <mlpack/core/cv/metrics/facilities.hpp>
namespace mlpack {
namespace cv {
@@ -22,7 +20,7 @@ double Accuracy::Evaluate(MLAlgorithm& model,
const DataType& data,
const arma::Row<size_t>& labels)
{
AssertSizes(data, labels, "Accuracy::Evaluate()");
util::CheckSameSizes(data, labels, "Accuracy::Evaluate()");
arma::Row<size_t> predictedLabels;
model.Classify(data, predictedLabels);
+3 -4
View File
@@ -13,7 +13,6 @@
#define MLPACK_CORE_CV_METRICS_F1_IMPL_HPP
#include <mlpack/core/cv/metrics/accuracy.hpp>
#include <mlpack/core/cv/metrics/facilities.hpp>
namespace mlpack {
namespace cv {
@@ -33,7 +32,7 @@ double F1<AS, PC>::Evaluate(MLAlgorithm& model,
const DataType& data,
const arma::Row<size_t>& labels)
{
AssertSizes(data, labels, "F1<Binary>::Evaluate()");
util::CheckSameSizes(data, labels, "F1<Binary>::Evaluate()");
arma::Row<size_t> predictedLabels;
model.Classify(data, predictedLabels);
@@ -56,7 +55,7 @@ double F1<AS, PC>::Evaluate(MLAlgorithm& model,
const DataType& data,
const arma::Row<size_t>& labels)
{
AssertSizes(data, labels, "F1<Micro>::Evaluate()");
util::CheckSameSizes(data, labels, "F1<Micro>::Evaluate()");
// Microaveraged F1 is really the same as microaveraged precision and
// microaveraged recall, which are in turn the same as accuracy.
@@ -70,7 +69,7 @@ double F1<AS, PC>::Evaluate(MLAlgorithm& model,
const DataType& data,
const arma::Row<size_t>& labels)
{
AssertSizes(data, labels, "F1<Macro>::Evaluate()");
util::CheckSameSizes(data, labels, "F1<Macro>::Evaluate()");
arma::Row<size_t> predictedLabels;
model.Classify(data, predictedLabels);
-23
View File
@@ -19,29 +19,6 @@
namespace mlpack {
namespace cv {
/**
* Assert there is the same number of the given data points and labels.
*
* @param data Column-major data.
* @param labels Labels.
* @param callerDescription A description of the caller that can be used for
* error generation.
*/
template<typename DataType>
void AssertSizes(const DataType& data,
const arma::Row<size_t>& labels,
const std::string& callerDescription)
{
if (data.n_cols != labels.n_elem)
{
std::ostringstream oss;
oss << callerDescription << ": number of points (" << data.n_cols << ") "
<< "does not match number of labels (" << labels.n_elem << ")!"
<< std::endl;
throw std::invalid_argument(oss.str());
}
}
/**
* Pairwise distance of the given data.
*
+2 -8
View File
@@ -20,14 +20,8 @@ double MSE::Evaluate(MLAlgorithm& model,
const DataType& data,
const ResponsesType& responses)
{
if (data.n_cols != responses.n_cols)
{
std::ostringstream oss;
oss << "MSE::Evaluate(): number of points (" << data.n_cols << ") "
<< "does not match number of responses (" << responses.n_cols << ")!"
<< std::endl;
throw std::invalid_argument(oss.str());
}
util::CheckSameSizes(data, (size_t) responses.n_cols, "MSE::Evaluate()",
"responses");
ResponsesType predictedResponses;
model.Predict(data, predictedResponses);
@@ -13,7 +13,6 @@
#define MLPACK_CORE_CV_METRICS_PRECISION_IMPL_HPP
#include <mlpack/core/cv/metrics/accuracy.hpp>
#include <mlpack/core/cv/metrics/facilities.hpp>
namespace mlpack {
namespace cv {
@@ -33,7 +32,7 @@ double Precision<AS, PC>::Evaluate(MLAlgorithm& model,
const DataType& data,
const arma::Row<size_t>& labels)
{
AssertSizes(data, labels, "Precision<Binary>::Evaluate()");
util::CheckSameSizes(data, labels, "Precision<Binary>::Evaluate()");
arma::Row<size_t> predictedLabels;
model.Classify(data, predictedLabels);
@@ -51,7 +50,7 @@ double Precision<AS, PC>::Evaluate(MLAlgorithm& model,
const DataType& data,
const arma::Row<size_t>& labels)
{
AssertSizes(data, labels, "Precision<Micro>::Evaluate()");
util::CheckSameSizes(data, labels, "Precision<Micro>::Evaluate()");
// Microaveraged precision turns out to be just accuracy.
return Accuracy::Evaluate(model, data, labels);
@@ -64,7 +63,7 @@ double Precision<AS, PC>::Evaluate(MLAlgorithm& model,
const DataType& data,
const arma::Row<size_t>& labels)
{
AssertSizes(data, labels, "Precision<Macro>::Evaluate()");
util::CheckSameSizes(data, labels, "Precision<Macro>::Evaluate()");
arma::Row<size_t> predictedLabels;
model.Classify(data, predictedLabels);
+2 -8
View File
@@ -21,14 +21,8 @@ double R2Score<AdjustedR2>::Evaluate(MLAlgorithm& model,
const DataType& data,
const ResponsesType& responses)
{
if (data.n_cols != responses.n_cols)
{
std::ostringstream oss;
oss << "R2Score::Evaluate(): number of points (" << data.n_cols << ") "
<< "does not match number of responses (" << responses.n_cols << ")!"
<< std::endl;
throw std::invalid_argument(oss.str());
}
util::CheckSameSizes(data, (size_t) responses.n_cols, "R2Score::Evaluate()",
"responses");
ResponsesType predictedResponses;
// Taking Predicted Output from the model.
+3 -4
View File
@@ -13,7 +13,6 @@
#define MLPACK_CORE_CV_METRICS_RECALL_IMPL_HPP
#include <mlpack/core/cv/metrics/accuracy.hpp>
#include <mlpack/core/cv/metrics/facilities.hpp>
namespace mlpack {
namespace cv {
@@ -33,7 +32,7 @@ double Recall<AS, PC>::Evaluate(MLAlgorithm& model,
const DataType& data,
const arma::Row<size_t>& labels)
{
AssertSizes(data, labels, "Recall<Binary>::Evaluate()");
util::CheckSameSizes(data, labels, "Recall<Binary>::Evaluate()");
arma::Row<size_t> predictedLabels;
model.Classify(data, predictedLabels);
@@ -51,7 +50,7 @@ double Recall<AS, PC>::Evaluate(MLAlgorithm& model,
const DataType& data,
const arma::Row<size_t>& labels)
{
AssertSizes(data, labels, "Recall<Micro>::Evaluate()");
util::CheckSameSizes(data, labels, "Recall<Micro>::Evaluate()");
// Microaveraged recall is really the same as accuracy.
return Accuracy::Evaluate(model, data, labels);
@@ -64,7 +63,7 @@ double Recall<AS, PC>::Evaluate(MLAlgorithm& model,
const DataType& data,
const arma::Row<size_t>& labels)
{
AssertSizes(data, labels, "Recall<Macro>::Evaluate()");
util::CheckSameSizes(data, labels, "Recall<Macro>::Evaluate()");
arma::Row<size_t> predictedLabels;
model.Classify(data, predictedLabels);
@@ -22,7 +22,7 @@ double SilhouetteScore::Overall(const DataType& X,
const arma::Row<size_t>& labels,
const Metric& metric)
{
AssertSizes(X, labels, "SilhouetteScore::Overall()");
util::CheckSameSizes(X, labels, "SilhouetteScore::Overall()");
return arma::mean(SamplesScore(X, labels, metric));
}
@@ -30,7 +30,7 @@ template<typename DataType>
arma::rowvec SilhouetteScore::SamplesScore(const DataType& distances,
const arma::Row<size_t>& labels)
{
AssertSizes(distances, labels, "SilhouetteScore::SamplesScore()");
util::CheckSameSizes(distances, labels, "SilhouetteScore::SamplesScore()");
// Stores the silhouette scores of individual samples.
arma::rowvec sampleScores(distances.n_rows);
@@ -76,7 +76,7 @@ arma::rowvec SilhouetteScore::SamplesScore(const DataType& X,
const arma::Row<size_t>& labels,
const Metric& metric)
{
AssertSizes(X, labels, "SilhouetteScore::SamplesScore()");
util::CheckSameSizes(X, labels, "SilhouetteScore::SamplesScore()");
DataType distances = PairwiseDistances(X, metric);
return SamplesScore(distances, labels);
}
+328 -86
View File
@@ -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
+3
View File
@@ -81,6 +81,9 @@ class BallBound
//! Move constructor: take possession of another bound.
BallBound(BallBound&& other);
//! Move assignment operator.
BallBound& operator=(BallBound&& other);
//! Destructor to release allocated memory.
~BallBound();
+28 -4
View File
@@ -71,10 +71,14 @@ template<typename MetricType, typename VecType>
BallBound<MetricType, VecType>& BallBound<MetricType, VecType>::operator=(
const BallBound& other)
{
radius = other.radius;
center = other.center;
metric = other.metric;
ownsMetric = false;
if (this != &other)
{
radius = other.radius;
center = other.center;
metric = other.metric;
ownsMetric = false;
}
return *this;
}
//! Move constructor.
@@ -92,6 +96,26 @@ BallBound<MetricType, VecType>::BallBound(BallBound&& other) :
other.ownsMetric = false;
}
//! Move assignment operator.
template<typename MetricType, typename VecType>
BallBound<MetricType, VecType>& BallBound<MetricType, VecType>::operator=(
BallBound&& other)
{
if (this != &other)
{
radius = other.radius;
center = std::move(other.center);
metric = other.metric;
ownsMetric = other.ownsMetric;
other.radius = 0.0;
other.center = VecType();
other.metric = nullptr;
other.ownsMetric = false;
}
return *this;
}
//! Destructor to release allocated memory.
template<typename MetricType, typename VecType>
BallBound<MetricType, VecType>::~BallBound()
@@ -86,6 +86,9 @@ class HollowBallBound
//! Move constructor: take possession of another bound.
HollowBallBound(HollowBallBound&& other);
//! Move assignment operator.
HollowBallBound& operator=(HollowBallBound&& other);
//! Destructor to release allocated memory.
~HollowBallBound();
@@ -80,15 +80,17 @@ template<typename TMetricType, typename ElemType>
HollowBallBound<TMetricType, ElemType>& HollowBallBound<TMetricType, ElemType>::
operator=(const HollowBallBound& other)
{
if (ownsMetric)
delete metric;
radii = other.radii;
center = other.center;
hollowCenter = other.hollowCenter;
metric = other.metric;
ownsMetric = false;
if (this != &other)
{
if (ownsMetric)
delete metric;
radii = other.radii;
center = other.center;
hollowCenter = other.hollowCenter;
metric = other.metric;
ownsMetric = false;
}
return *this;
}
@@ -111,6 +113,29 @@ HollowBallBound<TMetricType, ElemType>::HollowBallBound(
other.ownsMetric = false;
}
//! Move assignment operator.
template<typename TMetricType, typename ElemType>
HollowBallBound<TMetricType, ElemType>& HollowBallBound<TMetricType, ElemType>::
operator=(HollowBallBound&& other)
{
if (this != &other)
{
radii = other.radii;
center = std::move(other.center);
hollowCenter = std::move(other.hollowCenter);
metric = other.metric;
ownsMetric = other.ownsMetric;
other.radii.Hi() = 0.0;
other.radii.Lo() = 0.0;
other.center = arma::Col<ElemType>();
other.hollowCenter = arma::Col<ElemType>();
other.metric = nullptr;
other.ownsMetric = false;
}
return *this;
}
//! Destructor to release allocated memory.
template<typename TMetricType, typename ElemType>
HollowBallBound<TMetricType, ElemType>::~HollowBallBound()
+4
View File
@@ -73,12 +73,16 @@ class HRectBound
//! Copy constructor; necessary to prevent memory leaks.
HRectBound(const HRectBound& other);
//! Same as copy constructor; necessary to prevent memory leaks.
HRectBound& operator=(const HRectBound& other);
//! Move constructor: take possession of another bound's information.
HRectBound(HRectBound&& other);
//! Move assignment operator.
HRectBound& operator=(HRectBound&& other);
//! Destructor: clean up memory.
~HRectBound();
+20
View File
@@ -103,6 +103,26 @@ inline HRectBound<MetricType, ElemType>::HRectBound(
other.minWidth = 0.0;
}
/**
* Move assignment operator.
*/
template<typename MetricType, typename ElemType>
inline HRectBound<MetricType, ElemType>&
HRectBound<MetricType, ElemType>::operator=(
HRectBound<MetricType, ElemType>&& other)
{
if (this != &other)
{
bounds = other.bounds;
minWidth = other.minWidth;
dim = other.dim;
other.dim = 0;
other.bounds = nullptr;
other.minWidth = 0.0;
}
return *this;
}
/**
* Destructor: clean up memory.
*/
@@ -177,10 +177,18 @@ class DiscreteHilbertValue
/**
* Copy the local Hilbert value's pointer.
*
* @param val The DiscreteHilbertValue object from which the dataset
* @param other The DiscreteHilbertValue object from which the dataset
* will be copied.
*/
DiscreteHilbertValue& operator=(const DiscreteHilbertValue& val);
DiscreteHilbertValue& operator=(const DiscreteHilbertValue& other);
/**
* Move the local Hilbert object.
*
* @param other The DiscreteHilbertValue object from which the dataset
* will be copied.
*/
DiscreteHilbertValue& operator=(DiscreteHilbertValue&& other);
/**
* Nullify the localHilbertValues pointer in order to prevent an invalid free.
@@ -434,22 +434,43 @@ RemoveNode(TreeType* node, const size_t nodeIndex)
template<typename TreeElemType>
DiscreteHilbertValue<TreeElemType>& DiscreteHilbertValue<TreeElemType>::
operator=(const DiscreteHilbertValue& val)
operator=(const DiscreteHilbertValue& other)
{
if (this == &val)
if (this == &other)
return *this;
if (ownsLocalHilbertValues)
delete localHilbertValues;
localHilbertValues = const_cast<arma::Mat<HilbertElemType>* >
(val.LocalHilbertValues());
(other.LocalHilbertValues());
ownsLocalHilbertValues = false;
numValues = val.NumValues();
numValues = other.NumValues();
return *this;
}
template<typename TreeElemType>
DiscreteHilbertValue<TreeElemType>& DiscreteHilbertValue<TreeElemType>::
operator=(DiscreteHilbertValue&& other)
{
if (this != &other)
{
localHilbertValues = other.localHilbertValues;
ownsLocalHilbertValues = other.ownsLocalHilbertValues;
numValues = other.numValues;
valueToInsert = other.valueToInsert;
ownsValueToInsert = other.ownsValueToInsert;
other.localHilbertValues = nullptr;
other.ownsLocalHilbertValues = false;
other.numValues = 0;
other.valueToInsert = nullptr;
other.ownsValueToInsert = false;
}
return *this;
}
template<typename TreeElemType>
void DiscreteHilbertValue<TreeElemType>::NullifyData()
{
+1
View File
@@ -26,6 +26,7 @@ set(SOURCES
prefixedoutstream_impl.hpp
program_doc.hpp
program_doc.cpp
size_checks.hpp
sfinae_utility.hpp
singletons.cpp
timers.hpp
+29
View File
@@ -267,3 +267,32 @@ void IO::ClearSettings()
GetSingleton().aliases = persistentAliases;
GetSingleton().functionMap = persistentFunctions;
}
void IO::CheckInputMatrices()
{
typedef typename std::tuple<data::DatasetInfo, arma::mat> TupleType;
std::map<std::string, util::ParamData>::iterator itr;
for (itr = IO::Parameters().begin(); itr != IO::Parameters().end(); ++itr)
{
std::string paramName = itr->first;
std::string paramType = itr->second.cppType;
if (paramType == "arma::mat")
{
IO::CheckInputMatrix(IO::GetParam<arma::mat>(paramName), paramName);
}
else if (paramType == "arma::vec")
{
IO::CheckInputMatrix(IO::GetParam<arma::vec>(paramName), paramName);
}
else if (paramType == "arma::rowvec")
{
IO::CheckInputMatrix(IO::GetParam<arma::rowvec>(paramName), paramName);
}
else if (paramType == "std::tuple<mlpack::data::DatasetInfo, arma::mat>")
{
IO::CheckInputMatrix(
std::get<1>(IO::GetParam<TupleType>(paramName)), paramName);
}
}
}
+14
View File
@@ -219,6 +219,15 @@ class IO
template<typename T>
static T& GetRawParam(const std::string& identifier);
/**
* Utility function for CheckInputMatrices().
*
* @param matrix Matrix to check.
* @param identifier Name of the parameter in question.
*/
template<typename T>
static void CheckInputMatrix(const T& matrix, const std::string& identifier);
/**
* Given two (matrix) parameters, ensure that the first is an in-place copy of
* the second. This will generally do nothing (as the bindings already do
@@ -285,6 +294,11 @@ class IO
*/
static void ClearSettings();
/**
* Checks all input matrices for NaN and inf values, exits if found any.
*/
static void CheckInputMatrices();
private:
//! Convenience map from alias values to names.
std::map<char, std::string> aliases;
+12
View File
@@ -145,6 +145,18 @@ T& IO::GetRawParam(const std::string& identifier)
}
}
template<typename T>
void IO::CheckInputMatrix(const T& matrix, const std::string& identifier)
{
std::string errMsg1 = "The input " + identifier + " has NaN values.";
std::string errMsg2 = "The input " + identifier + " has inf values.";
if (matrix.has_nan())
Log::Fatal << errMsg1 << std::endl;
if (matrix.has_inf())
Log::Fatal << errMsg2 << std::endl;
}
} // namespace mlpack
#endif
+2
View File
@@ -230,6 +230,8 @@ PARAM_FLAG("copy_all_inputs", "If specified, all input parameters will be deep"
" copied before the method is run. This is useful for debugging problems "
"where the input parameters are being modified by the algorithm, but can "
"slow down the code.", "");
PARAM_FLAG("check_input_matrices", "If specified, the input matrix is checked for"
" NaN and inf values; an exception is thrown if any are found.", "");
// Nothing else needs to be defined---the binding will use mlpackMain() as-is.
+45 -92
View File
@@ -1015,7 +1015,9 @@ using DatasetInfo = DatasetMapper<IncrementPolicy, std::string>;
*/
#define TUPLE_TYPE std::tuple<mlpack::data::DatasetInfo, arma::mat>
#define PARAM_MATRIX_AND_INFO_IN(ID, DESC, ALIAS) \
PARAM_IN(TUPLE_TYPE, ID, DESC, ALIAS, TUPLE_TYPE(), false)
PARAM(TUPLE_TYPE, ID, DESC, ALIAS, \
"std::tuple<mlpack::data::DatasetInfo, arma::mat>", false, true, true, \
TUPLE_TYPE())
/**
* Define an input model. From the command line, the user can specify the file
@@ -1207,11 +1209,44 @@ using DatasetInfo = DatasetMapper<IncrementPolicy, std::string>;
PARAM_IN(std::vector<T>, ID, DESC, ALIAS, std::vector<T>(), true);
/**
* Define an input parameter. Don't use this function; use the other ones above
* that call it. Note that we are using the __LINE__ macro for naming these
* actual parameters when __COUNTER__ does not exist, which is a bit of an ugly
* hack... but this is the preprocessor, after all. We don't have much choice
* other than ugliness.
* Defining useful macros using PARAM macro defined later.
*/
#define PARAM_IN(T, ID, DESC, ALIAS, DEF, REQ) \
PARAM(T, ID, DESC, ALIAS, #T, REQ, true, false, DEF);
#define PARAM_OUT(T, ID, DESC, ALIAS, DEF, REQ) \
PARAM(T, ID, DESC, ALIAS, #T, REQ, false, false, DEF);
#define PARAM_MATRIX(ID, DESC, ALIAS, REQ, TRANS, IN) \
PARAM(arma::mat, ID, DESC, ALIAS, "arma::mat", REQ, IN, \
TRANS, arma::mat());
#define PARAM_UMATRIX(ID, DESC, ALIAS, REQ, TRANS, IN) \
PARAM(arma::Mat<size_t>, ID, DESC, ALIAS, "arma::Mat<size_t>", \
REQ, IN, TRANS, arma::Mat<size_t>());
#define PARAM_COL(ID, DESC, ALIAS, REQ, TRANS, IN) \
PARAM(arma::vec, ID, DESC, ALIAS, "arma::vec", REQ, IN, TRANS, \
arma::vec());
#define PARAM_UCOL(ID, DESC, ALIAS, REQ, TRANS, IN) \
PARAM(arma::Col<size_t>, ID, DESC, ALIAS, "arma::Col<size_t>", \
REQ, IN, TRANS, arma::Col<size_t>());
#define PARAM_ROW(ID, DESC, ALIAS, REQ, TRANS, IN) \
PARAM(arma::rowvec, ID, DESC, ALIAS, "arma::rowvec", REQ, IN, \
TRANS, arma::rowvec());
#define PARAM_UROW(ID, DESC, ALIAS, REQ, TRANS, IN) \
PARAM(arma::Row<size_t>, ID, DESC, ALIAS, "arma::Row<size_t>", \
REQ, IN, TRANS, arma::Row<size_t>());
/**
* Define the PARAM(), PARAM_MODEL() macro. Don't use this function;
* use the other ones above that call it. Note that we are using the __LINE__
* macro for naming these actual parameters when __COUNTER__ does not exist,
* which is a bit of an ugly hack... but this is the preprocessor, after all.
* We don't have much choice other than ugliness.
*
* @param T Type of the parameter.
* @param ID Name of the parameter.
@@ -1223,51 +1258,10 @@ using DatasetInfo = DatasetMapper<IncrementPolicy, std::string>;
* @param REQ Whether or not parameter is required (boolean value).
*/
#ifdef __COUNTER__
#define PARAM_IN(T, ID, DESC, ALIAS, DEF, REQ) \
#define PARAM(T, ID, DESC, ALIAS, NAME, REQ, IN, TRANS, DEF) \
static mlpack::util::Option<T> \
JOIN(io_option_dummy_object_in_, __COUNTER__) \
(DEF, ID, DESC, ALIAS, #T, REQ, true, false, testName);
#define PARAM_OUT(T, ID, DESC, ALIAS, DEF, REQ) \
static mlpack::util::Option<T> \
JOIN(io_option_dummy_object_out_, __COUNTER__) \
(DEF, ID, DESC, ALIAS, #T, REQ, false, false, testName);
#define PARAM_MATRIX(ID, DESC, ALIAS, REQ, TRANS, IN) \
static mlpack::util::Option<arma::mat> \
JOIN(io_option_dummy_matrix_, __COUNTER__) \
(arma::mat(), ID, DESC, ALIAS, "arma::mat", \
REQ, IN, !TRANS, testName);
#define PARAM_UMATRIX(ID, DESC, ALIAS, REQ, TRANS, IN) \
static mlpack::util::Option<arma::Mat<size_t>> \
JOIN(io_option_dummy_umatrix_, __COUNTER__) \
(arma::Mat<size_t>(), ID, DESC, ALIAS, "arma::Mat<size_t>", \
REQ, IN, !TRANS, testName);
#define PARAM_COL(ID, DESC, ALIAS, REQ, TRANS, IN) \
static mlpack::util::Option<arma::vec> \
JOIN(io_option_dummy_col_, __COUNTER__) \
(arma::vec(), ID, DESC, ALIAS, "arma::vec", \
REQ, IN, !TRANS, testName);
#define PARAM_UCOL(ID, DESC, ALIAS, REQ, TRANS, IN) \
static mlpack::util::Option<arma::Col<size_t>> \
JOIN(io_option_dummy_ucol_, __COUNTER__) \
(arma::Col<size_t>(), ID, DESC, ALIAS, "arma::Col<size_t>", \
REQ, IN, !TRANS, testName);
#define PARAM_ROW(ID, DESC, ALIAS, REQ, TRANS, IN) \
static mlpack::util::Option<arma::rowvec> \
JOIN(io_option_dummy_row_, __COUNTER__) \
(arma::rowvec(), ID, DESC, ALIAS, "arma::rowvec", \
REQ, IN, !TRANS, testName);
#define PARAM_UROW(ID, DESC, ALIAS, REQ, TRANS, IN) \
static mlpack::util::Option<arma::Row<size_t>> \
JOIN(io_option_dummy_urow_, __COUNTER__) \
(arma::Row<size_t>(), ID, DESC, ALIAS, "arma::Row<size_t>", \
REQ, IN, !TRANS, testName);
(DEF, ID, DESC, ALIAS, NAME, REQ, IN, !TRANS, testName);
// There are no uses of required models, so that is not an option to this
// macro (it would be easy to add).
@@ -1280,51 +1274,10 @@ using DatasetInfo = DatasetMapper<IncrementPolicy, std::string>;
// don't think we can absolutely guarantee success, but it should be "good
// enough". We use the __LINE__ macro and the type of the parameter to try
// and get a good guess at something unique.
#define PARAM_IN(T, ID, DESC, ALIAS, DEF, REQ) \
#define PARAM(T, ID, DESC, ALIAS, NAME, REQ, IN, TRANS, DEF) \
static mlpack::util::Option<T> \
JOIN(JOIN(io_option_dummy_object_in_, __LINE__), opt) \
(DEF, ID, DESC, ALIAS, #T, REQ, true, false, testName);
#define PARAM_OUT(T, ID, DESC, ALIAS, DEF, REQ) \
static mlpack::util::Option<T> \
JOIN(JOIN(io_option_dummy_object_out_, __LINE__), opt) \
(DEF, ID, DESC, ALIAS, #T, REQ, false, false, testName);
#define PARAM_MATRIX(ID, DESC, ALIAS, REQ, TRANS, IN) \
static mlpack::util::Option<arma::mat> \
JOIN(JOIN(io_option_dummy_object_matrix_, __LINE__), opt) \
(arma::mat(), ID, DESC, ALIAS, "arma::mat", REQ, IN, !TRANS, \
testName);
#define PARAM_UMATRIX(ID, DESC, ALIAS, REQ, TRANS, IN) \
static mlpack::util::Option<arma::Mat<size_t>> \
JOIN(JOIN(io_option_dummy_object_umatrix_, __LINE__), opt) \
(arma::Mat<size_t>(), ID, DESC, ALIAS, "arma::Mat<size_t>", REQ, IN, \
!TRANS, testName);
#define PARAM_COL(ID, DESC, ALIAS, REQ, TRANS, IN) \
static mlpack::util::Option<arma::vec> \
JOIN(io_option_dummy_object_col_, __LINE__) \
(arma::vec(), ID, DESC, ALIAS, "arma::vec", REQ, IN, !TRANS, \
testName);
#define PARAM_UCOL(ID, DESC, ALIAS, REQ, TRANS, IN) \
static mlpack::util::Option<arma::Col<size_t>> \
JOIN(io_option_dummy_object_ucol_, __LINE__) \
(arma::Col<size_t>(), ID, DESC, ALIAS, "arma::Col<size_t>", REQ, IN, \
!TRANS, testName);
#define PARAM_ROW(ID, DESC, ALIAS, REQ, TRANS, IN) \
static mlpack::util::Option<arma::rowvec> \
JOIN(io_option_dummy_object_row_, __LINE__) \
(arma::rowvec(), ID, DESC, ALIAS, "arma::rowvec", REQ, IN, !TRANS, \
testName);
#define PARAM_UROW(ID, DESC, ALIAS, REQ, TRANS, IN) \
static mlpack::util::Option<arma::Row<size_t>> \
JOIN(io_option_dummy_object_urow_, __LINE__) \
(arma::Row<size_t>(), ID, DESC, ALIAS, "arma::Row<size_t>", REQ, IN, \
!TRANS, testName);
(DEF, ID, DESC, ALIAS, NAME, REQ, IN, !TRANS, testName);
#define PARAM_MODEL(TYPE, ID, DESC, ALIAS, REQ, IN) \
static mlpack::util::Option<TYPE*> \
+4 -1
View File
@@ -43,11 +43,14 @@ namespace util {
* @param fatal If true, output goes to Log::Fatal instead of Log::Warn and an
* exception is thrown.
* @param customErrorMessage Error message to append.
* @param allowNone If true, then no error message will be thrown if none of the
* parameters in the constraints were passed.
*/
void RequireOnlyOnePassed(
const std::vector<std::string>& constraints,
const bool fatal = true,
const std::string& customErrorMessage = "");
const std::string& customErrorMessage = "",
const bool allowNone = false);
/**
* Require that at least one of the given parameters in the constraints set was
+3 -2
View File
@@ -21,7 +21,8 @@ namespace util {
inline void RequireOnlyOnePassed(
const std::vector<std::string>& constraints,
const bool fatal,
const std::string& errorMessage)
const std::string& errorMessage,
const bool allowNone)
{
if (BINDING_IGNORE_CHECK(constraints))
return;
@@ -57,7 +58,7 @@ inline void RequireOnlyOnePassed(
stream << "; " << errorMessage;
stream << "!" << std::endl;
}
else if (set == 0)
else if (set == 0 && !allowNone)
{
stream << (fatal ? "Must " : "Should ");
@@ -178,8 +178,7 @@ PrefixedOutStream::BaseLogic(const T& val)
if (maxVal == 0.0)
maxVal = 1;
int maxLog = log10(maxVal);
maxLog = (maxLog > 0) ? floor(maxLog) + 1 : 1;
const int maxLog = int(log10(maxVal)) + 1;
const int padding = 4;
convert.width(convert.precision() + maxLog + padding);
printVal.raw_print(convert);
+117
View File
@@ -0,0 +1,117 @@
/**
* @file size_checks.hpp
* @author Kirill Mishchenko
* @author Bisakh Mondal
*
* Utility for checking same size & same dimensionality.
*
* 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_UTIL_SIZE_CHECKS_HPP
#define MLPACK_UTIL_SIZE_CHECKS_HPP
namespace mlpack {
namespace util {
/**
* Check for if the given data points & labels have same size.
*
* @param data data.
* @param labels Labels.
* @param callerDescription A description of the caller that can be used for
* error generation.
* @param addInfo Name to use for labels for precise error generation. Default
* is "labels"; for example, "weights" could also be used.
*/
template<typename DataType, typename LabelsType>
inline void CheckSameSizes(const DataType& data,
const LabelsType& label,
const std::string& callerDescription,
const std::string& addInfo = "labels")
{
if (data.n_cols != label.n_elem)
{
std::ostringstream oss;
oss << callerDescription << ": number of points (" << data.n_cols << ") "
<< "does not match number of " << addInfo << " (" << label.n_elem << ")!"
<< std::endl;
throw std::invalid_argument(oss.str());
}
}
/**
* An overload of CheckSameSizes() where the size to be checked is known
* previously. The second parameter is of type unsigned int.
*/
template<typename DataType>
inline void CheckSameSizes(const DataType& data,
const size_t& size,
const std::string& callerDescription,
const std::string& addInfo = "labels")
{
if (data.n_cols != size)
{
std::ostringstream oss;
oss << callerDescription << ": number of points (" << data.n_cols << ") "
<< "does not match number of " << addInfo << " (" << size << ")!"
<< std::endl;
throw std::invalid_argument(oss.str());
}
}
/**
* Check for if the given dataset dimension matches with the model's.
*
* @param data dataset.
* @param dimension Dimension of the model.
* @param callerDescription A description of the caller that can be used for
* error generation.
* @param addInfo Name to use for dataset for precise error generation. Default
* is "dataset"; for example, "weights" could also be used.
*/
template<typename DataType, typename DimType>
inline void CheckSameDimensionality(const DataType& data,
const DimType& dimension,
const std::string& callerDescription,
const std::string& addInfo = "dataset")
{
if (data.n_rows != dimension.n_rows)
{
std::ostringstream oss;
oss << callerDescription << ": dimensionality of " << addInfo << " ("
<< data.n_rows << ") is not equal to the dimensionality of the model"
" (" << dimension.n_rows << ")!";
throw std::invalid_argument(oss.str());
}
}
/**
* An overload of CheckSameDimensionality() where the dimension to be checked
* is known second param is unsigned long int.
*/
template<typename DataType>
inline void CheckSameDimensionality(const DataType& data,
const size_t& dimension,
const std::string& callerDescription,
const std::string& addInfo = "dataset")
{
if (data.n_rows != dimension)
{
std::ostringstream oss;
oss << callerDescription << ": dimensionality of " << addInfo << " ("
<< data.n_rows << ") is not equal to the dimensionality of the model"
" (" << dimension << ")!";
throw std::invalid_argument(oss.str());
}
}
} // namespace util
} // namespace mlpack
#endif
+4 -3
View File
@@ -19,12 +19,13 @@ namespace util {
* Convert a string to lowercase letters.
*
* @param input The string to convert.
* @param output The string to be converted.
*/
inline void ToLower(const std::string& input, std::string& output)
inline std::string ToLower(const std::string& input)
{
std::transform(input.begin(), input.end(), output.begin(),
std::string output;
std::transform(input.begin(), input.end(), std::back_inserter(output),
[](unsigned char c){ return std::tolower(c); });
return output;
}
} // namespace util
+30 -9
View File
@@ -72,19 +72,40 @@ AdaBoostModel::AdaBoostModel(AdaBoostModel&& other) :
//! Copy assignment operator.
AdaBoostModel& AdaBoostModel::operator=(const AdaBoostModel& other)
{
mappings = other.mappings;
weakLearnerType = other.weakLearnerType;
if (this != &other)
{
mappings = other.mappings;
weakLearnerType = other.weakLearnerType;
delete dsBoost;
dsBoost = (other.dsBoost == NULL) ? NULL :
new AdaBoost<ID3DecisionStump>(*other.dsBoost);
delete dsBoost;
dsBoost = (other.dsBoost == NULL) ? NULL :
new AdaBoost<ID3DecisionStump>(*other.dsBoost);
delete pBoost;
pBoost = (other.pBoost == NULL) ? NULL :
new AdaBoost<Perceptron<>>(*other.pBoost);
delete pBoost;
pBoost = (other.pBoost == NULL) ? NULL :
new AdaBoost<Perceptron<>>(*other.pBoost);
dimensionality = other.dimensionality;
dimensionality = other.dimensionality;
}
return *this;
}
//! Move assignment operator.
AdaBoostModel& AdaBoostModel::operator=(AdaBoostModel&& other)
{
if (this != &other)
{
mappings = std::move(other.mappings);
weakLearnerType = other.weakLearnerType;
dsBoost = other.dsBoost;
other.dsBoost = nullptr;
pBoost = other.pBoost;
other.pBoost = nullptr;
dimensionality = other.dimensionality;
}
return *this;
}
@@ -61,6 +61,9 @@ class AdaBoostModel
//! Copy assignment operator.
AdaBoostModel& operator=(const AdaBoostModel& other);
//! Move assignment operator.
AdaBoostModel& operator=(AdaBoostModel&& other);
//! Clean up memory.
~AdaBoostModel();
@@ -36,7 +36,8 @@ class CompleteIncrementalTermination
*/
CompleteIncrementalTermination(
TerminationPolicy tPolicy = TerminationPolicy()) :
tPolicy(tPolicy) { }
tPolicy(tPolicy), incrementalIndex(0), iteration(0)
{ /* Nothing to do here. */ }
/**
* Initializes the termination policy before stating the factorization.
@@ -119,4 +120,3 @@ class CompleteIncrementalTermination
} // namespace mlpack
#endif // MLPACK_METHODS_AMF_COMPLETE_INCREMENTAL_TERMINATION_HPP
@@ -35,7 +35,8 @@ class IncompleteIncrementalTermination
*/
IncompleteIncrementalTermination(
TerminationPolicy tPolicy = TerminationPolicy()) :
tPolicy(tPolicy) { }
tPolicy(tPolicy), incrementalIndex(0), iteration(0)
{ /* Nothing to do here. */ }
/**
* Initializes the termination policy before stating the factorization.
@@ -40,8 +40,16 @@ class SimpleResidueTermination
* @param maxIterations Maximum number of iterations.
*/
SimpleResidueTermination(const double minResidue = 1e-5,
const size_t maxIterations = 10000)
: minResidue(minResidue), maxIterations(maxIterations) { }
const size_t maxIterations = 10000) :
minResidue(minResidue),
maxIterations(maxIterations),
residue(0.0),
iteration(0),
normOld(0),
nm(0)
{
// Nothing to do here.
}
/**
* Initializes the termination policy before stating the factorization.
@@ -56,7 +56,7 @@ class SVDCompleteIncrementalLearning
SVDCompleteIncrementalLearning(double u = 0.0001,
double kw = 0,
double kh = 0)
: u(u), kw(kw), kh(kh)
: u(u), kw(kw), kh(kh), currentUserIndex(0), currentItemIndex(0)
{
// Nothing to do.
}
@@ -172,7 +172,7 @@ class SVDCompleteIncrementalLearning<arma::sp_mat>
SVDCompleteIncrementalLearning(double u = 0.01,
double kw = 0,
double kh = 0)
: u(u), kw(kw), kh(kh), it(NULL)
: u(u), kw(kw), kh(kh), n(0), m(0), it(NULL), isStart(false)
{}
~SVDCompleteIncrementalLearning()
@@ -53,7 +53,7 @@ class SVDIncompleteIncrementalLearning
SVDIncompleteIncrementalLearning(double u = 0.001,
double kw = 0,
double kh = 0)
: u(u), kw(kw), kh(kh)
: u(u), kw(kw), kh(kh), currentUserIndex(0)
{
// Nothing to do.
}
@@ -19,6 +19,7 @@ set(SOURCES
multi_quadratic_function.hpp
poisson1_function.hpp
gaussian_function.hpp
hard_swish_function.hpp
)
# Add directory name to sources.
@@ -0,0 +1,116 @@
/**
* @file methods/ann/activation_functions/hard_swish_function.hpp
* @author Anush Kini
*
* Definition and implementation of the Hard Swish function as described by
* Howard A, Sandler M, Chu G, Chen LC, Chen B, Tan M, Wang W, Zhu Y, Pang R,
* Vasudevan V and Le QV.
* For more information, see the following paper.
*
* @code
* @misc{
* author = {Howard A, Sandler M, Chu G, Chen LC, Chen B, Tan M, Wang W,
* Zhu Y, Pang R, Vasudevan V and Le QV},
* title = {Searching for MobileNetV3},
* year = {2019}
* }
* @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_HARD_SWISH_FUNCTION_HPP
#define MLPACK_METHODS_ANN_ACTIVATION_FUNCTIONS_HARD_SWISH_FUNCTION_HPP
#include <mlpack/prereqs.hpp>
namespace mlpack {
namespace ann /** Artificial Neural Network. */ {
/**
* The Hard Swish function, defined by
*
* @f{eqnarray*}{
* f(x) &=& \begin{cases}
* 0 & x \leq -3\\
* x & x \geq +3\\
* \frac{x * (x + 3)}{6} & otherwise\\
* \end{cases} \\
* f'(x) &=& \begin{cases}
* 0 & x \leq -3\\
* 1 & x \geq +3\\
* \frac{2x + 3}{6} & otherwise\\
* \end{cases}
* @f}
*/
class HardSwishFunction
{
public:
/**
* Computes the Hard Swish function.
*
* @param x Input data.
* @return f(x).
*/
static double Fn(const double x)
{
if (x <= -3)
return 0;
else if (x >= 3)
return x;
return x * (x + 3) / 6;
}
/**
* Computes the Hard Swish 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.set_size(size(x));
for (size_t i = 0; i < x.n_elem; i++)
y(i) = Fn(x(i));
}
/**
* Computes the first derivative of the Hard Swish function.
*
* @param y Input data.
* @return f'(x).
*/
static double Deriv(const double y)
{
if (y <= -3)
return 0;
else if (y >= 3)
return 1;
return (2 * y + 3.0) / 6.0;
}
/**
* Computes the first derivatives of the Hard Swish function.
*
* @param y Input data.
* @param x The resulting derivatives.
*/
template <typename InputVecType, typename OutputVecType>
static void Deriv(const InputVecType &y, OutputVecType &x)
{
x.set_size(size(y));
for (size_t i = 0; i < y.n_elem; i++)
x(i) = Deriv(y(i));
}
}; // class HardSwishFunction
} // namespace ann
} // namespace mlpack
#endif
@@ -46,6 +46,8 @@ set(SOURCES
hard_tanh_impl.hpp
highway.hpp
highway_impl.hpp
isrlu.hpp
isrlu_impl.hpp
join.hpp
join_impl.hpp
layer.hpp
@@ -63,6 +65,8 @@ set(SOURCES
log_softmax_impl.hpp
lookup.hpp
lookup_impl.hpp
lp_pooling.hpp
lp_pooling_impl.hpp
lstm.hpp
lstm_impl.hpp
max_pooling.hpp
@@ -81,6 +85,8 @@ set(SOURCES
noisylinear_impl.hpp
parametric_relu.hpp
parametric_relu_impl.hpp
pixel_shuffle.hpp
pixel_shuffle_impl.hpp
positional_encoding.hpp
positional_encoding_impl.hpp
recurrent.hpp
@@ -125,8 +125,7 @@ AtrousConvolution<
weights.set_size(WeightSize(), 1);
// Transform paddingType to lowercase.
std::string paddingTypeLow = paddingType;
util::ToLower(paddingType, paddingTypeLow);
const std::string paddingTypeLow = util::ToLower(paddingType);
size_t padWLeft = std::get<0>(padW);
size_t padWRight = std::get<1>(padW);
@@ -27,6 +27,7 @@
#include <mlpack/methods/ann/activation_functions/elliot_function.hpp>
#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>
namespace mlpack {
namespace ann /** Artificial Neural Network. */ {
@@ -50,6 +51,7 @@ namespace ann /** Artificial Neural Network. */ {
* - ELiSHLayer
* - ElliotLayer
* - GaussianLayer
* - HardSwishLayer
*
* @tparam ActivationFunction Activation function used for the embedding layer.
* @tparam InputDataType Type of the input data (arma::colvec, arma::mat,
@@ -277,6 +279,17 @@ template <
using GaussianFunctionLayer = BaseLayer<
ActivationFunction, InputDataType, OutputDataType>;
/**
* Standard HardSwish-Layer using the HardSwish activation function.
*/
template <
class ActivationFunction = HardSwishFunction,
typename InputDataType = arma::mat,
typename OutputDataType = arma::mat
>
using HardSwishFunctionLayer = 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.
*/
@@ -29,6 +29,35 @@ namespace ann /** Artificial Neural Network. */ {
/**
* Implementation of the Convolution class. The Convolution class represents a
* single layer of a neural network.
* Example usage:
*
* Suppose we want to pass a matrix M (2744x100) to a `Convolution` layer;
* in this example, `M` was obtained from "flattening" 100 images (or Mel
* cepstral coefficients, if we talk about speech, or whatever you like) of
* dimension 196x14. In other words, the first 196 columns of each row of M
* will be made of the 196 columns of the first row of each of the 100 images
* (or Mel cepstral coefficients). Then the next 295 columns of M (196 - 393)
* will be made of the 196 columns of the second row of the 100 images (or Mel
* cepstral coefficients), etc. Given that the size of our 2-D input images is
* 196x14, the parameters for our `Convolution` layer will be something like
* this:
*
* ```
* Convolution<> c(1, // Number of input activation maps.
* 14, // Number of output activation maps.
* 3, // Filter width.
* 3, // Filter height.
* 1, // Stride along width.
* 1, // Stride along height.
* 0, // Padding width.
* 0, // Padding height.
* 196, // Input width.
* 14); // Input height.
* ```
*
* This `Convolution<>` layer will treat each column of the input matrix `M` as
* a 2-D image (or object) of the original 196x14 size, using this as the input
* for the 14 filters of this example.
*
* @tparam ForwardConvolutionRule Convolution to perform forward process.
* @tparam BackwardConvolutionRule Convolution to perform backward process.
@@ -120,8 +120,7 @@ Convolution<
weights.set_size(WeightSize(), 1);
// Transform paddingType to lowercase.
std::string paddingTypeLow = paddingType;
util::ToLower(paddingType, paddingTypeLow);
const std::string paddingTypeLow = util::ToLower(paddingType);
if (paddingTypeLow == "valid")
{
+13 -26
View File
@@ -163,33 +163,20 @@ void FastLSTM<InputDataType, OutputDataType>::ResetCell(const size_t size)
gradientStep = batchSize * size - 1;
const size_t rhoBatchSize = size * batchSize;
if (gate.is_empty() || gate.n_cols != rhoBatchSize)
{
gate.set_size(4 * outSize, rhoBatchSize);
gateActivation.set_size(outSize * 3, rhoBatchSize);
stateActivation.set_size(outSize, rhoBatchSize);
cellActivation.set_size(outSize, rhoBatchSize);
prevError.set_size(4 * outSize, batchSize);
if (prevOutput.is_empty())
{
prevOutput = arma::zeros<OutputDataType>(outSize, batchSize);
cell = arma::zeros(outSize, size * batchSize);
cellActivationError = arma::zeros<OutputDataType>(outSize, batchSize);
outParameter = arma::zeros<OutputDataType>(
outSize, (size + 1) * batchSize);
}
else
{
// To preserve the leading zeros, recreate the object according to given
// size specifications, while preserving the elements as well as the
// layout of the elements.
prevOutput.resize(outSize, batchSize);
cell.resize(outSize, size * batchSize);
cellActivationError.resize(outSize, batchSize);
outParameter.resize(outSize, (size + 1) * batchSize);
}
}
// Make sure all of the matrices we use to store state are at least as large
// as we need.
gate.set_size(4 * outSize, rhoBatchSize);
gateActivation.set_size(outSize * 3, rhoBatchSize);
stateActivation.set_size(outSize, rhoBatchSize);
cellActivation.set_size(outSize, rhoBatchSize);
prevError.set_size(4 * outSize, batchSize);
// Reset stored state to zeros.
prevOutput.zeros(outSize, batchSize);
cell.zeros(outSize, size * batchSize);
cellActivationError.zeros(outSize, batchSize);
outParameter.zeros(outSize, (size + 1) * batchSize);
}
template<typename InputDataType, typename OutputDataType>
+138
View File
@@ -0,0 +1,138 @@
/**
* @file methods/ann/layer/isrlu.hpp
* @author Abhinav Anand
*
* Definition of the ISRLU activation function as described by Jonathan T. Barron.
*
* For more information, read the following paper.
*
* @code
* @article{
* author = {Carlile, Brad and Delamarter, Guy and Kinney, Paul and Marti,
* Akiko and Whitney, Brian},
* title = {Improving deep learning by inverse square root linear units (ISRLUs)},
* year = {2017},
* url = {https://arxiv.org/pdf/1710.09967.pdf}
* }
* @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_LAYER_ISRLU_HPP
#define MLPACK_METHODS_ANN_LAYER_ISRLU_HPP
#include <mlpack/prereqs.hpp>
namespace mlpack {
namespace ann /** Artificial Neural Network. */ {
/**
* The ISRLU activation function, defined by
*
* @f{eqnarray*}{
* f(x) &=& \left\{
* \begin{array}{lr}
* x & : x \ge 0 \\
* x(\frac{1}{1 + \alpha x^2}) & : x < 0
* \end{array}
* \right. \\
* f'(x) &=& \left\{
* \begin{array}{lr}
* x & : 1 \ge 0 \\
* (\frac{1}{1 + \alpha x^2})^3 & : x < 0
* \end{array}
* \right.
* @f}
*
*
* @tparam InputDataType Type of the input data (arma::colvec, arma::mat,
* arma::sp_mat or arma::cube).
* @tparam OutputDataType Type of the output data (arma::colvec, arma::mat,
* arma::sp_mat or arma::cube).
*/
template <
typename InputDataType = arma::mat,
typename OutputDataType = arma::mat
>
class ISRLU
{
public:
/**
* Create the ISRLU object using the specified parameter.
*
* @param alpha Scale parameter controls the value to which an ISRLU
* saturates for negative inputs.
*/
ISRLU(const double alpha = 1.0);
/**
* Ordinary feed forward pass of a neural network, evaluating the function
* f(x) by propagating the activity forward through f.
*
* @param input Input data used for evaluating the specified function.
* @param output Resulting output activation.
*/
template<typename InputType, typename OutputType>
void Forward(const InputType& input, OutputType& output);
/**
* Ordinary feed backward pass of a neural network, calculating the function
* f(x) by propagating x backwards through f. Using the results from the feed
* forward pass.
*
* @param input The propagated input activation f(x).
* @param gy The backpropagated error.
* @param g The calculated gradient.
*/
template<typename DataType>
void Backward(const DataType& input, const DataType& gy, DataType& g);
//! Get the output parameter.
OutputDataType const& OutputParameter() const { return outputParameter; }
//! Modify the output parameter.
OutputDataType& OutputParameter() { return outputParameter; }
//! Get the delta.
OutputDataType const& Delta() const { return delta; }
//! Modify the delta.
OutputDataType& Delta() { return delta; }
//! Get the non zero gradient.
double const& Alpha() const { return alpha; }
//! Modify the non zero gradient.
double& Alpha() { return alpha; }
//! Get size of weights.
size_t WeightSize() { return 0; }
/**
* Serialize the layer.
*/
template<typename Archive>
void serialize(Archive& ar, const uint32_t /* version */);
private:
//! Locally-stored delta object.
OutputDataType delta;
//! Locally-stored output parameter object.
OutputDataType outputParameter;
//! Locally stored first derivative of the activation function.
arma::mat derivative;
//! ISRLU Hyperparameter (alpha > 0).
double alpha;
}; // class ISRLU
} // namespace ann
} // namespace mlpack
// Include implementation.
#include "isrlu_impl.hpp"
#endif
@@ -0,0 +1,65 @@
/**
* @file methods/ann/layer/isrlu_impl.hpp
* @author Abhinav Anand
*
* Implementation of the ISRLU activation function as described by Jonathan T. Barron.
*
* 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_LAYER_ISRLU_IMPL_HPP
#define MLPACK_METHODS_ANN_LAYER_ISRLU_IMPL_HPP
// In case it hasn't yet been included.
#include "isrlu.hpp"
namespace mlpack {
namespace ann /** Artificial Neural Network. */ {
template<typename InputDataType, typename OutputDataType>
ISRLU<InputDataType, OutputDataType>::ISRLU(const double alpha) :
alpha(alpha)
{}
template<typename InputDataType, typename OutputDataType>
template<typename InputType, typename OutputType>
void ISRLU<InputDataType, OutputDataType>::Forward(
const InputType& input, OutputType& output)
{
output = arma::ones<OutputDataType>(arma::size(input));
for (size_t i = 0; i < input.n_elem; ++i)
{
output(i) = (input(i) >= 0) ? input(i) : input(i) *
(1 / std::sqrt(1 + alpha * (input(i) * input(i))));
}
}
template<typename InputDataType, typename OutputDataType>
template<typename DataType>
void ISRLU<InputDataType, OutputDataType>::Backward(
const DataType& input, const DataType& gy, DataType& g)
{
derivative.set_size(arma::size(input));
for (size_t i = 0; i < input.n_elem; ++i)
{
derivative(i) = (input(i) >= 0) ? 1 :
std::pow(1 / std::sqrt(1 + alpha * input(i) * input(i)), 3);
}
g = gy % derivative;
}
template<typename InputDataType, typename OutputDataType>
template<typename Archive>
void ISRLU<InputDataType, OutputDataType>::serialize(
Archive& ar,
const uint32_t /* version */)
{
ar(CEREAL_NVP(alpha));
}
} // namespace ann
} // namespace mlpack
#endif
+2
View File
@@ -47,6 +47,7 @@
#include "linear3d.hpp"
#include "log_softmax.hpp"
#include "lookup.hpp"
#include "lp_pooling.hpp"
#include "lstm.hpp"
#include "max_pooling.hpp"
#include "mean_pooling.hpp"
@@ -57,6 +58,7 @@
#include "noisylinear.hpp"
#include "padding.hpp"
#include "parametric_relu.hpp"
#include "pixel_shuffle.hpp"
#include "positional_encoding.hpp"
#include "recurrent_attention.hpp"
#include "recurrent.hpp"
+7 -1
View File
@@ -38,10 +38,12 @@
#include <mlpack/methods/ann/layer/multiply_constant.hpp>
#include <mlpack/methods/ann/layer/max_pooling.hpp>
#include <mlpack/methods/ann/layer/mean_pooling.hpp>
#include <mlpack/methods/ann/layer/lp_pooling.hpp>
#include <mlpack/methods/ann/layer/noisylinear.hpp>
#include <mlpack/methods/ann/layer/adaptive_max_pooling.hpp>
#include <mlpack/methods/ann/layer/adaptive_mean_pooling.hpp>
#include <mlpack/methods/ann/layer/parametric_relu.hpp>
#include <mlpack/methods/ann/layer/pixel_shuffle.hpp>
#include <mlpack/methods/ann/layer/positional_encoding.hpp>
#include <mlpack/methods/ann/layer/reinforce_normal.hpp>
#include <mlpack/methods/ann/layer/reparametrization.hpp>
@@ -52,6 +54,7 @@
#include <mlpack/methods/ann/layer/virtual_batch_norm.hpp>
#include <mlpack/methods/ann/layer/hardshrink.hpp>
#include <mlpack/methods/ann/layer/celu.hpp>
#include <mlpack/methods/ann/layer/isrlu.hpp>
#include <mlpack/methods/ann/layer/softshrink.hpp>
#include <mlpack/methods/ann/layer/radial_basis_function.hpp>
@@ -219,6 +222,8 @@ class AdaptiveMeanPooling;
using MoreTypes = boost::variant<
Linear3D<arma::mat, arma::mat, NoRegularizer>*,
LpPooling<arma::mat, arma::mat>*,
PixelShuffle<arma::mat, arma::mat>*,
Glimpse<arma::mat, arma::mat>*,
Highway<arma::mat, arma::mat>*,
MultiheadAttention<arma::mat, arma::mat, NoRegularizer>*,
@@ -234,7 +239,8 @@ using MoreTypes = boost::variant<
VirtualBatchNorm<arma::mat, arma::mat>*,
RBF<arma::mat, arma::mat, GaussianFunction>*,
BaseLayer<GaussianFunction, arma::mat, arma::mat>*,
PositionalEncoding<arma::mat, arma::mat>*
PositionalEncoding<arma::mat, arma::mat>*,
ISRLU<arma::mat, arma::mat>*
>;
template <typename... CustomLayers>
@@ -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,
+284
View File
@@ -0,0 +1,284 @@
/**
* @file methods/ann/layer/lp_pooling.hpp
* @author Abhinav Anan
*
* Definition of the LpPooling layer class.
*
* 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_LAYER_LP_POOLING_HPP
#define MLPACK_METHODS_ANN_LAYER_LP_POOLING_HPP
#include <mlpack/prereqs.hpp>
namespace mlpack {
namespace ann /** Artificial Neural Network. */ {
/**
* Implementation of the LPPooling.
*
* @tparam InputDataType Type of the input data (arma::colvec, arma::mat,
* arma::sp_mat or arma::cube).
* @tparam OutputDataType Type of the output data (arma::colvec, arma::mat,
* arma::sp_mat or arma::cube).
*/
template <
typename InputDataType = arma::mat,
typename OutputDataType = arma::mat
>
class LpPooling
{
public:
//! Create the LpPooling object.
LpPooling();
/**
* Create the LpPooling object using the specified number of units.
*
* @param normType Parameter for type of norm.
* @param kernelWidth Width of the pooling window.
* @param kernelHeight Height of the pooling window.
* @param strideWidth Width of the stride operation.
* @param strideHeight Width of the stride operation.
* @param floor Set to true to use floor method.
*/
LpPooling(const size_t normType,
const size_t kernelWidth,
const size_t kernelHeight,
const size_t strideWidth = 1,
const size_t strideHeight = 1,
const bool floor = true);
/**
* Ordinary feed forward pass of a neural network, evaluating the function
* f(x) by propagating the activity forward through f.
*
* @param input Input data used for evaluating the specified function.
* @param output Resulting output activation.
*/
template<typename eT>
void Forward(const arma::Mat<eT>& input, arma::Mat<eT>& output);
/**
* Ordinary feed backward pass of a neural network, using 3rd-order tensors as
* input, calculating the function f(x) by propagating x backwards through f.
* Using the results from the feed forward pass.
*
* @param * (input) The propagated input activation.
* @param gy The backpropagated error.
* @param g The calculated gradient.
*/
template<typename eT>
void Backward(const arma::Mat<eT>& /* input */,
const arma::Mat<eT>& gy,
arma::Mat<eT>& g);
//! Get the output parameter.
OutputDataType const& OutputParameter() const { return outputParameter; }
//! Modify the output parameter.
OutputDataType& OutputParameter() { return outputParameter; }
//! Get the delta.
OutputDataType const& Delta() const { return delta; }
//! Modify the delta.
OutputDataType& Delta() { return delta; }
//! Get the intput width.
size_t const& InputWidth() const { return inputWidth; }
//! Modify the input width.
size_t& InputWidth() { return inputWidth; }
//! Get the input height.
size_t const& InputHeight() const { return inputHeight; }
//! Modify the input height.
size_t& InputHeight() { return inputHeight; }
//! Get the output width.
size_t const& OutputWidth() const { return outputWidth; }
//! Modify the output width.
size_t& OutputWidth() { return outputWidth; }
//! Get the output height.
size_t const& OutputHeight() const { return outputHeight; }
//! Modify the output height.
size_t& OutputHeight() { return outputHeight; }
//! Get the input size.
size_t InputSize() const { return inSize; }
//! Get the output size.
size_t OutputSize() const { return outSize; }
//! Get the normType.
size_t NormType() const { return normType; }
//! Modify the normType.
size_t& NormType() { return normType; }
//! Get the kernel width.
size_t KernelWidth() const { return kernelWidth; }
//! Modify the kernel width.
size_t& KernelWidth() { return kernelWidth; }
//! Get the kernel height.
size_t KernelHeight() const { return kernelHeight; }
//! Modify the kernel height.
size_t& KernelHeight() { return kernelHeight; }
//! Get the stride width.
size_t StrideWidth() const { return strideWidth; }
//! Modify the stride width.
size_t& StrideWidth() { return strideWidth; }
//! Get the stride height.
size_t StrideHeight() const { return strideHeight; }
//! Modify the stride height.
size_t& StrideHeight() { return strideHeight; }
//! Get the value of the rounding operation
bool const& Floor() const { return floor; }
//! Modify the value of the rounding operation
bool& Floor() { return floor; }
//! Get the size of the weights.
size_t WeightSize() const { return 0; }
/**
* Serialize the layer.
*/
template<typename Archive>
void serialize(Archive& ar, const uint32_t /* version */);
private:
/**
* Apply pooling to the input and store the results.
*
* @param input The input to be apply the pooling rule.
* @param output The pooled result.
*/
template<typename eT>
void Pooling(const arma::Mat<eT>& input, arma::Mat<eT>& output)
{
for (size_t j = 0, colidx = 0; j < output.n_cols;
++j, colidx += strideHeight)
{
for (size_t i = 0, rowidx = 0; i < output.n_rows;
++i, rowidx += strideWidth)
{
arma::mat subInput = input(
arma::span(rowidx, rowidx + kernelWidth - 1 - offset),
arma::span(colidx, colidx + kernelHeight - 1 - offset));
output(i, j) = pow(arma::accu(arma::pow(subInput,
normType)), 1.0 / normType);
}
}
}
/**
* Apply unpooling to the input and store the results.
*
* @param input The input to be apply the unpooling rule.
* @param output The pooled result.
*/
template<typename eT>
void Unpooling(const arma::Mat<eT>& input,
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 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));
size_t sum = pow(arma::accu(arma::pow(inputArea, normType)),
(normType - 1) / normType);
unpooledError = arma::Mat<eT>(inputArea.n_rows, inputArea.n_cols);
unpooledError.fill(error(i / rStep, j / cStep));
unpooledError %= arma::pow(inputArea, normType - 1);
unpooledError /= sum;
output(arma::span(i, i + rStep - 1 - offset),
arma::span(j, j + cStep - 1 - offset)) += unpooledError;
}
}
}
//! Locally-stored norm type.
size_t normType;
//! Locally-stored width of the pooling window.
size_t kernelWidth;
//! Locally-stored height of the pooling window.
size_t kernelHeight;
//! Locally-stored width of the stride operation.
size_t strideWidth;
//! Locally-stored height of the stride operation.
size_t strideHeight;
//! Rounding operation used.
bool floor;
//! Locally-stored number of input channels.
size_t inSize;
//! Locally-stored number of output channels.
size_t outSize;
//! Locally-stored input width.
size_t inputWidth;
//! Locally-stored input height.
size_t inputHeight;
//! Locally-stored output width.
size_t outputWidth;
//! Locally-stored output height.
size_t outputHeight;
//! Locally-stored reset parameter used to initialize the module once.
bool reset;
//! Locally-stored stored rounding offset.
size_t offset;
//! Locally-stored number of input units.
size_t batchSize;
//! Locally-stored output parameter.
arma::cube outputTemp;
//! Locally-stored transformed input parameter.
arma::cube inputTemp;
//! Locally-stored transformed output parameter.
arma::cube gTemp;
//! Locally-stored delta object.
OutputDataType delta;
//! Locally-stored gradient object.
OutputDataType gradient;
//! Locally-stored output parameter object.
OutputDataType outputParameter;
}; // class LpPooling
} // namespace ann
} // namespace mlpack
// Include implementation.
#include "lp_pooling_impl.hpp"
#endif
@@ -0,0 +1,141 @@
/**
* @file methods/ann/layer/lp_pooling_impl.hpp
* @author Marcus Edel
* @author Nilay Jain
*
* Implementation of the lpPooling layer class.
*
* 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_LAYER_LP_POOLING_IMPL_HPP
#define MLPACK_METHODS_ANN_LAYER_LP_POOLING_IMPL_HPP
// In case it hasn't yet been included.
#include "lp_pooling.hpp"
namespace mlpack {
namespace ann /** Artificial Neural Network. */ {
template<typename InputDataType, typename OutputDataType>
LpPooling<InputDataType, OutputDataType>::LpPooling()
{
// Nothing to do here.
}
template<typename InputDataType, typename OutputDataType>
LpPooling<InputDataType, OutputDataType>::LpPooling(
const size_t normType,
const size_t kernelWidth,
const size_t kernelHeight,
const size_t strideWidth,
const size_t strideHeight,
const bool floor) :
normType(normType),
kernelWidth(kernelWidth),
kernelHeight(kernelHeight),
strideWidth(strideWidth),
strideHeight(strideHeight),
floor(floor),
inSize(0),
outSize(0),
inputWidth(0),
inputHeight(0),
outputWidth(0),
outputHeight(0),
reset(false),
offset(0),
batchSize(0)
{
// Nothing to do here.
}
template<typename InputDataType, typename OutputDataType>
template<typename eT>
void LpPooling<InputDataType, OutputDataType>::Forward(
const arma::Mat<eT>& input, arma::Mat<eT>& output)
{
batchSize = input.n_cols;
inSize = input.n_elem / (inputWidth * inputHeight * batchSize);
inputTemp = arma::cube(const_cast<arma::Mat<eT>&>(input).memptr(),
inputWidth, inputHeight, batchSize * inSize, false, false);
if (floor)
{
outputWidth = std::floor((inputWidth -
(double) kernelWidth) / (double) strideWidth + 1);
outputHeight = std::floor((inputHeight -
(double) kernelHeight) / (double) strideHeight + 1);
offset = 0;
}
else
{
outputWidth = std::ceil((inputWidth -
(double) kernelWidth) / (double) strideWidth + 1);
outputHeight = std::ceil((inputHeight -
(double) kernelHeight) / (double) strideHeight + 1);
offset = 1;
}
outputTemp = arma::zeros<arma::Cube<eT> >(outputWidth, outputHeight,
batchSize * inSize);
for (size_t s = 0; s < inputTemp.n_slices; s++)
Pooling(inputTemp.slice(s), outputTemp.slice(s));
output = arma::Mat<eT>(outputTemp.memptr(), outputTemp.n_elem / batchSize,
batchSize);
outputWidth = outputTemp.n_rows;
outputHeight = outputTemp.n_cols;
outSize = batchSize * inSize;
}
template<typename InputDataType, typename OutputDataType>
template<typename eT>
void LpPooling<InputDataType, OutputDataType>::Backward(
const arma::Mat<eT>& /* input */,
const arma::Mat<eT>& gy,
arma::Mat<eT>& g)
{
arma::cube mappedError = arma::cube(((arma::Mat<eT>&) gy).memptr(),
outputWidth, outputHeight, outSize, false, false);
gTemp = arma::zeros<arma::cube>(inputTemp.n_rows,
inputTemp.n_cols, inputTemp.n_slices);
for (size_t s = 0; s < mappedError.n_slices; s++)
{
Unpooling(inputTemp.slice(s), mappedError.slice(s), gTemp.slice(s));
}
g = arma::mat(gTemp.memptr(), gTemp.n_elem / batchSize, batchSize);
}
template<typename InputDataType, typename OutputDataType>
template<typename Archive>
void LpPooling<InputDataType, OutputDataType>::serialize(
Archive& ar,
const uint32_t /* version */)
{
ar(CEREAL_NVP(normType));
ar(CEREAL_NVP(kernelWidth));
ar(CEREAL_NVP(kernelHeight));
ar(CEREAL_NVP(strideWidth));
ar(CEREAL_NVP(strideHeight));
ar(CEREAL_NVP(batchSize));
ar(CEREAL_NVP(floor));
ar(CEREAL_NVP(inputWidth));
ar(CEREAL_NVP(inputHeight));
ar(CEREAL_NVP(outputWidth));
ar(CEREAL_NVP(outputHeight));
}
} // namespace ann
} // namespace mlpack
#endif
+16 -27
View File
@@ -144,36 +144,25 @@ void LSTM<InputDataType, OutputDataType>::ResetCell(const size_t size)
gradientStep = batchSize * size - 1;
const size_t rhoBatchSize = size * batchSize;
if (inputGate.is_empty() || inputGate.n_cols < rhoBatchSize)
{
inputGate.set_size(outSize, rhoBatchSize);
forgetGate.set_size(outSize, rhoBatchSize);
hiddenLayer.set_size(outSize, rhoBatchSize);
outputGate.set_size(outSize, rhoBatchSize);
inputGateActivation.set_size(outSize, rhoBatchSize);
forgetGateActivation.set_size(outSize, rhoBatchSize);
outputGateActivation.set_size(outSize, rhoBatchSize);
hiddenLayerActivation.set_size(outSize, rhoBatchSize);
// Make sure all of the different matrices we will use to hold parameters are
// at least as large as we need.
inputGate.set_size(outSize, rhoBatchSize);
forgetGate.set_size(outSize, rhoBatchSize);
hiddenLayer.set_size(outSize, rhoBatchSize);
outputGate.set_size(outSize, rhoBatchSize);
cellActivation.set_size(outSize, rhoBatchSize);
prevError.set_size(4 * outSize, batchSize);
inputGateActivation.set_size(outSize, rhoBatchSize);
forgetGateActivation.set_size(outSize, rhoBatchSize);
outputGateActivation.set_size(outSize, rhoBatchSize);
hiddenLayerActivation.set_size(outSize, rhoBatchSize);
if (cell.is_empty())
{
cell = arma::zeros(outSize, size * batchSize);
outParameter = arma::zeros<OutputDataType>(
outSize, (size + 1) * batchSize);
}
else
{
// To preserve the leading zeros, recreate the object according to given
// size specifications, while preserving the elements as well as the
// layout of the elements.
cell.resize(outSize, size * batchSize);
outParameter.resize(outSize, (size + 1) * batchSize);
}
}
cellActivation.set_size(outSize, rhoBatchSize);
prevError.set_size(4 * outSize, batchSize);
// Now reset recurrent values to 0.
cell.zeros(outSize, size * batchSize);
outParameter.zeros(outSize, (size + 1) * batchSize);
}
template<typename InputDataType, typename OutputDataType>
@@ -120,6 +120,9 @@ class MultiheadAttention
const arma::Mat<eT>& error,
arma::Mat<eT>& gradient);
//! Get the size of the weights.
size_t WeightSize() const { return 4 * (embedDim + 1) * embedDim; }
/**
* Serialize the layer.
*/
@@ -54,7 +54,7 @@ MultiheadAttention(
}
headDim = embedDim / numHeads;
weights.set_size(4 * (embedDim + 1) * embedDim, 1);
weights.set_size(WeightSize(), 1);
}
template <typename InputDataType, typename OutputDataType,
@@ -39,6 +39,18 @@ class MultiplyConstant
*/
MultiplyConstant(const double scalar = 1.0);
//! Copy Constructor.
MultiplyConstant(const MultiplyConstant& layer);
//! Move Constructor.
MultiplyConstant(MultiplyConstant&& layer);
//! Copy assignment operator.
MultiplyConstant& operator=(const MultiplyConstant& layer);
//! Move assignment operator.
MultiplyConstant& operator=(MultiplyConstant&& layer);
/**
* Ordinary feed forward pass of a neural network. Multiply the input with the
* specified constant scalar value.
@@ -75,6 +87,9 @@ class MultiplyConstant
//! Modify the scalar multiplier.
double& Scalar() { return scalar; }
//! Get the size of the weights.
size_t WeightSize() const { return 0; }
/**
* Serialize the layer.
*/
@@ -26,6 +26,46 @@ MultiplyConstant<InputDataType, OutputDataType>::MultiplyConstant(
// Nothing to do here.
}
template<typename InputDataType, typename OutputDataType>
MultiplyConstant<InputDataType, OutputDataType>::MultiplyConstant(
const MultiplyConstant& layer) :
scalar(layer.scalar)
{
// Nothing to do here.
}
template<typename InputDataType, typename OutputDataType>
MultiplyConstant<InputDataType, OutputDataType>::MultiplyConstant(
MultiplyConstant&& layer) :
scalar(std::move(layer.scalar))
{
// Nothing to do here.
}
template<typename InputDataType, typename OutputDataType>
MultiplyConstant<InputDataType, OutputDataType>&
MultiplyConstant<InputDataType, OutputDataType>::operator=(
const MultiplyConstant& layer)
{
if (this != &layer)
{
scalar = layer.scalar;
}
return *this;
}
template<typename InputDataType, typename OutputDataType>
MultiplyConstant<InputDataType, OutputDataType>&
MultiplyConstant<InputDataType, OutputDataType>::operator=(
MultiplyConstant&& layer)
{
if (this != &layer)
{
scalar = std::move(layer.scalar);
}
return *this;
}
template<typename InputDataType, typename OutputDataType>
template<typename InputType, typename OutputType>
void MultiplyConstant<InputDataType, OutputDataType>::Forward(
@@ -50,6 +50,18 @@ class MultiplyMerge
*/
MultiplyMerge(const bool model = false, const bool run = true);
//! Copy Constructor.
MultiplyMerge(const MultiplyMerge& layer);
//! Move Constructor.
MultiplyMerge(MultiplyMerge&& layer);
//! Copy assignment operator.
MultiplyMerge& operator=(const MultiplyMerge& layer);
//! Move assignment operator.
MultiplyMerge& operator=(MultiplyMerge&& layer);
//! Destructor to release allocated memory.
~MultiplyMerge();
@@ -135,6 +147,9 @@ class MultiplyMerge
//! Modify the parameters.
OutputDataType& Parameters() { return weights; }
//! Get the size of the weights.
size_t WeightSize() const { return 0; }
/**
* Serialize the layer.
*/
@@ -32,6 +32,66 @@ MultiplyMerge<InputDataType, OutputDataType, CustomLayers...>::MultiplyMerge(
// Nothing to do here.
}
template<typename InputDataType, typename OutputDataType,
typename... CustomLayers>
MultiplyMerge<InputDataType, OutputDataType, CustomLayers...>::MultiplyMerge(
const MultiplyMerge& layer) :
model(layer.model),
run(layer.run),
ownsLayer(layer.ownsLayer),
network(layer.network),
weights(layer.weights)
{
// Nothing to do here.
}
template<typename InputDataType, typename OutputDataType,
typename... CustomLayers>
MultiplyMerge<InputDataType, OutputDataType, CustomLayers...>::MultiplyMerge(
MultiplyMerge&& layer) :
model(std::move(layer.model)),
run(std::move(layer.run)),
ownsLayer(std::move(layer.ownsLayer)),
network(std::move(layer.network)),
weights(std::move(layer.weights))
{
// Nothing to do here.
}
template<typename InputDataType, typename OutputDataType,
typename... CustomLayers>
MultiplyMerge<InputDataType, OutputDataType, CustomLayers...>&
MultiplyMerge<InputDataType, OutputDataType, CustomLayers...>::operator=(
const MultiplyMerge& layer)
{
if (this != &layer)
{
model = layer.model;
run = layer.run;
ownsLayer = layer.ownsLayer;
network = layer.network;
weights = layer.weights;
}
return *this;
}
template<typename InputDataType, typename OutputDataType,
typename... CustomLayers>
MultiplyMerge<InputDataType, OutputDataType, CustomLayers...>&
MultiplyMerge<InputDataType, OutputDataType, CustomLayers...>::operator=(
MultiplyMerge&& layer)
{
if (this != &layer)
{
model = std::move(layer.model);
run = std::move(layer.run);
ownsLayer = std::move(layer.ownsLayer);
network = std::move(layer.network);
weights = std::move(layer.weights);
}
return *this;
}
template<typename InputDataType, typename OutputDataType,
typename... CustomLayers>
MultiplyMerge<InputDataType, OutputDataType, CustomLayers...>::~MultiplyMerge()
@@ -0,0 +1,181 @@
/**
* @file methods/ann/layer/pixel_shuffle.hpp
* @author Anjishnu Mukherjee
* @author Abhinav Anand
*
* Definition of the PixelShuffle class.
*
* 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_LAYER_PIXEL_SHUFFLE_HPP
#define MLPACK_METHODS_ANN_LAYER_PIXEL_SHUFFLE_HPP
#include <mlpack/prereqs.hpp>
namespace mlpack {
namespace ann /** Artificial Neural Network. */ {
/**
* Implementation of the PixelShuffle layer.
*
* For more information, refer to the following paper,
*
* @code
* @article{Shi16,
* author = {Wenzhe Shi, Jose Caballero,Ferenc Huszár, Johannes Totz,
* Andrew P. Aitken, Rob Bishop, Daniel Rueckert, Zehan Wang},
* title = {Real-Time Single Image and Video Super-Resolution Using an
* Efficient Sub-Pixel Convolutional Neural Network},
* journal = {CoRR},
* volume = {abs/1609.05158},
* year = {2016},
* url = {https://arxiv.org/abs/1609.05158},
* eprint = {1609.05158},
* }
* @endcode
*
* @tparam InputDataType Type of the input data (arma::colvec, arma::mat,
* arma::sp_mat or arma::cube).
* @tparam OutputDataType Type of the output data (arma::colvec, arma::mat,
* arma::sp_mat or arma::cube).
*/
template <
typename InputDataType = arma::mat,
typename OutputDataType = arma::mat
>
class PixelShuffle
{
public:
//! Create the PixelShuffle object.
PixelShuffle();
/**
* Create the PixelShuffle object using the specified parameters.
* The number of input channels should be an integral multiple of the square
* of the upscale factor.
*
* @param upscaleFactor The scaling factor for Pixel Shuffle.
* @param height The height of each input image.
* @param width The width of each input image.
* @param size The number of channels of each input image.
*/
PixelShuffle(const size_t upscaleFactor,
const size_t height,
const size_t width,
const size_t size);
/**
* Ordinary feed forward pass of the PixelShuffle layer.
*
* @param input Input data used for evaluating the specified function.
* @param output Resulting output activation.
*/
template<typename eT>
void Forward(const arma::Mat<eT>& input, arma::Mat<eT>& output);
/**
* Ordinary feed backward pass of the PixelShuffle layer.
*
* @param input The propagated input activation.
* @param gy The backpropagated error.
* @param g The calculated gradient.
*/
template<typename eT>
void Backward(const arma::Mat<eT>& input,
const arma::Mat<eT>& gy,
arma::Mat<eT>& g);
//! Get the output parameter.
OutputDataType const& OutputParameter() const { return outputParameter; }
//! Modify the output parameter.
OutputDataType& OutputParameter() { return outputParameter; }
//! Get the delta.
OutputDataType const& Delta() const { return delta; }
//! Modify the delta.
OutputDataType& Delta() { return delta; }
//! Get the upscale factor.
size_t UpscaleFactor() const { return upscaleFactor; }
//! Modify the upscale factor.
size_t& UpscaleFactor() { return upscaleFactor; }
//! Get the input image height.
size_t InputHeight() const { return height; }
//! Modify the input image height.
size_t& InputHeight() { return height; }
//! Get the input image width.
size_t InputWidth() const { return width; }
//! Modify the input image width.
size_t& InputWidth() { return width; }
//! Get the number of input channels.
size_t InputChannels() const { return size; }
//! Modify the number of input channels.
size_t& InputChannels() { return size; }
//! Get the output image height.
size_t OutputHeight() const { return outputHeight; }
//! Get the output image width.
size_t OutputWidth() const { return outputWidth; }
//! Get the number of output channels.
size_t OutputChannels() const { return sizeOut; }
/**
* Serialize the layer.
*/
template<typename Archive>
void serialize(Archive& ar, const unsigned int /* version */);
private:
//! Locally-stored delta object.
OutputDataType delta;
//! Locally-stored output parameter object.
OutputDataType outputParameter;
//! The scaling factor for Pixel Shuffle.
size_t upscaleFactor;
//! The height of each input image.
size_t height;
//! The width of each input image.
size_t width;
//! The number of channels of each input image.
size_t size;
//! The number of images in the batch.
size_t batchSize;
//! The height of each output image.
size_t outputHeight;
//! The width of each output image.
size_t outputWidth;
//! The number of channels of each output image.
size_t sizeOut;
//! A boolean used to do some internal calculations once initially.
bool reset;
}; // class PixelShuffle
} // namespace ann
} // namespace mlpack
// Include implementation.
#include "pixel_shuffle_impl.hpp"
#endif
@@ -0,0 +1,143 @@
/**
* @file methods/ann/layer/pixel_shuffle_impl.hpp
* @author Anjishnu Mukherjee
* @author Abhinav Anand
*
* Implementation of the PixelShuffle class.
*
* 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_LAYER_PIXEL_SHUFFLE_IMPL_HPP
#define MLPACK_METHODS_ANN_LAYER_PIXEL_SHUFFLE_IMPL_HPP
// In case it hasn't yet been included.
#include "pixel_shuffle.hpp"
namespace mlpack {
namespace ann /** Artificial Neural Network. */ {
template<typename InputDataType, typename OutputDataType>
PixelShuffle<InputDataType, OutputDataType>::PixelShuffle() :
PixelShuffle(0, 0, 0, 0)
{
// Nothing to do here.
}
template<typename InputDataType, typename OutputDataType>
PixelShuffle<InputDataType, OutputDataType>::PixelShuffle(
const size_t upscaleFactor,
const size_t height,
const size_t width,
const size_t size) :
upscaleFactor(upscaleFactor),
height(height),
width(width),
size(size),
batchSize(0),
outputHeight(0),
outputWidth(0),
sizeOut(0),
reset(false)
{
// Nothing to do here.
}
template<typename InputDataType, typename OutputDataType>
template<typename eT>
void PixelShuffle<InputDataType, OutputDataType>::Forward(
const arma::Mat<eT>& input, arma::Mat<eT>& output)
{
if (!reset)
{
batchSize = input.n_cols;
sizeOut = size / std::pow(upscaleFactor, 2);
outputHeight = height * upscaleFactor;
outputWidth = width * upscaleFactor;
reset = true;
}
output.zeros(outputHeight * outputWidth * sizeOut, batchSize);
for (size_t n = 0; n < batchSize; n++)
{
arma::cube inputTemp(const_cast<arma::mat&>(input).memptr(), height,
width, size * batchSize, false, false);
arma::cube outputTemp(const_cast<arma::mat&>(output).memptr(),
outputHeight, outputWidth, sizeOut * batchSize, false, false);
for (size_t c = 0; c < sizeOut; c++)
{
for (size_t h = 0; h < outputHeight; h++)
{
for (size_t w = 0; w < outputWidth; w++)
{
size_t height_index = h / upscaleFactor;
size_t width_index = w / upscaleFactor;
size_t channel_index = (upscaleFactor * (h % upscaleFactor)) +
(w % upscaleFactor) + (c * std::pow(upscaleFactor, 2));
outputTemp(w, h, c + n * sizeOut) = inputTemp(width_index, height_index,
channel_index + n * size);
}
}
}
}
}
template<typename InputDataType, typename OutputDataType>
template<typename eT>
void PixelShuffle<InputDataType, OutputDataType>::Backward(
const arma::Mat<eT>& input, const arma::Mat<eT>& gy, arma::Mat<eT>& g)
{
g.zeros(arma::size(input));
for (size_t n = 0; n < batchSize; n++)
{
arma::cube gyTemp(const_cast<arma::mat&>(gy).memptr(), outputHeight,
outputWidth, sizeOut * batchSize, false, false);
arma::cube gTemp(const_cast<arma::mat&>(g).memptr(), height, width,
size * batchSize, false, false);
for (size_t c = 0; c < sizeOut; c++)
{
for (size_t h = 0; h < outputHeight; h++)
{
for (size_t w = 0; w < outputWidth; w++)
{
size_t height_index = h / upscaleFactor;
size_t width_index = w / upscaleFactor;
size_t channel_index = (upscaleFactor * (h % upscaleFactor)) +
(w % upscaleFactor) + (c * std::pow(upscaleFactor, 2));
gTemp(width_index, height_index, channel_index + n * size) = gyTemp(w, h,
c + n * sizeOut);
}
}
}
}
}
template<typename InputDataType, typename OutputDataType>
template<typename Archive>
void PixelShuffle<InputDataType, OutputDataType>::serialize(
Archive& ar,
const unsigned int /* version */)
{
ar(CEREAL_NVP(delta));
ar(CEREAL_NVP(outputParameter));
ar(CEREAL_NVP(upscaleFactor));
ar(CEREAL_NVP(height));
ar(CEREAL_NVP(width));
ar(CEREAL_NVP(size));
ar(CEREAL_NVP(batchSize));
ar(CEREAL_NVP(outputHeight));
ar(CEREAL_NVP(outputHeight));
ar(CEREAL_NVP(outputWidth));
ar(CEREAL_NVP(sizeOut));
}
} // namespace ann
} // namespace mlpack
#endif
@@ -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
{
@@ -31,7 +31,8 @@ RecurrentAttention<InputDataType, OutputDataType>::RecurrentAttention() :
rho(0),
forwardStep(0),
backwardStep(0),
deterministic(false)
deterministic(false),
outSize(0)
{
// Nothing to do.
}
@@ -21,7 +21,7 @@ namespace ann /** Artificial Neural Network. */ {
template<typename InputDataType, typename OutputDataType>
ReinforceNormal<InputDataType, OutputDataType>::ReinforceNormal(
const double stdev) : stdev(stdev)
const double stdev) : stdev(stdev), reward(0.0), deterministic(false)
{
// Nothing to do here.
}
@@ -34,8 +34,7 @@ void ReinforceNormal<InputDataType, OutputDataType>::Forward(
if (!deterministic)
{
// Multiply by standard deviations and re-center the means to the mean.
output = arma::randn<arma::Mat<eT> >(input.n_rows, input.n_cols) *
stdev + input;
output = output.randn(input.n_rows, input.n_cols) * stdev + input;
moduleInputParameter.push_back(input);
}
@@ -126,8 +126,7 @@ TransposedConvolution<
{
weights.set_size(WeightSize(), 1);
// Transform paddingType to lowercase.
std::string paddingTypeLow = paddingType;
util::ToLower(paddingType, paddingTypeLow);
const std::string paddingTypeLow = util::ToLower(paddingType);
if (paddingTypeLow == "valid")
{
+11
View File
@@ -206,6 +206,17 @@ class LayerNameVisitor : public boost::static_visitor<std::string>
return "meanpooling";
}
/**
* Return the name of the given layer of type LpPooling as a string.
*
* @param * Given layer of type LpPooling.
* @return The string representation of the layer.
*/
std::string LayerString(LpPooling<>* /*layer*/) const
{
return "lppooling";
}
/**
* Return the name of the given layer of type MultiplyConstant as a string.
*
@@ -9,24 +9,32 @@ set(SOURCES
dice_loss_impl.hpp
earth_mover_distance.hpp
earth_mover_distance_impl.hpp
empty_loss.hpp
empty_loss_impl.hpp
huber_loss.hpp
huber_loss_impl.hpp
hinge_embedding_loss.hpp
hinge_embedding_loss_impl.hpp
hinge_loss.hpp
hinge_loss_impl.hpp
kl_divergence.hpp
kl_divergence_impl.hpp
margin_ranking_loss.hpp
margin_ranking_loss_impl.hpp
mean_bias_error.hpp
mean_bias_error_impl.hpp
l1_loss.hpp
l1_loss_impl.hpp
log_cosh_loss.hpp
log_cosh_loss_impl.hpp
margin_ranking_loss.hpp
margin_ranking_loss_impl.hpp
mean_absolute_percentage_error.hpp
mean_absolute_percentage_error_impl.hpp
mean_bias_error.hpp
mean_bias_error_impl.hpp
mean_squared_error.hpp
mean_squared_error_impl.hpp
mean_squared_logarithmic_error.hpp
mean_squared_logarithmic_error_impl.hpp
negative_log_likelihood.hpp
negative_log_likelihood_impl.hpp
log_cosh_loss.hpp
log_cosh_loss_impl.hpp
poisson_nll_loss.hpp
poisson_nll_loss_impl.hpp
reconstruction_loss.hpp
@@ -35,12 +43,6 @@ set(SOURCES
sigmoid_cross_entropy_error_impl.hpp
soft_margin_loss.hpp
soft_margin_loss_impl.hpp
hinge_embedding_loss.hpp
hinge_embedding_loss_impl.hpp
empty_loss.hpp
empty_loss_impl.hpp
mean_absolute_percentage_error.hpp
mean_absolute_percentage_error_impl.hpp
triplet_margin_loss.hpp
triplet_margin_loss_impl.hpp
)
@@ -0,0 +1,105 @@
/**
* @file methods/ann/loss_functions/hinge_loss.hpp
* @author Anush Kini
*
* Definition of the Hinge Loss Function.
*
* 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_LOSS_FUNCTION_HINGE_LOSS_HPP
#define MLPACK_METHODS_ANN_LOSS_FUNCTION_HINGE_LOSS_HPP
#include<mlpack/prereqs.hpp>
namespace mlpack {
namespace ann /** Artificial Neural Network. */ {
/**
* Computes the hinge loss between \f$y_true\f$ and \f$y_pred\f$. Expects
* \f$y_true\f$ to be either -1 or 1. If \f$y_true\f$ is either 0 or 1, a
* temporary conversion is made to calculate the loss.
* The hinge loss \f$l(y_true, y_pred)\f$ is defined as
* \f$l(y_true, y_pred) = max(0, 1 - y_true*y_pred)\f$.
*
* @tparam InputDataType Type of the input data (arma::colvec, arma::mat,
* arma::sp_mat or arma::cube).
* @tparam OutputDataType Type of the output data (arma::colvec, arma::mat,
* arma::sp_mat or arma::cube).
*/
template <
typename InputDataType = arma::mat,
typename OutputDataType = arma::mat
>
class HingeLoss
{
public:
/**
* Create HingeLoss object.
*
* @param reduction Specifies the reduction to apply to the output. If false,
* 'mean' reduction is used, where sum of the output will be
* divided by the number of elements in the output. If
* true, 'sum' reduction is used and the output will be
* summed. It is set to true by default.
*/
HingeLoss(const bool reduction = true);
/**
* Computes the Hinge loss function.
*
* @param prediction Prediction used for evaluating the specified loss
* function.
* @param target Target data to compare with.
*/
template<typename PredictionType, typename TargetType>
typename PredictionType::elem_type Forward(const PredictionType& prediction,
const TargetType& target);
/**
* Ordinary feed backward pass of a neural network.
*
* @param prediction Prediction used for evaluating the specified loss
* function.
* @param target The target vector.
* @param loss The calculated error.
*/
template<typename PredictionType, typename TargetType, typename LossType>
void Backward(const PredictionType& prediction,
const TargetType& target,
LossType& loss);
//! Get the output parameter.
OutputDataType& OutputParameter() const { return outputParameter; }
//! Modify the output parameter.
OutputDataType& OutputParameter() { return outputParameter; }
//! Get the type of reduction used.
bool Reduction() const { return reduction; }
//! Modify the type of reduction used.
bool& Reduction() { return reduction; }
/**
* Serialize the layer.
*/
template<typename Archive>
void serialize(Archive& ar, const uint32_t /* version */);
private:
//! Locally-stored output parameter object.
OutputDataType outputParameter;
//! The boolean value that tells if reduction is sum or mean.
bool reduction;
}; // class HingeLoss
} // namespace ann
} // namespace mlpack
// include implementation
#include "hinge_loss_impl.hpp"
#endif
@@ -0,0 +1,75 @@
/**
* @file methods/ann/loss_functions/hinge_loss_impl.hpp
* @author Anush Kini
*
* Implementation of the Hinge loss function.
*
* 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_LOSS_FUNCTION_HINGE_LOSS_IMPL_HPP
#define MLPACK_METHODS_ANN_LOSS_FUNCTION_HINGE_LOSS_IMPL_HPP
// In case it hasn't yet been included.
#include "hinge_loss.hpp"
namespace mlpack {
namespace ann /** Artificial Neural Network. */ {
template<typename InputDataType, typename OutputDataType>
HingeLoss<InputDataType, OutputDataType>::HingeLoss(const bool reduction):
reduction(reduction)
{
// Nothing to do here.
}
template<typename InputDataType, typename OutputDataType>
template<typename PredictionType, typename TargetType>
typename PredictionType::elem_type
HingeLoss<InputDataType, OutputDataType>::Forward(
const PredictionType& prediction,
const TargetType& target)
{
TargetType temp = target - (target == 0);
TargetType temp_zeros(size(target), arma::fill::zeros);
PredictionType loss = arma::max(temp_zeros, 1 - prediction % temp);
typename PredictionType::elem_type lossSum = arma::accu(loss);
if (reduction)
return lossSum;
return lossSum / loss.n_elem;
}
template<typename InputDataType, typename OutputDataType>
template<typename PredictionType, typename TargetType, typename LossType>
void HingeLoss<InputDataType, OutputDataType>::Backward(
const PredictionType& prediction,
const TargetType& target,
LossType& loss)
{
TargetType temp = target - (target == 0);
loss = (prediction < (1 / temp)) % -temp;
if (!reduction)
loss /= target.n_elem;
}
template<typename InputDataType, typename OutputDataType>
template<typename Archive>
void HingeLoss<InputDataType, OutputDataType>::serialize(
Archive& ar,
const uint32_t /* version */)
{
ar(CEREAL_NVP(reduction));
}
} // namespace ann
} // namespace mlpack
#endif
@@ -35,11 +35,10 @@ NegativeLogLikelihood<InputDataType, OutputDataType>::Forward(
ElemType output = 0;
for (size_t i = 0; i < prediction.n_cols; ++i)
{
size_t currentTarget = target(i) - 1;
Log::Assert(currentTarget < prediction.n_rows,
Log::Assert(target(i) >= 0 && target(i) < prediction.n_rows,
"Target class out of range.");
output -= prediction(currentTarget, i);
output -= prediction(target(i), i);
}
return output;
@@ -55,11 +54,10 @@ void NegativeLogLikelihood<InputDataType, OutputDataType>::Backward(
loss = arma::zeros<LossType>(prediction.n_rows, prediction.n_cols);
for (size_t i = 0; i < prediction.n_cols; ++i)
{
size_t currentTarget = target(i) - 1;
Log::Assert(currentTarget < prediction.n_rows,
Log::Assert(target(i) >= 0 && target(i) < prediction.n_rows,
"Target class out of range.");
loss(currentTarget, i) = -1;
loss(target(i), i) = -1;
}
}
+2 -2
View File
@@ -87,10 +87,10 @@ RNN<OutputLayerType, InitializationRuleType, CustomLayers...>::RNN(
targetSize(std::move(network.targetSize)),
reset(std::move(network.reset)),
single(std::move(network.single)),
network(std::move(network.network)),
parameter(std::move(network.parameter)),
numFunctions(std::move(network.numFunctions)),
deterministic(std::move(network.deterministic)),
network(std::move(network.network))
deterministic(std::move(network.deterministic))
{
// Nothing to do here.
}
+1
View File
@@ -5,6 +5,7 @@ set(SOURCES
cf_impl.hpp
cf_model.hpp
cf_model_impl.hpp
cf_model.cpp
svd_wrapper.hpp
svd_wrapper_impl.hpp
)
+163 -279
View File
@@ -194,279 +194,6 @@ PARAM_STRING_IN("interpolation", "Algorithm used for weight interpolation.",
PARAM_STRING_IN("neighbor_search", "Algorithm used for neighbor search.",
"S", "euclidean");
template <typename NeighborSearchType,
typename InterpolationType>
void ComputeRecommendations(CFModel* cf,
const size_t numRecs,
arma::Mat<size_t>& recommendations)
{
// Reading users.
if (IO::HasParam("query"))
{
// User matrix.
arma::Mat<size_t> users =
std::move(IO::GetParam<arma::Mat<size_t>>("query"));
if (users.n_rows > 1)
users = users.t();
if (users.n_rows > 1)
Log::Fatal << "List of query users must be one-dimensional!"
<< std::endl;
Log::Info << "Generating recommendations for "
<< users.n_elem << " users."
<< endl;
cf->GetRecommendations<NeighborSearchType, InterpolationType>
(numRecs, recommendations, users.row(0).t());
}
else
{
Log::Info << "Generating recommendations for all users." << endl;
cf->GetRecommendations<NeighborSearchType, InterpolationType>
(numRecs, recommendations);
}
}
template <typename NeighborSearchType>
void ComputeRecommendations(CFModel* cf,
const size_t numRecs,
arma::Mat<size_t>& recommendations)
{
// Verify the Interpolation algorithms.
RequireParamInSet<string>("interpolation", { "average",
"regression", "similarity" }, true, "unknown interpolation algorithm");
// Taking Interpolation Alternatives
const string interpolationAlgorithm = IO::GetParam<string>("interpolation");
// Determining the Interpolation Algorithm
if (interpolationAlgorithm == "average")
{
ComputeRecommendations<NeighborSearchType, AverageInterpolation>
(cf, numRecs, recommendations);
}
else if (interpolationAlgorithm == "regression")
{
ComputeRecommendations<NeighborSearchType, RegressionInterpolation>
(cf, numRecs, recommendations);
}
else if (interpolationAlgorithm == "similarity")
{
ComputeRecommendations<NeighborSearchType, SimilarityInterpolation>
(cf, numRecs, recommendations);
}
}
void ComputeRecommendations(CFModel* cf,
const size_t numRecs,
arma::Mat<size_t>& recommendations)
{
// Verifying the Neighbor Search algorithms
RequireParamInSet<string>("neighbor_search", { "cosine",
"euclidean", "pearson" }, true, "unknown neighbor search algorithm");
// Taking Neighbor Search alternatives
const string neighborSearchAlgorithm = IO::GetParam<string>
("neighbor_search");
// Determining the Neighbor Search Algorithms
if (neighborSearchAlgorithm == "cosine")
{
ComputeRecommendations<CosineSearch>(cf, numRecs, recommendations);
}
else if (neighborSearchAlgorithm == "euclidean")
{
ComputeRecommendations<EuclideanSearch>(cf, numRecs, recommendations);
}
else if (neighborSearchAlgorithm == "pearson")
{
ComputeRecommendations<PearsonSearch>(cf, numRecs, recommendations);
}
}
template <typename NeighborSearchType,
typename InterpolationType>
void ComputeRMSE(CFModel* cf)
{
// Now, compute each test point.
arma::mat testData = std::move(IO::GetParam<arma::mat>("test"));
// Assemble the combination matrix to get RMSE value.
arma::Mat<size_t> combinations(2, testData.n_cols);
for (size_t i = 0; i < testData.n_cols; ++i)
{
combinations(0, i) = size_t(testData(0, i));
combinations(1, i) = size_t(testData(1, i));
}
// Now compute the RMSE.
arma::vec predictions;
cf->Predict<NeighborSearchType, InterpolationType>
(combinations, predictions);
// Compute the root of the sum of the squared errors, divide by the number of
// points to get the RMSE. It turns out this is just the L2-norm divided by
// the square root of the number of points, if we interpret the predictions
// and the true values as vectors.
const double rmse = arma::norm(predictions - testData.row(2).t(), 2) /
std::sqrt((double) testData.n_cols);
Log::Info << "RMSE is " << rmse << "." << endl;
}
template <typename NeighborSearchType>
void ComputeRMSE(CFModel* cf)
{
// Verifying the Interpolation algorithms
RequireParamInSet<string>("interpolation", { "average",
"regression", "similarity" }, true, "unknown interpolation algorithm");
// Taking Interpolation Alternatives
const string interpolationAlgorithm = IO::GetParam<string>("interpolation");
if (interpolationAlgorithm == "average")
{
ComputeRMSE<NeighborSearchType, AverageInterpolation>(cf);
}
else if (interpolationAlgorithm == "regression")
{
ComputeRMSE<NeighborSearchType, RegressionInterpolation>(cf);
}
else if (interpolationAlgorithm == "similarity")
{
ComputeRMSE<NeighborSearchType, SimilarityInterpolation>(cf);
}
}
void ComputeRMSE(CFModel* cf)
{
// Verifying the Neighbor Search algorithms
RequireParamInSet<string>("neighbor_search", { "cosine",
"euclidean", "pearson" }, true, "unknown neighbor search algorithm");
// Taking Neighbor Search alternatives
const string neighborSearchAlgorithm = IO::GetParam<string>
("neighbor_search");
if (neighborSearchAlgorithm == "cosine")
{
ComputeRMSE<CosineSearch>(cf);
}
else if (neighborSearchAlgorithm == "euclidean")
{
ComputeRMSE<EuclideanSearch>(cf);
}
else if (neighborSearchAlgorithm == "pearson")
{
ComputeRMSE<PearsonSearch>(cf);
}
}
void PerformAction(CFModel* c)
{
if (IO::HasParam("query") || IO::HasParam("all_user_recommendations"))
{
// Get parameters for generating recommendations.
const size_t numRecs = (size_t) IO::GetParam<int>("recommendations");
// Get the recommendations.
arma::Mat<size_t> recommendations;
ComputeRecommendations(c, numRecs, recommendations);
// Save the output.
IO::GetParam<arma::Mat<size_t>>("output") = recommendations;
}
if (IO::HasParam("test"))
ComputeRMSE(c);
IO::GetParam<CFModel*>("output_model") = c;
}
template<typename DecompositionPolicy>
void PerformAction(arma::mat& dataset,
const size_t rank,
const size_t maxIterations,
const double minResidue)
{
const size_t neighborhood = (size_t) IO::GetParam<int>("neighborhood");
// Make sure the normalization strategy is valid.
RequireParamInSet<string>("normalization", { "overall_mean", "item_mean",
"user_mean", "z_score", "none" }, true, "unknown normalization type");
CFModel* c = new CFModel();
const string normalizationType = IO::GetParam<string>("normalization");
c->template Train<DecompositionPolicy>(dataset, neighborhood, rank,
maxIterations, minResidue, IO::HasParam("iteration_only_termination"),
normalizationType);
try
{
PerformAction(c);
}
catch (std::exception& e)
{
// Clean the memory before throwing completely.
delete c;
throw;
}
}
void AssembleFactorizerType(const std::string& algorithm,
arma::mat& dataset,
const size_t rank)
{
const size_t maxIterations = (size_t) IO::GetParam<int>("max_iterations");
const double minResidue = IO::GetParam<double>("min_residue");
if (algorithm == "NMF")
{
PerformAction<NMFPolicy>(dataset, rank, maxIterations, minResidue);
}
else if (algorithm == "BatchSVD")
{
PerformAction<BatchSVDPolicy>(dataset, rank, maxIterations, minResidue);
}
else if (algorithm == "SVDIncompleteIncremental")
{
PerformAction<SVDIncompletePolicy>(dataset, rank, maxIterations,
minResidue);
}
else if (algorithm == "SVDCompleteIncremental")
{
PerformAction<SVDCompletePolicy>(dataset, rank, maxIterations, minResidue);
}
else if (algorithm == "RegSVD")
{
ReportIgnoredParam("min_residue", "Regularized SVD terminates only "
"when max_iterations is reached");
PerformAction<RegSVDPolicy>(dataset, rank, maxIterations, minResidue);
}
else if (algorithm == "RandSVD")
{
ReportIgnoredParam("min_residue", "Randomized SVD terminates only "
"when max_iterations is reached");
PerformAction<RandomizedSVDPolicy>(dataset, rank, maxIterations,
minResidue);
}
else if (algorithm == "BiasSVD")
{
ReportIgnoredParam("min_residue", "Bias SVD terminates only "
"when max_iterations is reached");
PerformAction<BiasSVDPolicy>(dataset, rank, maxIterations, minResidue);
}
else if (algorithm == "SVDPP")
{
ReportIgnoredParam("min_residue", "SVD++ terminates only "
"when max_iterations is reached");
PerformAction<SVDPlusPlusPolicy>(dataset, rank, maxIterations, minResidue);
}
}
static void mlpackMain()
{
if (IO::GetParam<int>("seed") == 0)
@@ -496,6 +223,7 @@ static void mlpackMain()
"recommendations must be positive");
// Either load from a model, or train a model.
CFModel* cf;
if (IO::HasParam("training"))
{
// Train a model.
@@ -523,23 +251,179 @@ static void mlpackMain()
// Get parameters.
const size_t rank = (size_t) IO::GetParam<int>("rank");
cf = new CFModel();
// Perform decomposition to prepare for recommendations.
Log::Info << "Performing CF matrix decomposition on dataset..." << endl;
const string algo = IO::GetParam<string>("algorithm");
if (algo == "NMF")
{
cf->DecompositionType() = CFModel::NMF;
}
else if (algo == "BatchSVD")
{
cf->DecompositionType() = CFModel::BATCH_SVD;
}
else if (algo == "SVDIncompleteIncremental")
{
cf->DecompositionType() = CFModel::SVD_INCOMPLETE;
}
else if (algo == "SVDCompleteIncremental")
{
cf->DecompositionType() = CFModel::SVD_COMPLETE;
}
else if (algo == "RegSVD")
{
ReportIgnoredParam("min_residue", "Regularized SVD terminates only "
"when max_iterations is reached");
cf->DecompositionType() = CFModel::REG_SVD;
}
else if (algo == "RandSVD")
{
ReportIgnoredParam("min_residue", "Randomized SVD terminates only "
"when max_iterations is reached");
cf->DecompositionType() = CFModel::RANDOMIZED_SVD;
}
else if (algo == "BiasSVD")
{
ReportIgnoredParam("min_residue", "Bias SVD terminates only "
"when max_iterations is reached");
cf->DecompositionType() = CFModel::BIAS_SVD;
}
else if (algo == "SVDPP")
{
ReportIgnoredParam("min_residue", "SVD++ terminates only "
"when max_iterations is reached");
cf->DecompositionType() = CFModel::SVD_PLUS_PLUS;
}
// Perform the factorization and do whatever the user wanted.
AssembleFactorizerType(algo, dataset, rank);
const size_t neighborhood = (size_t) IO::GetParam<int>("neighborhood");
// Make sure the normalization strategy is valid.
RequireParamInSet<string>("normalization", { "overall_mean", "item_mean",
"user_mean", "z_score", "none" }, true, "unknown normalization type");
const string normalizationType = IO::GetParam<string>("normalization");
if (normalizationType == "none")
cf->NormalizationType() = CFModel::NO_NORMALIZATION;
else if (normalizationType == "item_mean")
cf->NormalizationType() = CFModel::ITEM_MEAN_NORMALIZATION;
else if (normalizationType == "user_mean")
cf->NormalizationType() = CFModel::USER_MEAN_NORMALIZATION;
else if (normalizationType == "overall_mean")
cf->NormalizationType() = CFModel::OVERALL_MEAN_NORMALIZATION;
else if (normalizationType == "z_score")
cf->NormalizationType() = CFModel::Z_SCORE_NORMALIZATION;
cf->Train(dataset,
neighborhood,
rank,
size_t(IO::GetParam<int>("max_iterations")),
IO::GetParam<double>("min_residue"),
IO::HasParam("iteration_only_termination"));
}
else
{
// Load from a model after validating parameters.
RequireAtLeastOnePassed({ "query", "all_user_recommendations",
"test" }, true);
RequireAtLeastOnePassed({ "query", "all_user_recommendations", "test" },
true);
// Load an input model.
CFModel* c = std::move(IO::GetParam<CFModel*>("input_model"));
PerformAction(c);
cf = std::move(IO::GetParam<CFModel*>("input_model"));
}
// Get the types of the neighbor search method and the interpolation. (These
// may or may not be used.)
NeighborSearchTypes nsType;
RequireParamInSet<string>("neighbor_search", { "cosine",
"euclidean", "pearson" }, true, "unknown neighbor search algorithm");
if (IO::GetParam<std::string>("neighbor_search") == "cosine")
nsType = COSINE_SEARCH;
else if (IO::GetParam<std::string>("neighbor_search") == "euclidean")
nsType = EUCLIDEAN_SEARCH;
else // if (IO::GetParam<std::string>("neighbor_search") == "pearson")
nsType = PEARSON_SEARCH;
InterpolationTypes interpolationType;
RequireParamInSet<string>("interpolation", { "average",
"regression", "similarity" }, true, "unknown interpolation algorithm");
if (IO::GetParam<std::string>("interpolation") == "average")
interpolationType = AVERAGE_INTERPOLATION;
else if (IO::GetParam<std::string>("interpolation") == "regression")
interpolationType = REGRESSION_INTERPOLATION;
else // if (IO::GetParam<std::string>("interpolation") == "similarity")
interpolationType = SIMILARITY_INTERPOLATION;
if (IO::HasParam("query") || IO::HasParam("all_user_recommendations"))
{
// Get parameters for generating recommendations.
const size_t numRecs = (size_t) IO::GetParam<int>("recommendations");
// Get the recommendations.
arma::Mat<size_t> recommendations;
// Reading users.
if (IO::HasParam("query"))
{
// User matrix.
arma::Mat<size_t> users =
std::move(IO::GetParam<arma::Mat<size_t>>("query"));
if (users.n_rows > 1)
{
users = users.t();
}
if (users.n_rows > 1)
{
Log::Fatal << "List of query users must be one-dimensional!"
<< std::endl;
}
Log::Info << "Generating recommendations for " << users.n_elem
<< " users." << endl;
cf->GetRecommendations(nsType, interpolationType, numRecs,
recommendations, users.row(0).t());
}
else
{
Log::Info << "Generating recommendations for all users." << endl;
cf->GetRecommendations(nsType, interpolationType, numRecs,
recommendations);
}
// Save the output.
IO::GetParam<arma::Mat<size_t>>("output") = recommendations;
}
if (IO::HasParam("test"))
{
// Now, compute each test point.
arma::mat testData = std::move(IO::GetParam<arma::mat>("test"));
// Assemble the combination matrix to get RMSE value.
arma::Mat<size_t> combinations(2, testData.n_cols);
for (size_t i = 0; i < testData.n_cols; ++i)
{
combinations(0, i) = size_t(testData(0, i));
combinations(1, i) = size_t(testData(1, i));
}
// Now compute the RMSE.
arma::vec predictions;
cf->Predict(nsType, interpolationType, combinations, predictions);
// Compute the root of the sum of the squared errors, divide by the number
// of points to get the RMSE. It turns out this is just the L2-norm divided
// by the square root of the number of points, if we interpret the
// predictions and the true values as vectors.
const double rmse = arma::norm(predictions - testData.row(2).t(), 2) /
std::sqrt((double) testData.n_cols);
Log::Info << "RMSE is " << rmse << "." << endl;
}
IO::GetParam<CFModel*>("output_model") = cf;
}
+207
View File
@@ -0,0 +1,207 @@
/**
* @file methods/cf/cf_model_impl.hpp
* @author Wenhao Huang
*
* A serializable CF model, used by the main program.
*
* 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.
*/
#include "cf_model.hpp"
namespace mlpack {
namespace cf {
CFModel::CFModel() :
decompositionType(NMF),
normalizationType(NO_NORMALIZATION),
cf(NULL)
{
// Nothing else to do.
}
CFModel::CFModel(const CFModel& other) :
decompositionType(other.decompositionType),
normalizationType(other.normalizationType),
cf(other.cf->Clone())
{
// Nothing else to do.
}
CFModel::CFModel(CFModel&& other) :
decompositionType(other.decompositionType),
normalizationType(other.normalizationType),
cf(std::move(other.cf))
{
// Reset properties of the other one.
other.decompositionType = NMF;
other.normalizationType = NO_NORMALIZATION;
}
CFModel& CFModel::operator=(const CFModel& other)
{
if (this != &other)
{
decompositionType = other.decompositionType;
normalizationType = other.normalizationType;
cf = other.cf->Clone();
}
return *this;
}
CFModel& CFModel::operator=(CFModel&& other)
{
if (this != &other)
{
decompositionType = other.decompositionType;
normalizationType = other.normalizationType;
cf = std::move(other.cf);
// Reset the other object.
other.decompositionType = NMF;
other.normalizationType = NO_NORMALIZATION;
}
return *this;
}
CFModel::~CFModel()
{
delete cf;
}
template<typename DecompositionPolicy>
CFWrapperBase* TrainHelper(const DecompositionPolicy& decomposition,
const CFModel::NormalizationTypes normalizationType,
const arma::mat& data,
const size_t numUsersForSimilarity,
const size_t rank,
const size_t maxIterations,
const double minResidue,
const bool mit)
{
switch (normalizationType)
{
case CFModel::NO_NORMALIZATION:
return new CFWrapper<DecompositionPolicy, NoNormalization>(data,
decomposition, numUsersForSimilarity, rank, maxIterations, minResidue,
mit);
break;
case CFModel::ITEM_MEAN_NORMALIZATION:
return new CFWrapper<DecompositionPolicy, ItemMeanNormalization>(data,
decomposition, numUsersForSimilarity, rank, maxIterations, minResidue,
mit);
break;
case CFModel::USER_MEAN_NORMALIZATION:
return new CFWrapper<DecompositionPolicy, UserMeanNormalization>(data,
decomposition, numUsersForSimilarity, rank, maxIterations, minResidue,
mit);
break;
case CFModel::OVERALL_MEAN_NORMALIZATION:
return new CFWrapper<DecompositionPolicy, OverallMeanNormalization>(data,
decomposition, numUsersForSimilarity, rank, maxIterations, minResidue,
mit);
break;
case CFModel::Z_SCORE_NORMALIZATION:
return new CFWrapper<DecompositionPolicy, ZScoreNormalization>(data,
decomposition, numUsersForSimilarity, rank, maxIterations, minResidue,
mit);
break;
}
// This shouldn't ever happen.
return NULL;
}
void CFModel::Train(const arma::mat& data,
const size_t numUsersForSimilarity,
const size_t rank,
const size_t maxIterations,
const double minResidue,
const bool mit)
{
// Delete the current CFType object, if there is one.
delete cf;
switch (decompositionType)
{
case NMF:
cf = TrainHelper(NMFPolicy(), normalizationType, data,
numUsersForSimilarity, rank, maxIterations, minResidue, mit);
break;
case BATCH_SVD:
cf = TrainHelper(BatchSVDPolicy(), normalizationType, data,
numUsersForSimilarity, rank, maxIterations, minResidue, mit);
break;
case RANDOMIZED_SVD:
cf = TrainHelper(RandomizedSVDPolicy(), normalizationType, data,
numUsersForSimilarity, rank, maxIterations, minResidue, mit);
break;
case REG_SVD:
cf = TrainHelper(RegSVDPolicy(), normalizationType, data,
numUsersForSimilarity, rank, maxIterations, minResidue, mit);
break;
case SVD_COMPLETE:
cf = TrainHelper(SVDCompletePolicy(), normalizationType, data,
numUsersForSimilarity, rank, maxIterations, minResidue, mit);
break;
case SVD_INCOMPLETE:
cf = TrainHelper(SVDIncompletePolicy(), normalizationType, data,
numUsersForSimilarity, rank, maxIterations, minResidue, mit);
break;
case BIAS_SVD:
cf = TrainHelper(BiasSVDPolicy(), normalizationType, data,
numUsersForSimilarity, rank, maxIterations, minResidue, mit);
break;
case SVD_PLUS_PLUS:
cf = TrainHelper(SVDPlusPlusPolicy(), normalizationType, data,
numUsersForSimilarity, rank, maxIterations, minResidue, mit);
break;
}
}
//! Make predictions.
void CFModel::Predict(const NeighborSearchTypes nsType,
const InterpolationTypes interpolationType,
const arma::Mat<size_t>& combinations,
arma::vec& predictions)
{
cf->Predict(nsType, interpolationType, combinations, predictions);
}
//! Compute recommendations for queried users.
void CFModel::GetRecommendations(const NeighborSearchTypes nsType,
const InterpolationTypes interpolationType,
const size_t numRecs,
arma::Mat<size_t>& recommendations,
const arma::Col<size_t>& users)
{
cf->GetRecommendations(nsType, interpolationType, numRecs, recommendations,
users);
}
//! Compute recommendations for all users.
void CFModel::GetRecommendations(const NeighborSearchTypes nsType,
const InterpolationTypes interpolationType,
const size_t numRecs,
arma::Mat<size_t>& recommendations)
{
cf->GetRecommendations(nsType, interpolationType, numRecs, recommendations);
}
} // namespace cf
} // namespace mlpack
+189 -136
View File
@@ -14,105 +14,146 @@
#define MLPACK_METHODS_CF_CF_MODEL_HPP
#include <mlpack/core.hpp>
#include <boost/variant.hpp>
#include "cf.hpp"
#include <mlpack/methods/cf/decomposition_policies/batch_svd_method.hpp>
#include <mlpack/methods/cf/decomposition_policies/randomized_svd_method.hpp>
#include <mlpack/methods/cf/decomposition_policies/regularized_svd_method.hpp>
#include <mlpack/methods/cf/decomposition_policies/svd_complete_method.hpp>
#include <mlpack/methods/cf/decomposition_policies/svd_incomplete_method.hpp>
#include <mlpack/methods/cf/decomposition_policies/bias_svd_method.hpp>
#include <mlpack/methods/cf/decomposition_policies/svdplusplus_method.hpp>
#include <mlpack/methods/cf/normalization/no_normalization.hpp>
#include <mlpack/methods/cf/normalization/overall_mean_normalization.hpp>
#include <mlpack/methods/cf/normalization/user_mean_normalization.hpp>
#include <mlpack/methods/cf/normalization/item_mean_normalization.hpp>
#include <mlpack/methods/cf/normalization/z_score_normalization.hpp>
namespace mlpack {
namespace cf {
/**
* DeleteVisitor deletes the CFType<> object which is pointed to by the
* variable cf in class CFModel.
* NeighborSearchTypes contains the set of NeighborSearchPolicy classes that are
* usable by CFModel at prediction time.
*/
class DeleteVisitor : public boost::static_visitor<void>
enum NeighborSearchTypes
{
public:
//! Delete CFType object.
template <typename DecompositionPolicy,
typename NormalizationType = NoNormalization>
void operator()(CFType<DecompositionPolicy, NormalizationType>* c) const;
COSINE_SEARCH,
EUCLIDEAN_SEARCH,
PEARSON_SEARCH
};
/**
* GetValueVisitor returns the pointer which points to the CFType object.
* InterpolationTypes contains the set of InterpolationPolicy classes that are
* usable by CFModel at prediction time.
*/
class GetValueVisitor : public boost::static_visitor<void*>
enum InterpolationTypes
{
public:
//! Return stored pointer as void* type.
template <typename DecompositionPolicy,
typename NormalizationType = NoNormalization>
void* operator()(CFType<DecompositionPolicy, NormalizationType>* c) const;
AVERAGE_INTERPOLATION,
REGRESSION_INTERPOLATION,
SIMILARITY_INTERPOLATION
};
/**
* PredictVisitor uses the CFType object to make predictions on the given
* combinations of users and items.
* The CFWrapperBase class provides a unified interface that can be used by the
* CFModel class to interact with all different CF types at runtime. All CF
* wrapper types inherit from this base class.
*/
template <typename NeighborSearchPolicy,
typename InterpolationPolicy>
class PredictVisitor : public boost::static_visitor<void>
class CFWrapperBase
{
private:
//! User/item combinations to predict.
const arma::Mat<size_t>& combinations;
//! Predicted ratings for each user/item combination.
arma::vec& predictions;
public:
//! Predict ratings for each user-item combination.
template <typename DecompositionPolicy,
typename NormalizationType = NoNormalization>
void operator()(CFType<DecompositionPolicy, NormalizationType>* c) const;
//! Create the object. The base class has nothing to hold.
CFWrapperBase() { }
//! Visitor constructor.
PredictVisitor(const arma::Mat<size_t>& combinations,
arma::vec& predictions);
//! Make a copy of the object.
virtual CFWrapperBase* Clone() const = 0;
//! Delete the object.
virtual ~CFWrapperBase() { }
//! Compute predictions for users.
virtual void Predict(const NeighborSearchTypes nsType,
const InterpolationTypes interpolationType,
const arma::Mat<size_t>& combinations,
arma::vec& predictions) = 0;
//! Compute recommendations for all users.
virtual void GetRecommendations(
const NeighborSearchTypes nsType,
const InterpolationTypes interpolationType,
const size_t numRecs,
arma::Mat<size_t>& recommendations) = 0;
//! Compute recommendations.
virtual void GetRecommendations(
const NeighborSearchTypes nsType,
const InterpolationTypes interpolationType,
const size_t numRecs,
arma::Mat<size_t>& recommendations,
const arma::Col<size_t>& users) = 0;
};
/**
* RecommendationVisitor uses the CFType object to get recommendations for the
* given users.
* The CFWrapper class wraps the functionality of all CF types. If special
* handling is needed for a future CF type, this class can be extended.
*/
template <typename NeighborSearchPolicy,
typename InterpolationPolicy>
class RecommendationVisitor : public boost::static_visitor<void>
template<typename DecompositionPolicy, typename NormalizationPolicy>
class CFWrapper : public CFWrapperBase
{
private:
//! Number of Recommendations.
const size_t numRecs;
//! Recommendations matrix to save recommendations.
arma::Mat<size_t>& recommendations;
//! Users for which recommendations are to be generated.
const arma::Col<size_t>& users;
//! Whether users are given.
const bool usersGiven;
protected:
typedef CFType<DecompositionPolicy, NormalizationPolicy> CFModelType;
public:
//! Visitor constructor.
RecommendationVisitor(const size_t numRecs,
arma::Mat<size_t>& recommendations,
const arma::Col<size_t>& users,
const bool usersGiven);
//! Create the CFWrapper object, using default parameters to initialize the
//! held CF object.
CFWrapper() { }
//! Generates the given number of recommendations.
template <typename DecompositionPolicy,
typename NormalizationType = NoNormalization>
void operator()(CFType<DecompositionPolicy, NormalizationType>* c) const;
//! Create the CFWrapper object, initializing the held CF object.
CFWrapper(const arma::mat& data,
const DecompositionPolicy& decomposition,
const size_t numUsersForSimilarity,
const size_t rank,
const size_t maxIterations,
const size_t minResidue,
const bool mit) :
cf(data,
decomposition,
numUsersForSimilarity,
rank,
maxIterations,
minResidue,
mit)
{
// Nothing else to do.
}
//! Clone the CFWrapper object. This handles polymorphism correctly.
virtual CFWrapper* Clone() const { return new CFWrapper(*this); }
//! Destroy the CFWrapper object.
virtual ~CFWrapper() { }
//! Get the CFType object.
CFModelType& CF() { return cf; }
//! Compute predictions for users.
virtual void Predict(const NeighborSearchTypes nsType,
const InterpolationTypes interpolationType,
const arma::Mat<size_t>& combinations,
arma::vec& predictions);
//! Compute recommendations for all users.
virtual void GetRecommendations(
const NeighborSearchTypes nsType,
const InterpolationTypes interpolationType,
const size_t numRecs,
arma::Mat<size_t>& recommendations);
//! Compute recommendations.
virtual void GetRecommendations(
const NeighborSearchTypes nsType,
const InterpolationTypes interpolationType,
const size_t numRecs,
arma::Mat<size_t>& recommendations,
const arma::Col<size_t>& users);
//! Serialize the model.
template<typename Archive>
void serialize(Archive& ar, const uint32_t /* version */)
{
ar(CEREAL_NVP(cf));
}
protected:
//! This is the CF object that we are wrapping.
CFModelType cf;
};
/**
@@ -120,98 +161,110 @@ class RecommendationVisitor : public boost::static_visitor<void>
*/
class CFModel
{
public:
enum DecompositionTypes
{
NMF,
BATCH_SVD,
RANDOMIZED_SVD,
REG_SVD,
SVD_COMPLETE,
SVD_INCOMPLETE,
BIAS_SVD,
SVD_PLUS_PLUS
};
enum NormalizationTypes
{
NO_NORMALIZATION,
ITEM_MEAN_NORMALIZATION,
USER_MEAN_NORMALIZATION,
OVERALL_MEAN_NORMALIZATION,
Z_SCORE_NORMALIZATION
};
private:
//! The current decomposition policy type.
DecompositionTypes decompositionType;
//! The current normalization policy type.
NormalizationTypes normalizationType;
/**
* cf holds an instance of the CFType class for the current
* decompositionPolicy and normalizationType. It is initialized every time
* Train() is executed. We access to the contained value through the visitor
* classes defined above.
* Train() is executed.
*/
boost::variant<CFType<NMFPolicy, NoNormalization>*,
CFType<BatchSVDPolicy, NoNormalization>*,
CFType<RandomizedSVDPolicy, NoNormalization>*,
CFType<RegSVDPolicy, NoNormalization>*,
CFType<SVDCompletePolicy, NoNormalization>*,
CFType<SVDIncompletePolicy, NoNormalization>*,
CFType<BiasSVDPolicy, NoNormalization>*,
CFType<SVDPlusPlusPolicy, NoNormalization>*,
CFType<NMFPolicy, ItemMeanNormalization>*,
CFType<BatchSVDPolicy, ItemMeanNormalization>*,
CFType<RandomizedSVDPolicy, ItemMeanNormalization>*,
CFType<RegSVDPolicy, ItemMeanNormalization>*,
CFType<SVDCompletePolicy, ItemMeanNormalization>*,
CFType<SVDIncompletePolicy, ItemMeanNormalization>*,
CFType<BiasSVDPolicy, ItemMeanNormalization>*,
CFType<SVDPlusPlusPolicy, ItemMeanNormalization>*,
CFType<NMFPolicy, UserMeanNormalization>*,
CFType<BatchSVDPolicy, UserMeanNormalization>*,
CFType<RandomizedSVDPolicy, UserMeanNormalization>*,
CFType<RegSVDPolicy, UserMeanNormalization>*,
CFType<SVDCompletePolicy, UserMeanNormalization>*,
CFType<SVDIncompletePolicy, UserMeanNormalization>*,
CFType<BiasSVDPolicy, UserMeanNormalization>*,
CFType<SVDPlusPlusPolicy, UserMeanNormalization>*,
CFType<NMFPolicy, OverallMeanNormalization>*,
CFType<BatchSVDPolicy, OverallMeanNormalization>*,
CFType<RandomizedSVDPolicy, OverallMeanNormalization>*,
CFType<RegSVDPolicy, OverallMeanNormalization>*,
CFType<SVDCompletePolicy, OverallMeanNormalization>*,
CFType<SVDIncompletePolicy, OverallMeanNormalization>*,
CFType<BiasSVDPolicy, OverallMeanNormalization>*,
CFType<SVDPlusPlusPolicy, OverallMeanNormalization>*,
CFType<NMFPolicy, ZScoreNormalization>*,
CFType<BatchSVDPolicy, ZScoreNormalization>*,
CFType<RandomizedSVDPolicy, ZScoreNormalization>*,
CFType<RegSVDPolicy, ZScoreNormalization>*,
CFType<SVDCompletePolicy, ZScoreNormalization>*,
CFType<SVDIncompletePolicy, ZScoreNormalization>*,
CFType<BiasSVDPolicy, ZScoreNormalization>*,
CFType<SVDPlusPlusPolicy, ZScoreNormalization>*> cf;
CFWrapperBase* cf;
public:
//! Create an empty CF model.
CFModel() { }
CFModel();
//! Create a CF model by copying the given model.
CFModel(const CFModel& other);
//! Create a CF model by taking ownership of the data of the other model.
CFModel(CFModel&& other);
//! Make this CF model a copy of the other model.
CFModel& operator=(const CFModel& other);
//! Make this CF model take ownership of the data of the other model.
CFModel& operator=(CFModel&& other);
//! Clean up memory.
~CFModel();
//! Get the pointer to CFType<> object.
template <typename DecompositionPolicy,
typename NormalizationType = NoNormalization>
const CFType<DecompositionPolicy, NormalizationType>* CFPtr() const;
//! Get the CFWrapperBase object. (Be careful!)
CFWrapperBase* CF() const { return cf; }
//! Get the decomposition type.
const DecompositionTypes& DecompositionType() const
{
return decompositionType;
}
//! Set the decomposition type.
DecompositionTypes& DecompositionType()
{
return decompositionType;
}
//! Get the normalization type.
const NormalizationTypes& NormalizationType() const
{
return normalizationType;
}
//! Set the normalization type.
NormalizationTypes& NormalizationType()
{
return normalizationType;
}
//! Train the model.
template<typename DecompositionPolicy,
typename MatType>
void Train(const MatType& data,
void Train(const arma::mat& data,
const size_t numUsersForSimilarity,
const size_t rank,
const size_t maxIterations,
const double minResidue,
const bool mit,
const std::string& normalizationType = "none");
const bool mit);
//! Make predictions.
template <typename NeighborSearchPolicy,
typename InterpolationPolicy>
void Predict(const arma::Mat<size_t>& combinations,
void Predict(const NeighborSearchTypes nsType,
const InterpolationTypes interpolationType,
const arma::Mat<size_t>& combinations,
arma::vec& predictions);
//! Compute recommendations for query users.
template<typename NeighborSearchPolicy,
typename InterpolationPolicy>
void GetRecommendations(const size_t numRecs,
void GetRecommendations(const NeighborSearchTypes nsType,
const InterpolationTypes interpolationType,
const size_t numRecs,
arma::Mat<size_t>& recommendations,
const arma::Col<size_t>& users);
//! Compute recommendations for all users.
template<typename NeighborSearchPolicy,
typename InterpolationPolicy>
void GetRecommendations(const size_t numRecs,
void GetRecommendations(const NeighborSearchTypes nsType,
const InterpolationTypes interpolationType,
const size_t numRecs,
arma::Mat<size_t>& recommendations);
//! Serialize the model.

Some files were not shown because too many files have changed in this diff Show More