Merge branch 'master' into msi-install-headers

This commit is contained in:
Ryan Curtin
2024-09-04 11:58:28 -04:00
committed by GitHub
152 changed files with 4200 additions and 2015 deletions
+8 -10
View File
@@ -19,16 +19,15 @@ jobs:
# RAM usage.
CMakeArgs: '-DDEBUG=ON -DPROFILE=OFF -DBUILD_TESTS=ON -DBUILD_PYTHON_BINDINGS=OFF -DBUILD_JULIA_BINDINGS=OFF -DBUILD_GO_BINDINGS=OFF -DBUILD_R_BINDINGS=OFF -DUSE_PRECOMPILED_HEADERS=OFF'
Python:
CMakeArgs: '-DDEBUG=OFF -DPROFILE=OFF -DBUILD_TESTS=ON -DBUILD_PYTHON_BINDINGS=ON -DPYTHON_EXECUTABLE=/usr/bin/python3 -DBUILD_GO_BINDINGS=OFF -DBUILD_JULIA_BINDINGS=OFF -DBUILD_R_BINDINGS=OFF'
binding: 'python'
python.version: '3.7'
CMakeArgs: '-DDEBUG=OFF -DPROFILE=OFF -DBUILD_TESTS=ON -DBUILD_PYTHON_BINDINGS=ON -DPYTHON_EXECUTABLE=/usr/bin/python3 -DBUILD_GO_BINDINGS=OFF -DBUILD_JULIA_BINDINGS=OFF -DBUILD_R_BINDINGS=OFF'
Julia:
julia.version: '1.3.0'
CMakeArgs: '-DDEBUG=OFF -DPROFILE=OFF -DBUILD_TESTS=ON -DBUILD_PYTHON_BINDINGS=OFF -DBUILD_JULIA_BINDINGS=ON -DBUILD_GO_BINDINGS=OFF -DJULIA_EXECUTABLE=/opt/julia-1.6.3/bin/julia -DBUILD_R_BINDINGS=OFF'
CMakeArgs: '-DDEBUG=OFF -DPROFILE=OFF -DBUILD_TESTS=ON -DBUILD_PYTHON_BINDINGS=OFF -DBUILD_JULIA_BINDINGS=ON -DBUILD_GO_BINDINGS=OFF -DJULIA_EXECUTABLE=/opt/julia-1.10.4/bin/julia -DBUILD_R_BINDINGS=OFF'
binding: 'julia'
Go:
binding: 'go'
go.version: '1.11.0'
CMakeArgs: '-DDEBUG=OFF -DPROFILE=OFF -DBUILD_TESTS=ON -DBUILD_PYTHON_BINDINGS=OFF -DBUILD_JULIA_BINDINGS=OFF -DBUILD_GO_BINDINGS=ON -DBUILD_R_BINDINGS=OFF'
binding: 'go'
Markdown:
CMakeArgs: '-DDEBUG=OFF -DPROFILE=OFF -DBUILD_TESTS=ON -DBUILD_MARKDOWN_BINDINGS=ON -DBUILD_PYTHON_BINDINGS=OFF -DBUILD_GO_BINDINGS=OFF -DBUILD_JULIA_BINDINGS=OFF -DBUILD_R_BINDINGS=OFF'
@@ -44,20 +43,19 @@ jobs:
# clang on OS X segfaults when using precompiled headers, so we disable
# them.
Plain:
python.version: '3.8'
CMakeArgs: '-DDEBUG=ON -DPROFILE=OFF -DBUILD_TESTS=ON -DBUILD_PYTHON_BINDINGS=OFF -DBUILD_JULIA_BINDINGS=OFF -DBUILD_GO_BINDINGS=OFF -DBUILD_R_BINDINGS=OFF -DUSE_PRECOMPILED_HEADERS=OFF'
python.version: '3.8'
Python:
binding: 'python'
python.version: '3.8'
binding: 'python'
CMakeArgs: '-DDEBUG=ON -DPROFILE=OFF -DBUILD_TESTS=ON -DBUILD_PYTHON_BINDINGS=ON -DBUILD_JULIA_BINDINGS=OFF -DBUILD_GO_BINDINGS=OFF -DBUILD_R_BINDINGS=OFF -DUSE_PRECOMPILED_HEADERS=OFF'
Julia:
python.version: '3.8'
julia.version: '1.6.3'
binding: 'julia'
CMakeArgs: '-DDEBUG=ON -DPROFILE=OFF -DBUILD_TESTS=ON -DBUILD_JULIA_BINDINGS=ON -DBUILD_PYTHON_BINDINGS=OFF -DBUILD_GO_BINDINGS=OFF -DBUILD_R_BINDINGS=OFF -DUSE_PRECOMPILED_HEADERS=OFF'
Go:
binding: 'go'
python.version: '3.8'
go.version: '1.11.0'
binding: 'go'
CMakeArgs: '-DDEBUG=ON -DPROFILE=OFF -DBUILD_TESTS=ON -DBUILD_PYTHON_BINDINGS=OFF -DBUILD_JULIA_BINDINGS=OFF -DBUILD_GO_BINDINGS=ON -DBUILD_R_BINDINGS=OFF -DUSE_PRECOMPILED_HEADERS=OFF'
steps:
+11 -12
View File
@@ -7,7 +7,8 @@ steps:
# Set python version
- task: UsePythonVersion@0
inputs:
versionSpec: '3.7'
versionSpec: '$(python.version)'
condition: ne(variables['python.version'], '')
# Install build dependencies.
- script: |
@@ -24,19 +25,18 @@ steps:
sudo apt-get install -y --allow-unauthenticated libopenblas-dev g++ xz-utils
if [ "$(binding)" == "python" ]; then
export PYBIN=$(which python)
$PYBIN -m pip install --upgrade pip
$PYBIN -m pip install --upgrade --ignore-installed setuptools cython pandas wheel
if [ "$BINDING" = "python" ]; then
python -m pip install --upgrade pip
python -m pip install --upgrade --ignore-installed setuptools cython pandas wheel
fi
if [ "a$(julia.version)" != "a" ]; then
wget https://julialang-s3.julialang.org/bin/linux/x64/1.6/julia-1.6.3-linux-x86_64.tar.gz
sudo tar -C /opt/ -xvpf julia-1.6.3-linux-x86_64.tar.gz
if [ "$BINDING" = "julia" ]; then
wget https://julialang-s3.julialang.org/bin/linux/x64/1.10/julia-1.10.4-linux-x86_64.tar.gz
sudo tar -C /opt/ -xvpf julia-1.10.4-linux-x86_64.tar.gz
fi
# Install armadillo.
curl -k -L https://sourceforge.net/projects/arma/files/armadillo-9.800.6.tar.xz | tar -xvJ && \
curl -k -L https://sourceforge.net/projects/arma/files/armadillo-10.8.2.tar.xz | tar -xvJ && \
cd armadillo* && \
cmake . && \
make && \
@@ -68,14 +68,13 @@ steps:
# Configure mlpack (CMake)
- script: |
unset BOOST_ROOT
mkdir build && cd build
if [ "$(binding)" == "go" ]; then
if [ "$BINDING" = "go" ]; then
export GOPATH=$PWD/src/mlpack/bindings/go
export GO111MODULE=off
go get -u -t gonum.org/v1/gonum/...
fi
cmake $(CMakeArgs) -DPYTHON_EXECUTABLE=`which python` -DCEREAL_INCLUDE_DIR=/usr/include/ ..
cmake $CMAKEARGS -DPYTHON_EXECUTABLE=`which python` -DCEREAL_INCLUDE_DIR=/usr/include/ ..
displayName: 'CMake'
# Build mlpack
+6 -7
View File
@@ -15,12 +15,12 @@ steps:
sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer
brew install libomp openblas armadillo cereal ensmallen
if [ "$(binding)" == "python" ]; then
if [ "$BINDING" = "python" ]; then
pip install --upgrade pip
pip install cython numpy pandas zipp configparser wheel
fi
if [ "a$(julia.version)" != "a" ]; then
if [ "$BINDING" = "julia" ]; then
brew install --cask julia
fi
@@ -29,16 +29,15 @@ steps:
# Configure mlpack (CMake)
- script: |
mkdir build && cd build
if [ "$(binding)" == "go" ]; then
if [ "$BINDING" = "go" ]; then
export GOPATH=$PWD/src/mlpack/bindings/go
export GO111MODULE=off
go get -u -t gonum.org/v1/gonum/...
fi
if [ "$(binding)" == "python" ]; then
export PYPATH=$(which python)
cmake $(CMakeArgs) -DPYTHON_EXECUTABLE=$PYPATH ..
if [ "$BINDING" = "python" ]; then
cmake $CMAKEARGS -DPYTHON_EXECUTABLE=$(which python) ..
else
cmake $(CMakeArgs) ..
cmake $CMAKEARGS ..
fi
displayName: 'CMake'
+6 -6
View File
@@ -27,10 +27,10 @@ steps:
- bash: |
git clone --depth 1 https://github.com/mlpack/jenkins-conf.git conf
curl -O -L https://sourceforge.net/projects/arma/files/armadillo-9.800.6.tar.xz -o armadillo-9.800.6.tar.xz
tar -xvf armadillo-9.800.6.tar.xz
curl -O -L https://sourceforge.net/projects/arma/files/armadillo-10.8.2.tar.xz -o armadillo-10.8.2.tar.xz
tar -xvf armadillo-10.8.2.tar.xz
cd armadillo-9.800.6/ && cmake $(CMakeGenerator) \
cd armadillo-10.8.2/ && cmake $(CMakeGenerator) \
-DBLAS_LIBRARY:FILEPATH=$(Agent.ToolsDirectory)/OpenBLAS.0.2.14.1/lib/native/lib/x64/libopenblas.dll.a \
-DLAPACK_LIBRARY:FILEPATH=$(Agent.ToolsDirectory)/OpenBLAS.0.2.14.1/lib/native/lib/x64/libopenblas.dll.a \
-DCMAKE_PREFIX:FILEPATH=../../armadillo \
@@ -41,7 +41,7 @@ steps:
# Build armadillo
- task: MSBuild@1
inputs:
solution: 'armadillo-9.800.6/*.sln'
solution: 'armadillo-10.8.2/*.sln'
msbuildLocationMethod: 'location'
msbuildVersion: $(MSBuildVersion)
configuration: 'Release'
@@ -60,8 +60,8 @@ steps:
$(CMakeArgs) `
-DBLAS_LIBRARIES:FILEPATH=$(Agent.ToolsDirectory)\OpenBLAS.0.2.14.1\lib\native\lib\x64\libopenblas.dll.a `
-DLAPACK_LIBRARIES:FILEPATH=$(Agent.ToolsDirectory)\OpenBLAS.0.2.14.1\lib\native\lib\x64\libopenblas.dll.a `
-DARMADILLO_INCLUDE_DIR="..\armadillo-9.800.6\tmp\include" `
-DARMADILLO_LIBRARY="..\armadillo-9.800.6\Release\armadillo.lib" `
-DARMADILLO_INCLUDE_DIR="..\armadillo-10.8.2\tmp\include" `
-DARMADILLO_LIBRARY="..\armadillo-10.8.2\Release\armadillo.lib" `
-DCEREAL_INCLUDE_DIR="..\cereal-1.3.2\include" `
-DENSMALLEN_INCLUDE_DIR=$(Agent.ToolsDirectory)\ensmallen.2.17.0\installed\x64-linux\include `
-DBUILD_JULIA_BINDINGS=OFF `
+22
View File
@@ -0,0 +1,22 @@
# Once a PR has been approved by one member of the mlpack organization, a second
# approving review will automatically be added 24 hours later. This allows time
# for other maintainers to take a look.
name: Auto-approve pull requests
on:
schedule:
# Run roughly every four hours.
- cron: "15 0,4,8,12,16,20 * * *"
jobs:
auto-approve:
runs-on: ubuntu-latest
permissions:
pull-requests: write
steps:
- name: Auto-approve pull requests
uses: rcurtin/actions/auto-approve@v1
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
approval-message:
'Second approval provided automatically after 24 hours. :+1:'
+24
View File
@@ -0,0 +1,24 @@
name: Close inactive issues
on:
schedule:
- cron: "30 1 * * *"
jobs:
close-issues:
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
steps:
- uses: actions/stale@v9
with:
days-before-issues-stale: 30
days-before-issue-close: 7
stale-issue-label: "s: stale"
stale-pr-label: "s: stale"
stale-issue-message: "This issue has been automatically marked as stale because it has not had any recent activity. It will be closed in 7 days if no further activity occurs. Thank you for your contributions! :+1:"
days-before-pr-stale: 30,
days-before-pr-close: 14
repo-token: ${{ secrets.GITHUB_TOKEN }}
exempt-issue-labels: "s: keep open"
exempt-pr-labels: "s: keep open"
+17
View File
@@ -0,0 +1,17 @@
# Post a message to new contributors that they can get some stickers mailed to
# them.
name: 'Stickers for new contributors'
on:
pull_request:
types: [closed]
jobs:
sticker_comment:
runs-on: ubuntu-latest
if: github.event.pull_request.merged == true
steps:
# Forked version of first-interaction that runs only on first merged PR.
- uses: rcurtin/actions/stickers@v1
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
pr-message: "Hello there! Thanks for your contribution. Congratulations on your first contribution to mlpack! If you'd like to add your name to the list of contributors in `COPYRIGHT.txt` and you haven't already, please feel free to push a change to this PR---or, if it gets merged before you can, feel free to open another PR.\n\nIn addition, if you'd like some stickers to put on your laptop, we can get them in the mail for you. Just send an email with your physical mailing address to stickers@mlpack.org, and then one of the mlpack maintainers will put some stickers in an envelope for you. It may take a few weeks to get them, depending on your location. :+1:"
+16
View File
@@ -0,0 +1,16 @@
# Post a message to new contributors that they can get some stickers mailed to
# them.
name: 'Welcome message for new contributors'
on:
pull_request:
types: [open]
jobs:
sticker_comment:
runs-on: ubuntu-latest
if: github.event.pull_request.merged == true
steps:
- uses: actions/first-interaction@v1.3.0
with:
token: ${{ secrets.GITHUB_TOKEN }}
pr-message: "Thanks for opening your first pull request in this repository! Someone will review it when they have a chance. In the mean time, please be sure that you've handled the following things, to make the review process quicker and easier:\n\n - All code should follow the [style guide](https://github.com/mlpack/mlpack/wiki/DesignGuidelines#style-guidelines)\n - Documentation added for any new functionality\n - Tests added for any new functionality\n - Tests that are added follow the [testing guide](https://github.com/mlpack/mlpack/wiki/Testing-Guidelines)\n - Headers and license information added to the top of any new code files\n - HISTORY.md updated if the changes are big or user-facing\n - All CI checks should be passing\n\nThank you again for your contributions! :+1:"
+1
View File
@@ -28,6 +28,7 @@ macro(search_openblas version)
get_deps(https://github.com/xianyi/OpenBLAS/releases/download/v${version}/OpenBLAS-${version}.tar.gz OpenBLAS OpenBLAS-${version}.tar.gz)
if (NOT MSVC)
if (NOT EXISTS "${CMAKE_BINARY_DIR}/deps/OpenBLAS-${version}/libopenblas.a")
set(ENV{COMMON_OPT} "${CMAKE_OPENBLAS_FLAGS}") # Pass our flags to OpenBLAS
execute_process(COMMAND make TARGET=${OPENBLAS_TARGET} BINARY=${OPENBLAS_BINARY} HOSTCC=gcc CC=${CMAKE_C_COMPILER} FC=${CMAKE_FORTRAN_COMPILER} NO_SHARED=1
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/deps/OpenBLAS-${version})
endif()
+8 -4
View File
@@ -23,7 +23,7 @@ option(USE_PRECOMPILED_HEADERS "Use precompiled headers for mlpack_test build."
# For Armadillo, try to keep the minimum required version less than or equal to
# what's available on the current Ubuntu LTS or most recent stable RHEL release.
# See https://github.com/mlpack/mlpack/issues/3033 for some more discussion.
set(ARMADILLO_VERSION "9.800")
set(ARMADILLO_VERSION "10.8")
set(ENSMALLEN_VERSION "2.10.0")
set(CEREAL_VERSION "1.1.2")
@@ -249,8 +249,12 @@ if (DEBUG)
else()
add_definitions(-DNDEBUG)
if (NOT MSVC)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -O3")
if (NOT CMAKE_CROSSCOMPILING)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -O3")
else()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99")
endif()
else ()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /O3")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /O3")
@@ -283,7 +287,7 @@ endif()
# Download and compile OpenBLAS if we are cross compiling mlpack for a specific
# architecture. The function takes the version of OpenBLAS as variable.
if (CMAKE_CROSSCOMPILING)
search_openblas(0.3.13)
search_openblas(0.3.26)
endif()
if (NOT DOWNLOAD_DEPENDENCIES)
+12 -2
View File
@@ -4,9 +4,19 @@
_????-??-??_
* Distribute STB headers as part of R package (#3724, #3726).
* Added OpenMP support for fast approximation (#3685).
* Distribute STB headers as part of R package (#3724, #3726).
* Added OpenMP parallelization to Hamerly, Naive, and Elkan k-means (#3761, #3762, #3764).
* Added OpenMP support for fast approximation (#3685).
* Implemented the Find and Fill algorithm into the Dropout Layer and added OpenMP support (#3684).
* Update Python bindings to support NumPy 2.x (#3752).
* Bump minimum Armadillo version to 10.8 (#3760).
* Adapt `NearestInterpolation` ANN layer to new Layer Inteface (#3768).
## mlpack 4.4.0
+2 -2
View File
@@ -108,7 +108,7 @@ Citations are beneficial for the growth and improvement of mlpack.
**mlpack** requires the following additional dependencies:
- C++17 compiler
- [Armadillo](https://arma.sourceforge.net)   >= 9.800
- [Armadillo](https://arma.sourceforge.net)   >= 10.8
- [ensmallen](https://ensmallen.org)  >= 2.10.0
- [cereal](http://uscilab.github.io/cereal/)     >= 1.1.2
@@ -333,7 +333,7 @@ dependencies are installed:
- R >= 4.0
- Rcpp >= 0.12.12
- RcppArmadillo >= 0.9.800.0
- RcppArmadillo >= 0.10.8.0
- RcppEnsmallen >= 0.2.10.0
- roxygen2
- testthat
+47 -24
View File
@@ -4,63 +4,86 @@
# footprints.
# Set generic minimization flags for all platforms.
# These flags are the same for all cross-compilation cases.
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Os -fdata-sections -ffunction-sections")
# These flags are the same for all cross-compilation cases and they are
# mainly to reduce the binary footprint.
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Os -s -fdata-sections -ffunction-sections")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fomit-frame-pointer -fno-unwind-tables")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-asynchronous-unwind-tables -fvisibility=hidden")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fshort-enums -finline-small-functions")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -findirect-inlining -fno-common")
#-flto -fuse-ld=gold # There is an issue with gold link when compiling on
# Ubuntu 16. At that point gcc linker did not integrate the flto support
# inside and it was a separate plugin that need to be added. Therefore,
# this can be added when mlpack Azure CI moves toward Ubuntu 20.
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fmerge-all-constants -fno-ident")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-unroll-loops -fno-math-errno")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-stack-protector")
set(CMAKE_OPENBLAS_FLAGS "${CMAKE_CXX_FLAGS}") # OpenBLAS does not supoport flto
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -flto")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--hash-style=gnu -Wl,--build-id=none")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-z,norelro")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections")
## Keep the following flag in comment, they might be relevant in the case of MCU's
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wl,-nmagic,-Bsymbolic -nostartfiles")
set(BOARD_NAME "" CACHE STRING "Specify Board name to optimize for.")
string(TOUPPER ${BOARD_NAME} BOARD)
# Set specific platforms CMAKE CXX flags.
if(BOARD MATCHES "RPI0" OR BOARD MATCHES "RPI1")
if(BOARD MATCHES "RPI0" OR BOARD MATCHES "RPI1" OR BOARD MATCHES "ARM11")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mtune=arm1176jzf-s")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mcpu=arm1176jzf-s -mfloat-abi=hard -mfpu=vfp")
set(OPENBLAS_TARGET "ARMV6")
set(OPENBLAS_BINARY "32")
elseif(BOARD MATCHES "RPI2")
elseif(BOARD MATCHES "RPI2" OR BOARD MATCHES "CORTEXA7")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mtune=cortex-a7")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfloat-abi=hard -mfpu=neon-vfpv4")
set(OPENBLAS_TARGET "ARMV7")
set(OPENBLAS_BINARY "32")
elseif(BOARD MATCHES "RPI3")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mtune=cortex-a53")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections")
elseif(BOARD MATCHES "CORTEXA8")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mtune=cortex-a8")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfloat-abi=hard -mfpu=neon")
set(OPENBLAS_TARGET "ARMV7")
set(OPENBLAS_BINARY "32")
elseif(BOARD MATCHES "CORTEXA9")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mtune=cortex-a9")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfloat-abi=hard -mfpu=neon")
set(OPENBLAS_TARGET "CORTEXA9")
set(OPENBLAS_BINARY "32")
elseif(BOARD MATCHES "CORTEXA15")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mtune=cortex-a15")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfloat-abi=hard -mfpu=neon")
set(OPENBLAS_TARGET "CORTEXA15")
set(OPENBLAS_BINARY "32")
elseif(BOARD MATCHES "RPI3" OR BOARD MATCHES "CORTEXA53")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mtune=cortex-a53 -ftree-vectorize")
set(OPENBLAS_TARGET "CORTEXA53")
set(OPENBLAS_BINARY "64")
elseif(BOARD MATCHES "RPI4")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mtune=cortex-a72")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections")
elseif(BOARD MATCHES "RPI4" OR BOARD MATCHES "CORTEXA72")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mtune=cortex-a72 -ftree-vectorize")
set(OPENBLAS_TARGET "CORTEXA72")
set(OPENBLAS_BINARY "64")
elseif(BOARD MATCHES "JETSONAGX" OR BOARD MATCHES "CORTEXA76")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mtune=cortex-a76 -ftree-vectorize")
set(OPENBLAS_TARGET "CORTEXA76")
set(OPENBLAS_BINARY "64")
elseif(BOARD MATCHES "BV")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections")
set(OPENBLAS_TARGET "RISCV64_GENERIC")
set(OPENBLAS_BINARY "64")
elseif(BOARD MATCHES "JETSONAGX")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -matune=cortex-a76")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections")
set(OPENBLAS_TARGET "ARM8")
elseif(BOARD MATCHES "C906")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mtune=thead-c906")
set(OPENBLAS_TARGET "RISCV64_GENERIC")
set(OPENBLAS_BINARY "64")
elseif(BOARD MATCHES "x280")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mtune=sifive-x280")
set(OPENBLAS_TARGET "x280")
set(OPENBLAS_BINARY "64")
elseif(BOARD MATCHES "KATAMI")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=pentium3")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections")
set(OPENBLAS_TARGET "KATAMI")
set(OPENBLAS_BINARY "32")
elseif(BOARD MATCHES "COPPERMINE")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=pentium3")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections")
set(OPENBLAS_TARGET "COPPERMINE")
set(OPENBLAS_BINARY "32")
elseif(BOARD MATCHES "NORTHWOOD")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=pentium4")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections")
set(OPENBLAS_TARGET "NORTHWOOD")
set(OPENBLAS_BINARY "32")
elseif(BOARD)
+26 -1
View File
@@ -100,29 +100,54 @@ Predict continuous values.
### Clustering algorithms
***NOTE:*** this documentation is still under construction and so some
algorithms that mlpack implements are not yet listed here. For now, see
[the mlpack/methods directory](https://github.com/mlpack/mlpack/tree/master/src/mlpack/methods)
for a full list of algorithms.
Group points into clusters.
<!-- TODO: add some -->
* [`MeanShift`](user/methods/mean_shift.md): clustering with the density-based
mean shift algorithm
### Geometric algorithms
***NOTE:*** this documentation is still under construction and so no geometric
algorithms in mlpack are documented yet. For now, see
[the mlpack/methods directory](https://github.com/mlpack/mlpack/tree/master/src/mlpack/methods)
for a full list of algorithms.
Computations based on distance metrics.
<!-- TODO: add some -->
### Preprocessing utilities
***NOTE:*** this documentation is still under construction and so no
preprocessing utilities in mlpack are documented yet. For now, see
[the mlpack/methods/preprocess directory](https://github.com/mlpack/mlpack/tree/master/src/mlpack/methods)
for a full list of algorithms.
Prepare data for machine learning algorithms.
<!-- TODO: add some -->
### Transformations
***NOTE:*** this documentation is still under construction and so some
algorithms that mlpack implements are not yet listed here. For now, see
[the mlpack/methods directory](https://github.com/mlpack/mlpack/tree/master/src/mlpack/methods)
for a full list of algorithms.
Transform data from one space to another.
* [`AMF`](user/methods/amf.md): alternating matrix factorization
* [`LocalCoordinateCoding`](user/methods/local_coordinate_coding.md): local
coordinate coding with dictionary learning
* [`LMNN`](user/methods/lmnn.md): large margin nearest neighbor (distance
metric learning)
* [`NCA`](user/methods/nca.md): neighborhood components analysis (distance
metric learning)
* [`NMF`](user/methods/nmf.md): non-negative matrix factorization
* [`PCA`](user/methods/pca.md): principal components analysis
* [`SparseCoding`](user/methods/sparse_coding.md): sparse coding with
+1 -1
View File
@@ -24,7 +24,7 @@ sudo apt-get install libmlpack-dev
and on Fedora or Red Hat:
```sh
sudo dnf install mlpack
sudo dnf install mlpack-devel
```
You can also use a Docker image from Dockerhub,
+24 -3
View File
@@ -132,9 +132,20 @@ when the sidebar is built for each page.
<!-- Clustering algorithms -->
<li>
<a href="LINKROOTindex.html#clustering-algorithms">
Clustering
</a>
<details>
<summary>
<a href="LINKROOTindex.html#clustering-algorithms">
Clustering
</a>
</summary>
<ul>
<li>
<a href="LINKROOTuser/methods/mean_shift.html">
<code>MeanShift</code>
</a>
</li>
</ul>
</details>
</li>
<!-- Geometric algorithms -->
@@ -170,6 +181,16 @@ when the sidebar is built for each page.
<code>LocalCoordinateCoding</code>
</a>
</li>
<li>
<a href="LINKROOTuser/methods/lmnn.html">
<code>LMNN</code>
</a>
</li>
<li>
<a href="LINKROOTuser/methods/nca.html">
<code>NCA</code>
</a>
</li>
<li>
<a href="LINKROOTuser/methods/nmf.html">
<code>NMF</code>
+7 -7
View File
@@ -1677,9 +1677,9 @@ $ mlpack_linear_svm --input_model_file lsvm_model.bin --test_file test.csv
$ mlpack_lmnn [--batch_size 50] [--center] [--distance_file <string>]
[--help] [--info <string>] --input_file <string> [--k 1] [--labels_file
<string>] [--linear_scan] [--max_iterations 100000] [--normalize]
[--optimizer 'amsgrad'] [--passes 50] [--print_accuracy] [--range 1]
[--rank 0] [--regularization 0.5] [--seed 0] [--step_size 0.01]
[--tolerance 1e-07] [--verbose] [--version] [--centered_data_file
[--optimizer 'amsgrad'] [--passes 50] [--print_accuracy] [--rank 0]
[--regularization 0.5] [--seed 0] [--step_size 0.01] [--tolerance 1e-07]
[--update_interval 1] [--verbose] [--version] [--centered_data_file
<string>] [--output_file <string>] [--transformed_data_file <string>]
```
@@ -1706,12 +1706,12 @@ An implementation of Large Margin Nearest Neighbors (LMNN), a distance learning
| `--optimizer (-O)` | [`string`](#doc_string) | Optimizer to use; 'amsgrad', 'bbsgd', 'sgd', or 'lbfgs'. | `'amsgrad'` |
| `--passes (-p)` | [`int`](#doc_int) | Maximum number of full passes over dataset for AMSGrad, BB_SGD and SGD. | `50` |
| `--print_accuracy (-P)` | [`flag`](#doc_flag) | Print accuracies on initial and transformed dataset | |
| `--range (-R)` | [`int`](#doc_int) | Number of iterations after which impostors needs to be recalculated | `1` |
| `--rank (-A)` | [`int`](#doc_int) | Rank of distance matrix to be optimized. | `0` |
| `--regularization (-r)` | [`double`](#doc_double) | Regularization for LMNN objective function | `0.5` |
| `--seed (-s)` | [`int`](#doc_int) | Random seed. If 0, 'std::time(NULL)' is used. | `0` |
| `--step_size (-a)` | [`double`](#doc_double) | Step size for AMSGrad, BB_SGD and SGD (alpha). | `0.01` |
| `--tolerance (-t)` | [`double`](#doc_double) | Maximum tolerance for termination of AMSGrad, BB_SGD, SGD or L-BFGS. | `1e-07` |
| `--update_interval (-R)` | [`int`](#doc_int) | Number of iterations after which impostors need to be recalculated. | `1` |
| `--verbose (-v)` | [`flag`](#doc_flag) | Display informational messages and the full list of parameters and timers at the end of execution. | |
| `--version (-V)` | [`flag`](#doc_flag) | Display the version of mlpack. <span class="special">Only exists in CLI binding.</span> | |
@@ -1731,7 +1731,7 @@ This program implements Large Margin Nearest Neighbors, a distance learning tech
To work, this algorithm needs labeled data. It can be given as the last row of the input dataset (specified with `--input_file (-i)`), or alternatively as a separate matrix (specified with `--labels_file (-l)`). Additionally, a starting point for optimization (specified with `--distance_file (-d)`can be given, having (r x d) dimensionality. Here r should satisfy 1 <= r <= d, Consequently a Low-Rank matrix will be optimized. Alternatively, Low-Rank distance can be learned by specifying the `--rank (-A)`parameter (A Low-Rank matrix with uniformly distributed values will be used as initial learning point).
The program also requires number of targets neighbors to work with ( specified with `--k (-k)`), A regularization parameter can also be passed, It acts as a trade of between the pulling and pushing terms (specified with `--regularization (-r)`), In addition, this implementation of LMNN includes a parameter to decide the interval after which impostors must be re-calculated (specified with `--range (-R)`).
The program also requires number of targets neighbors to work with ( specified with `--k (-k)`), A regularization parameter can also be passed, It acts as a trade of between the pulling and pushing terms (specified with `--regularization (-r)`), In addition, this implementation of LMNN includes a parameter to decide the interval after which impostors must be re-calculated (specified with `--update_interval (-R)`).
Output can either be the learned distance matrix (specified with `--output_file (-o)`), or the transformed dataset (specified with `--transformed_data_file (-D)`), or both. Additionally mean-centered dataset (specified with `--centered_data_file (-c)`) can be accessed given mean-centering (specified with `--center (-C)`) is performed on the dataset. Accuracy on initial dataset and final transformed dataset can be printed by specifying the `--print_accuracy (-P)`parameter.
@@ -1755,10 +1755,10 @@ $ mlpack_lmnn --input_file iris.csv --labels_file iris_labels.csv --k 3
--optimizer bbsgd --output_file output.csv
```
An another program call making use of range & regularization parameter with dataset having labels as last column can be made as:
Another program call making use of update interval & regularization parameter with dataset having labels as last column can be made as:
```bash
$ mlpack_lmnn --input_file letter_recognition.csv --k 5 --range 10
$ mlpack_lmnn --input_file letter_recognition.csv --k 5 --update_interval 10
--regularization 0.4 --output_file output.csv
```
+5 -5
View File
@@ -2069,12 +2069,12 @@ param.Normalize = false
param.Optimizer = "amsgrad"
param.Passes = 50
param.PrintAccuracy = false
param.Range = 1
param.Rank = 0
param.Regularization = 0.5
param.Seed = 0
param.StepSize = 0.01
param.Tolerance = 1e-07
param.UpdateInterval = 1
param.Verbose = false
centered_data, output, transformed_data := mlpack.Lmnn(input, param)
@@ -2102,12 +2102,12 @@ There are two types of input options: required options, which are passed directl
| `Optimizer` | [`string`](#doc_string) | Optimizer to use; 'amsgrad', 'bbsgd', 'sgd', or 'lbfgs'. | `"amsgrad"` |
| `Passes` | [`int`](#doc_int) | Maximum number of full passes over dataset for AMSGrad, BB_SGD and SGD. | `50` |
| `PrintAccuracy` | [`bool`](#doc_bool) | Print accuracies on initial and transformed dataset | `false` |
| `Range` | [`int`](#doc_int) | Number of iterations after which impostors needs to be recalculated | `1` |
| `Rank` | [`int`](#doc_int) | Rank of distance matrix to be optimized. | `0` |
| `Regularization` | [`float64`](#doc_float64) | Regularization for LMNN objective function | `0.5` |
| `Seed` | [`int`](#doc_int) | Random seed. If 0, 'std::time(NULL)' is used. | `0` |
| `StepSize` | [`float64`](#doc_float64) | Step size for AMSGrad, BB_SGD and SGD (alpha). | `0.01` |
| `Tolerance` | [`float64`](#doc_float64) | Maximum tolerance for termination of AMSGrad, BB_SGD, SGD or L-BFGS. | `1e-07` |
| `UpdateInterval` | [`int`](#doc_int) | Number of iterations after which impostors need to be recalculated. | `1` |
| `Verbose` | [`bool`](#doc_bool) | Display informational messages and the full list of parameters and timers at the end of execution. | `false` |
### Output options
@@ -2127,7 +2127,7 @@ This program implements Large Margin Nearest Neighbors, a distance learning tech
To work, this algorithm needs labeled data. It can be given as the last row of the input dataset (specified with `Input`), or alternatively as a separate matrix (specified with `Labels`). Additionally, a starting point for optimization (specified with `Distance`can be given, having (r x d) dimensionality. Here r should satisfy 1 <= r <= d, Consequently a Low-Rank matrix will be optimized. Alternatively, Low-Rank distance can be learned by specifying the `Rank`parameter (A Low-Rank matrix with uniformly distributed values will be used as initial learning point).
The program also requires number of targets neighbors to work with ( specified with `K`), A regularization parameter can also be passed, It acts as a trade of between the pulling and pushing terms (specified with `Regularization`), In addition, this implementation of LMNN includes a parameter to decide the interval after which impostors must be re-calculated (specified with `Range`).
The program also requires number of targets neighbors to work with ( specified with `K`), A regularization parameter can also be passed, It acts as a trade of between the pulling and pushing terms (specified with `Regularization`), In addition, this implementation of LMNN includes a parameter to decide the interval after which impostors must be re-calculated (specified with `UpdateInterval`).
Output can either be the learned distance matrix (specified with `Output`), or the transformed dataset (specified with `TransformedData`), or both. Additionally mean-centered dataset (specified with `CenteredData`) can be accessed given mean-centering (specified with `Center`) is performed on the dataset. Accuracy on initial dataset and final transformed dataset can be printed by specifying the `PrintAccuracy`parameter.
@@ -2156,13 +2156,13 @@ param.Optimizer = "bbsgd"
_, output, _ := mlpack.Lmnn(iris, param)
```
An another program call making use of range & regularization parameter with dataset having labels as last column can be made as:
Another program call making use of update interval & regularization parameter with dataset having labels as last column can be made as:
```go
// Initialize optional parameters for Lmnn().
param := mlpack.LmnnOptions()
param.K = 5
param.Range = 10
param.UpdateInterval = 10
param.Regularization = 0.4
_, output, _ := mlpack.Lmnn(letter_recognition, param)
+7 -7
View File
@@ -1696,9 +1696,9 @@ julia> using mlpack: lmnn
julia> centered_data, output, transformed_data = lmnn(input;
batch_size=50, center=false, distance=zeros(0, 0), k=1, labels=Int[],
linear_scan=false, max_iterations=100000, normalize=false,
optimizer="amsgrad", passes=50, print_accuracy=false, range=1, rank=0,
optimizer="amsgrad", passes=50, print_accuracy=false, rank=0,
regularization=0.5, seed=0, step_size=0.01, tolerance=1e-07,
verbose=false)
update_interval=1, verbose=false)
```
An implementation of Large Margin Nearest Neighbors (LMNN), a distance learning technique. Given a labeled dataset, this learns a transformation of the data that improves k-nearest-neighbor performance; this can be useful as a preprocessing step. [Detailed documentation](#lmnn_detailed-documentation).
@@ -1722,12 +1722,12 @@ An implementation of Large Margin Nearest Neighbors (LMNN), a distance learning
| `optimizer` | [`String`](#doc_String) | Optimizer to use; 'amsgrad', 'bbsgd', 'sgd', or 'lbfgs'. | `"amsgrad"` |
| `passes` | [`Int`](#doc_Int) | Maximum number of full passes over dataset for AMSGrad, BB_SGD and SGD. | `50` |
| `print_accuracy` | [`Bool`](#doc_Bool) | Print accuracies on initial and transformed dataset | `false` |
| `range` | [`Int`](#doc_Int) | Number of iterations after which impostors needs to be recalculated | `1` |
| `rank` | [`Int`](#doc_Int) | Rank of distance matrix to be optimized. | `0` |
| `regularization` | [`Float64`](#doc_Float64) | Regularization for LMNN objective function | `0.5` |
| `seed` | [`Int`](#doc_Int) | Random seed. If 0, 'std::time(NULL)' is used. | `0` |
| `step_size` | [`Float64`](#doc_Float64) | Step size for AMSGrad, BB_SGD and SGD (alpha). | `0.01` |
| `tolerance` | [`Float64`](#doc_Float64) | Maximum tolerance for termination of AMSGrad, BB_SGD, SGD or L-BFGS. | `1e-07` |
| `update_interval` | [`Int`](#doc_Int) | Number of iterations after which impostors need to be recalculated. | `1` |
| `verbose` | [`Bool`](#doc_Bool) | Display informational messages and the full list of parameters and timers at the end of execution. | `false` |
### Output options
@@ -1747,7 +1747,7 @@ This program implements Large Margin Nearest Neighbors, a distance learning tech
To work, this algorithm needs labeled data. It can be given as the last row of the input dataset (specified with `input`), or alternatively as a separate matrix (specified with `labels`). Additionally, a starting point for optimization (specified with `distance`can be given, having (r x d) dimensionality. Here r should satisfy 1 <= r <= d, Consequently a Low-Rank matrix will be optimized. Alternatively, Low-Rank distance can be learned by specifying the `rank`parameter (A Low-Rank matrix with uniformly distributed values will be used as initial learning point).
The program also requires number of targets neighbors to work with ( specified with `k`), A regularization parameter can also be passed, It acts as a trade of between the pulling and pushing terms (specified with `regularization`), In addition, this implementation of LMNN includes a parameter to decide the interval after which impostors must be re-calculated (specified with `range`).
The program also requires number of targets neighbors to work with ( specified with `k`), A regularization parameter can also be passed, It acts as a trade of between the pulling and pushing terms (specified with `regularization`), In addition, this implementation of LMNN includes a parameter to decide the interval after which impostors must be re-calculated (specified with `update_interval`).
Output can either be the learned distance matrix (specified with `output`), or the transformed dataset (specified with `transformed_data`), or both. Additionally mean-centered dataset (specified with `centered_data`) can be accessed given mean-centering (specified with `center`) is performed on the dataset. Accuracy on initial dataset and final transformed dataset can be printed by specifying the `print_accuracy`parameter.
@@ -1774,13 +1774,13 @@ julia> _, output, _ = lmnn(iris; k=3, labels=iris_labels,
optimizer="bbsgd")
```
An another program call making use of range & regularization parameter with dataset having labels as last column can be made as:
Another program call making use of update interval & regularization parameter with dataset having labels as last column can be made as:
```julia
julia> using CSV
julia> letter_recognition = CSV.read("letter_recognition.csv")
julia> _, output, _ = lmnn(letter_recognition; k=5, range=10,
regularization=0.4)
julia> _, output, _ = lmnn(letter_recognition; k=5,
regularization=0.4, update_interval=10)
```
### See also
+6 -6
View File
@@ -1715,8 +1715,8 @@ Then, to use that model to predict classes for the dataset '`'test'`', storing t
copy_all_inputs=False, distance=np.empty([0, 0]), input_=np.empty([0,
0]), k=1, labels=np.empty([0], dtype=np.uint64), linear_scan=False,
max_iterations=100000, normalize=False, optimizer='amsgrad', passes=50,
print_accuracy=False, range=1, rank=0, regularization=0.5, seed=0,
step_size=0.01, tolerance=1e-07, verbose=False)
print_accuracy=False, rank=0, regularization=0.5, seed=0,
step_size=0.01, tolerance=1e-07, update_interval=1, verbose=False)
>>> centered_data = d['centered_data']
>>> output = d['output']
>>> transformed_data = d['transformed_data']
@@ -1744,12 +1744,12 @@ An implementation of Large Margin Nearest Neighbors (LMNN), a distance learning
| `optimizer` | [`str`](#doc_str) | Optimizer to use; 'amsgrad', 'bbsgd', 'sgd', or 'lbfgs'. | `'amsgrad'` |
| `passes` | [`int`](#doc_int) | Maximum number of full passes over dataset for AMSGrad, BB_SGD and SGD. | `50` |
| `print_accuracy` | [`bool`](#doc_bool) | Print accuracies on initial and transformed dataset | `False` |
| `range` | [`int`](#doc_int) | Number of iterations after which impostors needs to be recalculated | `1` |
| `rank` | [`int`](#doc_int) | Rank of distance matrix to be optimized. | `0` |
| `regularization` | [`float`](#doc_float) | Regularization for LMNN objective function | `0.5` |
| `seed` | [`int`](#doc_int) | Random seed. If 0, 'std::time(NULL)' is used. | `0` |
| `step_size` | [`float`](#doc_float) | Step size for AMSGrad, BB_SGD and SGD (alpha). | `0.01` |
| `tolerance` | [`float`](#doc_float) | Maximum tolerance for termination of AMSGrad, BB_SGD, SGD or L-BFGS. | `1e-07` |
| `update_interval` | [`int`](#doc_int) | Number of iterations after which impostors need to be recalculated. | `1` |
| `verbose` | [`bool`](#doc_bool) | Display informational messages and the full list of parameters and timers at the end of execution. | `False` |
### Output options
@@ -1769,7 +1769,7 @@ This program implements Large Margin Nearest Neighbors, a distance learning tech
To work, this algorithm needs labeled data. It can be given as the last row of the input dataset (specified with `input_`), or alternatively as a separate matrix (specified with `labels`). Additionally, a starting point for optimization (specified with `distance`can be given, having (r x d) dimensionality. Here r should satisfy 1 <= r <= d, Consequently a Low-Rank matrix will be optimized. Alternatively, Low-Rank distance can be learned by specifying the `rank`parameter (A Low-Rank matrix with uniformly distributed values will be used as initial learning point).
The program also requires number of targets neighbors to work with ( specified with `k`), A regularization parameter can also be passed, It acts as a trade of between the pulling and pushing terms (specified with `regularization`), In addition, this implementation of LMNN includes a parameter to decide the interval after which impostors must be re-calculated (specified with `range`).
The program also requires number of targets neighbors to work with ( specified with `k`), A regularization parameter can also be passed, It acts as a trade of between the pulling and pushing terms (specified with `regularization`), In addition, this implementation of LMNN includes a parameter to decide the interval after which impostors must be re-calculated (specified with `update_interval`).
Output can either be the learned distance matrix (specified with `output`), or the transformed dataset (specified with `transformed_data`), or both. Additionally mean-centered dataset (specified with `centered_data`) can be accessed given mean-centering (specified with `center`) is performed on the dataset. Accuracy on initial dataset and final transformed dataset can be printed by specifying the `print_accuracy`parameter.
@@ -1793,10 +1793,10 @@ Example - Let's say we want to learn distance on iris dataset with number of tar
>>> output = output['output']
```
An another program call making use of range & regularization parameter with dataset having labels as last column can be made as:
Another program call making use of update interval & regularization parameter with dataset having labels as last column can be made as:
```python
>>> output = lmnn(input_=letter_recognition, k=5, range=10,
>>> output = lmnn(input_=letter_recognition, k=5, update_interval=10,
regularization=0.4)
>>> output = output['output']
```
+6 -6
View File
@@ -1689,9 +1689,9 @@ R> library(mlpack)
R> d <- lmnn(batch_size=50, center=FALSE, distance=matrix(numeric(), 0,
0), input=matrix(numeric(), 0, 0), k=1, labels=matrix(integer(), 0, 0),
linear_scan=FALSE, max_iterations=100000, normalize=FALSE,
optimizer="amsgrad", passes=50, print_accuracy=FALSE, range=1, rank=0,
optimizer="amsgrad", passes=50, print_accuracy=FALSE, rank=0,
regularization=0.5, seed=0, step_size=0.01, tolerance=1e-07,
verbose=getOption("mlpack.verbose", FALSE))
update_interval=1, verbose=getOption("mlpack.verbose", FALSE))
R> centered_data <- d$centered_data
R> output <- d$output
R> transformed_data <- d$transformed_data
@@ -1718,12 +1718,12 @@ An implementation of Large Margin Nearest Neighbors (LMNN), a distance learning
| `optimizer` | [`character`](#doc_character) | Optimizer to use; 'amsgrad', 'bbsgd', 'sgd', or 'lbfgs'. | `"amsgrad"` |
| `passes` | [`integer`](#doc_integer) | Maximum number of full passes over dataset for AMSGrad, BB_SGD and SGD. | `50` |
| `print_accuracy` | [`logical`](#doc_logical) | Print accuracies on initial and transformed dataset | `FALSE` |
| `range` | [`integer`](#doc_integer) | Number of iterations after which impostors needs to be recalculated | `1` |
| `rank` | [`integer`](#doc_integer) | Rank of distance matrix to be optimized. | `0` |
| `regularization` | [`numeric`](#doc_numeric) | Regularization for LMNN objective function | `0.5` |
| `seed` | [`integer`](#doc_integer) | Random seed. If 0, 'std::time(NULL)' is used. | `0` |
| `step_size` | [`numeric`](#doc_numeric) | Step size for AMSGrad, BB_SGD and SGD (alpha). | `0.01` |
| `tolerance` | [`numeric`](#doc_numeric) | Maximum tolerance for termination of AMSGrad, BB_SGD, SGD or L-BFGS. | `1e-07` |
| `update_interval` | [`integer`](#doc_integer) | Number of iterations after which impostors need to be recalculated. | `1` |
| `verbose` | [`logical`](#doc_logical) | Display informational messages and the full list of parameters and timers at the end of execution. | `getOption("mlpack.verbose", FALSE)` |
### Output options
@@ -1743,7 +1743,7 @@ This program implements Large Margin Nearest Neighbors, a distance learning tech
To work, this algorithm needs labeled data. It can be given as the last row of the input dataset (specified with `input`), or alternatively as a separate matrix (specified with `labels`). Additionally, a starting point for optimization (specified with `distance`can be given, having (r x d) dimensionality. Here r should satisfy 1 <= r <= d, Consequently a Low-Rank matrix will be optimized. Alternatively, Low-Rank distance can be learned by specifying the `rank`parameter (A Low-Rank matrix with uniformly distributed values will be used as initial learning point).
The program also requires number of targets neighbors to work with ( specified with `k`), A regularization parameter can also be passed, It acts as a trade of between the pulling and pushing terms (specified with `regularization`), In addition, this implementation of LMNN includes a parameter to decide the interval after which impostors must be re-calculated (specified with `range`).
The program also requires number of targets neighbors to work with ( specified with `k`), A regularization parameter can also be passed, It acts as a trade of between the pulling and pushing terms (specified with `regularization`), In addition, this implementation of LMNN includes a parameter to decide the interval after which impostors must be re-calculated (specified with `update_interval`).
Output can either be the learned distance matrix (specified with `output`), or the transformed dataset (specified with `transformed_data`), or both. Additionally mean-centered dataset (specified with `centered_data`) can be accessed given mean-centering (specified with `center`) is performed on the dataset. Accuracy on initial dataset and final transformed dataset can be printed by specifying the `print_accuracy`parameter.
@@ -1767,10 +1767,10 @@ R> output <- lmnn(input=iris, labels=iris_labels, k=3, optimizer="bbsgd")
R> output <- output$output
```
An another program call making use of range & regularization parameter with dataset having labels as last column can be made as:
Another program call making use of update interval & regularization parameter with dataset having labels as last column can be made as:
```R
R> output <- lmnn(input=letter_recognition, k=5, range=10,
R> output <- lmnn(input=letter_recognition, k=5, update_interval=10,
regularization=0.4)
R> output <- output$output
```
+18 -8
View File
@@ -862,9 +862,9 @@ including:
* [`NeighborSearch`](/src/mlpack/methods/neighbor_search/neighbor_search.hpp)
* [`RangeSearch`](/src/mlpack/methods/range_search/range_search.hpp)
* [`LMNN`](/src/mlpack/methods/lmnn/lmnn.hpp)
* [`LMNN`](methods/lmnn.md)
* [`EMST`](/src/mlpack/methods/emst/emst.hpp)
* [`NCA`](/src/mlpack/methods/nca/nca.hpp)
* [`NCA`](methods/nca.md)
* [`RANN`](/src/mlpack/methods/rann/rann.hpp)
* [`KMeans`](/src/mlpack/methods/kmeans/kmeans.hpp)
@@ -1281,6 +1281,11 @@ std::cout << "Squared Mahalanobis distance on 32-bit floating point data:"
<< std::endl;
std::cout << " - Points 3 and 5: " << d1 << "." << std::endl;
std::cout << " - Points 11 and 31: " << d2 << "." << std::endl;
// Note that an equivalent transformation matrix can be recovered from Q with
// an upper Cholesky decomposition (Q -> R.t() * R).
arma::mat recoveredW = arma::chol(md.Q(), "lower");
// A transformed dataset can be created with `(recoveredW * dataset)`.
```
---
@@ -1641,7 +1646,8 @@ where `bw` is the bandwidth parameter of the kernel.
* `g.Gradient(distance)`
- Compute the (one-dimensional) gradient of the kernel function with respect
to the distance between two points, evaluated at `distance`.
to the distance between two points, evaluated at `distance`. This is used
by [`MeanShift`](methods/mean_shift.md).
* `g.Normalizer(dimensionality)`
- Return the
@@ -1876,7 +1882,8 @@ distance between `x1` and `x2`) is greater than or equal to `bw`.
* `e.Gradient(distance)`
- Compute the (one-dimensional) gradient of the kernel function with respect
to the distance between two points, evaluated at `distance`.
to the distance between two points, evaluated at `distance`. This is used
by [`MeanShift`](methods/mean_shift.md).
* `e.Normalizer(dimensionality)`
- Return the
@@ -1933,7 +1940,7 @@ std::cout << "Kernel values between two floating-point vectors: " << k5
### `HyperbolicTangentKernel`
The `HyperbolicTangentKernel` implements the
[hyperbolic tangent kernel](https://en.wikipedia.org/wiki/Support_vector_machine#Nonlinear_Kernels),
[hyperbolic tangent kernel](https://en.wikipedia.org/wiki/Support_vector_machine#Nonlinear_kernels),
which is defined by the following equation:
`f(x1, x2) = tanh(s * (x1^T x2) + t)`
where `s` is the scale parameter and `t` is the offset parameter.
@@ -2046,7 +2053,8 @@ where `bw` is the bandwidth parameter.
* `l.Gradient(distance)`
- Compute the (one-dimensional) gradient of the kernel function with respect
to the distance between two points, evaluated at `distance`.
to the distance between two points, evaluated at `distance`. This is used
by [`MeanShift`](methods/mean_shift.md).
---
@@ -2365,7 +2373,8 @@ as the uniform kernel, or rectangular window kernel. The value of the
* `s.Gradient(distance)`
- Compute the (one-dimensional) gradient of the kernel function with respect
to the distance between two points, evaluated at `distance`.
to the distance between two points, evaluated at `distance`. This is used
by [`MeanShift`](methods/mean_shift.md).
* `s.Normalizer(dimensionality)`
- Return the
@@ -2459,7 +2468,8 @@ where `bw` is the bandwidth of the kernel.
* `t.Gradient(distance)`
- Compute the (one-dimensional) gradient of the kernel function with respect
to the distance between two points, evaluated at `distance`.
to the distance between two points, evaluated at `distance`. This is used
by [`MeanShift`](methods/mean_shift.md).
---
+3 -2
View File
@@ -458,11 +458,9 @@ class CustomNumericSplit
categorical feature.
* The `AllCategoricalSplit` _(default)_ and `BestBinaryCategoricalSplit` are~
available for drop-in usage.
* `AllCategoricalSplit`, the default ID3 split
algorithm, splits all categories into their own node. This variant is simple,
and has complexity `O(n)`, where `n` is the number of samples.
* `BestBinaryCategoricalSplit` is the preferred algorithm of
[the CART system](https://www.taylorfrancis.com/books/mono/10.1201/9781315139470/classification-regression-trees-leo-breiman-jerome-friedman-olshen-charles-stone).
It will find the the best (entropy-minimizing) binary partition of the
@@ -471,6 +469,9 @@ class CustomNumericSplit
more than two _classes_.~
- ***Note***: `BestBinaryCategoricalSplit` should not be chosen when there
are multiple classes and many categories.
* A custom class must take a [`FitnessFunction`](#fitnessfunction) as a
template parameter, implement three functions, and have an internal
structure `AuxiliarySplitInfo` that is used at classification time:
```c++
template<typename FitnessFunction>
+1 -4
View File
@@ -462,11 +462,9 @@ class CustomNumericSplit
categorical feature.
* The `AllCategoricalSplit` _(default)_ and `BestBinaryCategoricalSplit` are~
available for drop-in usage.
* `AllCategoricalSplit`, the default ID3 split
algorithm, splits all categories into their own node. This variant is simple,
and has complexity `O(n)`, where `n` is the number of samples.
* `BestBinaryCategoricalSplit` is the preferred algorithm of
[the CART system](https://www.taylorfrancis.com/books/mono/10.1201/9781315139470/classification-regression-trees-leo-breiman-jerome-friedman-olshen-charles-stone).
It will find the the best (entropy-minimizing) binary partition of the
@@ -476,10 +474,9 @@ class CustomNumericSplit
- ***Note***: `BestBinaryCategoricalSplit` should not be chosen when there
are multiple classes and many categories.
- ***Note***: for regression tasks,
[W. Fisher's proof of correctness](http://www.csiss.org/SPACE/workshops/2004/SAC/files/fisher.pdf)
[W. Fisher's proof of correctness](https://www.mlpack.org/papers/fisher.pdf)
only applies to when `FitnessFunction` is `MSEGain`; therefore,
`BestBinaryCategoricalSplit` requires the use of `MSEGain`.
* A custom class must take a [`FitnessFunction`](#fitnessfunction) as a
template parameter, implement three functions, and have an internal
structure `AuxiliarySplitInfo` that is used at classification time:
+454
View File
@@ -0,0 +1,454 @@
## LMNN
The `LMNN` class implements large margin nearest neighbor, which can be used
as both a linear dimensionality reduction technique and a distance learning
technique (also called metric learning). LMNN finds a linear transformation of
the dataset that improves `k`-nearest-neighbor classification performance.
#### Simple usage example:
```c++
// Learn a distance metric that improves kNN classification performance.
// All data and labels are uniform random; 10 dimensional data, 5 classes.
// Replace with a data::Load() call or similar for a real application.
arma::mat dataset(10, 1000, arma::fill::randu); // 1000 points.
arma::Row<size_t> labels =
arma::randi<arma::Row<size_t>>(1000, arma::distr_param(0, 4));
mlpack::LMNN lmnn(3 /* neighbors to consider */); // Step 1: create object.
arma::mat distance;
lmnn.LearnDistance(dataset, labels, distance); // Step 2: learn distance.
// `distance` can now be used as a transformation matrix for the data.
arma::mat transformedData = distance * dataset;
// Or, you can create a MahalanobisDistance to evaluate points in the
// transformed dataset space.
arma::mat q = distance.t() * distance;
mlpack::MahalanobisDistance d(std::move(q));
std::cout << "Distance between points 0 and 1:" << std::endl;
std::cout << " - Before LMNN: "
<< mlpack::EuclideanDistance::Evaluate(dataset.col(0), dataset.col(1))
<< "." << std::endl;
std::cout << " - After LMNN: "
<< d.Evaluate(dataset.col(0), dataset.col(1)) << "." << std::endl;
```
<p style="text-align: center; font-size: 85%"><a href="#simple-examples">More examples...</a></p>
#### Quick links:
* [Constructors](#constructors): create `LMNN` objects.
* [`LearnDistance()`](#learning-distances): learn distance metrics.
* [Other functionality](#other-functionality) for loading and saving.
* [Examples](#simple-examples) of simple usage and integration with other
techniques.
#### See also:
<!-- TODO: link to kNN -->
* [mlpack distance metrics](../core.md#distances)
* [`NCA`](nca.md)
* [Metric learning on Wikipedia](https://en.wikipedia.org/wiki/Similarity_learning#Metric_learning)
* [Large margin nearest neighbor on Wikipedia](https://en.wikipedia.org/wiki/Large_margin_nearest_neighbor)
* [Distance metric learning for Large Margin Nearest Neighbor Classification (pdf)](https://proceedings.neurips.cc/paper_files/paper/2005/file/a7f592cef8b130a6967a90617db5681b-Paper.pdf)
### Constructors
* `lmnn = LMNN(k, regularization=0.5, updateInterval=1)`
- Create an `LMNN` object considering the specified number `k` of neighbors.
- Optionally, specify the regularization to be applied to the LMNN cost
function (a `double`), and the number of iterations between recomputation
of neighbors (`updateInterval`, a `size_t`).
---
* `lmnn = LMNN<DistanceType>(k, regularization=0.5, updateInterval=1)`
* `lmnn = LMNN<DistanceType>(k, regularization, updateInterval, distance)`
- Create an `LMNN` object using a custom
[`DistanceType`](../core.md#distances).
- `k` specifies the number of neighbors to consider.
- `regularization` specifies the regularization penalty to be applied to the
LMNN cost function (a `double`).
- `updateInterval` specifies the number of iterations between recomputation
of neighbors (a `size_t`).
- An instantiated `DistanceType` can optionally be passed with the `distance`
parameter.
- Using a custom `DistanceType` means that `LearnDistance()` will learn a
linear transformation for the data *in the metric space of the custom
`DistanceType`*.
* This means any learned distance may not necessarily improve
classification performance with the
[Euclidean distance](../core.md#lmetric).
* Instead, classification performance will be improved when the learned
distance is used with the given `DistanceType` only.
- Any mlpack `DistanceType` can be used as a drop-in replacement, or a
[custom `DistanceType`](../../developer/distances.md).
* A list of mlpack's provided distance metrics can be found
[here](../core.md#distances).
- ***Note: be sure that you understand the implications of a custom
`DistanceType` before using this version.***
---
***Notes***:
- A larger `k` will cause `LearnDistance()` to take longer to compute, but will
give more accurate results. It is generally suggested to keep `k` in roughly
the `3` to `5` range, depending on the dataset. Using `k = 1` can provide
fast convergence, but the learned distance metric may be of lower quality.
- `regularization` controls the balance between encouraging small distances for
points of the same class and penalizing small distances for points of
different classes. When `regularization` is increased, small distances for
points of different classes are further penalized.
- Setting `updateInterval` greater than `1` will allow the LMNN algorithm to
take multiple steps without the expensive recomputation of neighbors, but
this means that subsequent optimization steps may not be using the true
nearest neighbors.
* If using an SGD-like algorithm (i.e. an optimizer for a
[differentiable separable function](https://www.ensmallen.org/docs.html#differentiable-separable-functions)),
this can often be set to a relatively high value (100 is not unreasonable).
* If using an optimizer like L-BFGS (i.e. a full-batch optimizer for
[differentiable functions](https://www.ensmallen.org/docs.html#differentiable-functions)),
this should be kept relatively low (going above 10 is not advised).
* It is worth cross-validating different values of the parameter to see what
works for your dataset.
---
### Learning Distances
Once an `LMNN` object has been created, the `LearnDistance()` method can be used
to learn a distance.
* `lmnn.LearnDistance(data, labels, distance, [callbacks...])`
* `lmnn.LearnDistance(data, labels, distance, optimizer, [callbacks...])`
- Learn a distance metric on the given `data` and `labels`, filling
`distance` with a transformation matrix that can be used to map the data
into the space of the learned distance.
- Optionally, pass an instantiated
[ensmallen optimizer](https://www.ensmallen.org) and/or
[ensmallen callbacks](https://www.ensmallen.org/docs.html#callback-documentation)
to be used for the learning process.
- If no optimizer is passed,
[`ens::AMSGrad`](https://www.ensmallen.org/docs.html#amsgrad) is used.
- If `distance` already has size `r` x `data.n_rows` for some `r` less than
or equal to `data.n_rows`, it will be used as the starting point for
optimization. Otherwise, the identity matrix with size `data.n_rows` x
`data.n_rows` will be used.
- When optimization is complete, `distance` will have size `r` x
`data.n_rows`, where `r` is less than or equal to `data.n_rows`.
* *Note*: If `r < data.n_rows`, then LMNN has learned a distance metric
that also reduces the dimensionality of the data. See the
[last example](#simple-examples).
To use `distance`, either:
* Compute a new transformed dataset as `distance * data`, or
* Use an instantiated [`MahalanobisDistance`](../core.md#mahalanobisdistance)
with `distance.t() * distance` as the `Q` matrix.
See the [examples section](#simple-examples) for more details.
#### `LearnDistance()` Parameters:
| **name** | **type** | **description** |
|----------|----------|-----------------|
| `data` | [`arma::mat`](../matrices.md) | [Column-major](../matrices.md#representing-data-in-mlpack) training matrix. |
| `labels` | [`arma::Row<size_t>`](../matrices.md) | Training labels, [between `0` and `numClasses - 1`](../load_save.md#normalizing-labels) (inclusive). Should have length `data.n_cols`. |
| `distance` | [`arma::mat`](../matrices.md) | Output matrix to store transformation matrix representing learned distance. |
| `optimizer` | [any ensmallen optimizer](https://www.ensmallen.org) | Instantiated ensmallen optimizer for [differentiable functions](https://www.ensmallen.org/docs.html#differentiable-functions) or [differentiable separable functions](https://www.ensmallen.org/docs.html#differentiable-separable-functions). | `ens::AMSGrad()` |
| `callbacks...` | [any set of ensmallen callbacks](https://www.ensmallen.org/docs.html#callback-documentation) | Optional callbacks for the ensmallen optimizer, such as e.g. `ens::ProgressBar()`, `ens::Report()`, or others. | _(N/A)_ |
***Note***: any matrix type can be used for `data` and `distance`, so long as
that type implements the Armadillo API. So, e.g., `arma::fmat` can be used.
### Other Functionality
* An `LMNN` object can be serialized with
[`data::Save()` and `data::Load()`](../load_save.md#mlpack-objects).
Note that this is only meaningful if a custom `DistanceType` is being used,
and that custom `DistanceType` has state to be saved.
* `lmnn.K()` returns the number of neighbors used by LMNN, and `lmnn.K() = k`
will set the number of neighbors to use to `k`.
* `lmnn.Regularization()` returns the current regularization value of the LMNN
object (as a `double`), and `lmnn.Regularization() = r` can be used to set
the regularization value to `r`.
* `lmnn.UpdateInterval()` returns the current number of iterations between
neighbor recomputation (as a `size_t`), and `lmnn.UpdateInterval() = i` sets
the number of iterations between neighbor recomputation to `i`.
* `lmnn.Distance()` will return the `DistanceType` being used for learning.
Unless a custom `DistanceType` was specified in the constructor,
this simply returns a [`SquaredEuclideanDistance`](../core.md#lmetric)
object.
### Simple Examples
Learn a distance metric to improve classification performance on the iris
dataset, and show improved performance when using
[`NaiveBayesClassifier`](naive_bayes_classifier.md).
```c++
// See https://datasets.mlpack.org/satellite.test.csv.
// (We are using the test set here just because it is a little smaller and
// we want this example to run quickly.)
arma::mat dataset;
mlpack::data::Load("satellite.test.csv", dataset, true);
// See https://datasets.mlpack.org/satellite.test.labels.csv.
arma::Row<size_t> labels;
mlpack::data::Load("satellite.test.labels.csv", labels, true);
// Create an LMNN object using 5 nearest neighbors and learn a distance.
arma::mat distance;
mlpack::LMNN lmnn(5);
lmnn.LearnDistance(dataset, labels, distance);
// The distance matrix has size equal to the dimensionality of the data.
std::cout << "Learned distance size: " << distance.n_rows << " x "
<< distance.n_cols << "." << std::endl;
// Learn a NaiveBayesClassifier model on the data and print the performance.
mlpack::NaiveBayesClassifier nbc1(dataset, labels, 2);
arma::Row<size_t> predictions;
nbc1.Classify(dataset, predictions);
std::cout << "Naive Bayes Classifier without LMNN: "
<< arma::accu(labels == predictions) << " of " << labels.n_elem
<< " correct." << std::endl;
// Now transform the data and learn another NaiveBayesClassifier.
arma::mat transformedDataset = distance * dataset;
mlpack::NaiveBayesClassifier nbc2(transformedDataset, labels, 2);
nbc2.Classify(transformedDataset, predictions);
std::cout << "Naive Bayes Classifier with LMNN: "
<< arma::accu(labels == predictions) << " of " << labels.n_elem
<< " correct." << std::endl;
```
---
Learn a distance metric on the vehicle dataset, using 32-bit floating point to
represent the data and metric.
```c++
// See https://datasets.mlpack.org/vehicle.csv.
arma::fmat dataset;
mlpack::data::Load("vehicle.csv", dataset, true);
// The labels are contained as the last row of the dataset.
arma::Row<size_t> labels =
arma::conv_to<arma::Row<size_t>>::from(dataset.row(dataset.n_rows - 1));
dataset.shed_row(dataset.n_rows - 1);
// Create an LMNN object with k=1 and learn distance on float32 data.
// Set updateInterval to a large value (100) because we are using the default
// AMSGrad optimizer (which will take very many small steps).
arma::fmat distance;
mlpack::LMNN lmnn(1, 0.5, 100);
lmnn.LearnDistance(dataset, labels, distance, ens::ProgressBar());
// We want to compute six quantities:
//
// - Average distance to points of the same class before LMNN.
// - Average distance to points of the same class after LMNN, using
// MahalanobisDistance.
// - Average distance to points of the same class after LMNN, using the
// transformed dataset.
//
// - The same three quantities above, but for points of the other class.
//
// LMNN should reduce the average distance to points in the same class, while
// increasing the average distance to points in other classes.
float distSums[6] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
size_t sameCount = 0;
arma::fmat q = distance.t() * distance;
mlpack::MahalanobisDistance md(std::move(q));
arma::fmat transformedDataset = distance * dataset;
for (size_t i = 1; i < dataset.n_cols; ++i)
{
const double d1 = mlpack::EuclideanDistance::Evaluate(
dataset.col(0), dataset.col(i));
const double d2 = md.Evaluate(dataset.col(0), dataset.col(i));
const double d3 = mlpack::EuclideanDistance::Evaluate(
transformedDataset.col(0), transformedDataset.col(i));
// Determine whether the point has the same label as point 0.
if (labels[i] == labels[0])
{
distSums[0] += d1;
distSums[1] += d2;
distSums[2] += d3;
++sameCount;
}
else
{
distSums[3] += d1;
distSums[4] += d2;
distSums[5] += d3;
}
}
// Turn the results into average distances across the class.
distSums[0] /= sameCount;
distSums[1] /= sameCount;
distSums[2] /= sameCount;
distSums[3] /= (dataset.n_cols - sameCount);
distSums[4] /= (dataset.n_cols - sameCount);
distSums[5] /= (dataset.n_cols - sameCount);
// Print the results.
std::cout << "Average distance between point 0 and other points of the same "
<< "class:" << std::endl;
std::cout << " - Before LMNN: " << distSums[0] << "."
<< std::endl;
std::cout << " - After LMNN (with MahalanobisDistance): " << distSums[1] << "."
<< std::endl;
std::cout << " - After LMNN (with transformed dataset): " << distSums[2] << "."
<< std::endl;
std::cout << std::endl;
std::cout << "Average distance between point 0 and points of other classes: "
<< std::endl;
std::cout << " - Before LMNN: " << distSums[3] << "."
<< std::endl;
std::cout << " - After LMNN (with MahalanobisDistance): " << distSums[4] << "."
<< std::endl;
std::cout << " - After LMNN (with transformed dataset): " << distSums[5] << "."
<< std::endl;
std::cout << std::endl;
std::cout << "Ratio of other-class to same-class distances:" << std::endl;
std::cout << "(We expect this to go up.)" << std::endl;
std::cout << " - Before LMNN: " << (distSums[3] / distSums[0]) << "."
<< std::endl;
std::cout << " - After LMNN: " << (distSums[5] / distSums[2]) << "."
<< std::endl;
```
---
Learn a distance metric on the iris dataset, using the L-BFGS optimizer with
callbacks.
```c++
// See https://datasets.mlpack.org/iris.csv.
arma::mat dataset;
mlpack::data::Load("iris.csv", dataset, true);
// See https://datasets.mlpack.org/iris.labels.csv.
arma::Row<size_t> labels;
mlpack::data::Load("iris.labels.csv", labels, true);
// Learn a distance with ensmallen's L-BFGS optimizer.
ens::L_BFGS lbfgs;
lbfgs.NumBasis() = 5;
lbfgs.MaxIterations() = 1000;
// Use 5 neighbors for LMNN, and leave updateInterval at the default of 1,
// because we are using L-BFGS (a full-back optimizer).
mlpack::LMNN lmnn(5);
// Use a callback that prints a final optimization report.
arma::mat distance;
lmnn.LearnDistance(dataset, labels, distance, lbfgs, ens::Report());
```
---
Learn a distance metric on the vehicle dataset, but instead of using the
Euclidean distance as the underlying metric, use the Manhattan distance. This
means that LMNN is optimizing k-NN performance under the Manhattan distance, not
under the Euclidean distance.
```c++
// See https://datasets.mlpack.org/vehicle.csv.
arma::mat dataset;
mlpack::data::Load("vehicle.csv", dataset, true);
// The labels are contained as the last row of the dataset.
arma::Row<size_t> labels =
arma::conv_to<arma::Row<size_t>>::from(dataset.row(dataset.n_rows - 1));
dataset.shed_row(dataset.n_rows - 1);
// Create the LMNN object and optimize. Use k=3 and Nesterov momentum SGD,
// printing a progress bar during optimization. Because Nesterov momentum SGD
// is an ensmallen optimizer for differentiable separable functions, we increase
// updateInterval to reduce the number of neighbor recomputations. We also set
// the regularization parameter to 1.0 to increase the penalty for nearby
// neighbors of a different class.
mlpack::LMNN<mlpack::ManhattanDistance> lmnn(3, 1.0, 100);
arma::mat distance;
ens::NesterovMomentumSGD opt(0.000001 /* step size */,
32 /* batch size */,
20 * dataset.n_cols /* 20 epochs */);
lmnn.LearnDistance(dataset, labels, distance, opt, ens::ProgressBar());
// Now inspect distances between points with the Euclidean distance and with the
// inner product distance.
arma::mat transformedDataset = distance * dataset;
// Points 0 and 1 have the same label (0). See their original distance---with
// both the Euclidean and Manhattan distances---and their transformed distances.
// We expect these points to get closer together, in the Manhattan distance.
const double d1 = mlpack::ManhattanDistance::Evaluate(
dataset.col(0), dataset.col(1));
const double d2 = mlpack::ManhattanDistance::Evaluate(
transformedDataset.col(0), transformedDataset.col(1));
std::cout << "Distance between points 0 and 1 (same class):" << std::endl;
std::cout << " - Manhattan distance:" << std::endl;
std::cout << " * Before LMNN: " << d1 << std::endl;
std::cout << " * After LMNN: " << d2 << std::endl;
std::cout << std::endl;
// Point 3 has a different label. We therefore expect this point to get further
// from point 0 with the Manhattan distance, but not necessarily with the
// Euclidean distance.
const double d3 = mlpack::ManhattanDistance::Evaluate(
dataset.col(0), dataset.col(3));
const double d4 = mlpack::ManhattanDistance::Evaluate(
transformedDataset.col(0), transformedDataset.col(3));
std::cout << "Distance between points 0 and 3 (different class):" << std::endl;
std::cout << " - Manhattan distance:" << std::endl;
std::cout << " * Before LMNN: " << d3 << std::endl;
std::cout << " * After LMNN: " << d4 << std::endl;
// Note that point 3 has been moved further away from point 0 than point 1.
```
---
Learn a distance metric while also performing dimensionality reduction, reducing
the dimensionality of the satellite dataset by 3 dimensions.
```c++
// See https://datasets.mlpack.org/satellite.train.csv.
arma::mat dataset;
mlpack::data::Load("satellite.train.csv", dataset, true);
// See https://datasets.mlpack.org/satellite.labels.csv.
arma::Row<size_t> labels;
mlpack::data::Load("satellite.train.labels.csv", labels, true);
// Use a random initialization for the distance transformation, with the
// specified output dimensionality.
arma::mat distance(dataset.n_rows - 3, dataset.n_rows, arma::fill::randu);
mlpack::LMNN lmnn(3);
ens::L_BFGS opt;
opt.MaxIterations() = 10; // You may want more in a real application.
lmnn.LearnDistance(dataset, labels, distance, opt, ens::Report());
// Now transform the dataset.
arma::mat transformedData = distance * dataset;
std::cout << "Original data has size " << dataset.n_rows << " x "
<< dataset.n_cols << "." << std::endl;
std::cout << "Transformed data has size " << transformedData.n_rows << " x "
<< transformedData.n_cols << "." << std::endl;
```
+341
View File
@@ -0,0 +1,341 @@
## `MeanShift`
The `MeanShift` class implements mean shift, a clustering technique. Mean shift
models the density of the data using a kernel function (also called Parzen
window), producing a number of clusters that represent the data density. Mean
shift does not require the user to guess the number of clusters, and does not
make any assumptions on the shape of the data.
mlpack's `MeanShift` class allows control of the kernel function used via
template parameters.
#### Simple usage example:
```c++
// Use mean shift to cluster random data and print the number of points that
// fall into each cluster.
// Create random dataset with two separated 10-dimensional Gaussians.
arma::mat dataset = arma::join_rows(
arma::randn<arma::mat>(10, 1000) + 3.0, // 1000 points from N(-3, 1).
arma::randn<arma::mat>(10, 1000) - 3.0); // 1000 points from N( 3, 1).
mlpack::MeanShift ms; // Step 1: create object.
arma::Row<size_t> assignments;
arma::mat centroids;
ms.Cluster(dataset, assignments, centroids); // Step 2: perform clustering.
// Print the number of clusters.
std::cout << "Found " << centroids.n_cols << " centroids." << std::endl;
// Print the number of points in each cluster.
for (size_t c = 0; c < centroids.n_cols; ++c)
{
std::cout << " * Cluster " << c << " has " << arma::accu(assignments == c)
<< " points." << std::endl;
}
```
<p style="text-align: center; font-size: 85%"><a href="#simple-examples">More examples...</a></p>
#### Quick links:
* [Constructors](#constructors): create `MeanShift` objects.
* [`Cluster()`](#clustering): perform clustering.
* [Other functionality](#other-functionality) for loading, saving, inspecting,
and estimating the radius to use.
* [Examples](#simple-examples) of simple usage and links to detailed example
projects.
* [Template parameters](#advanced-functionality-template-parameters) for custom
behavior.
#### See also:
* [mlpack clustering algorithms](../../index.md#clustering-algorithms)
* [mlpack kernels](../core.md#kernels)
* [Mean shift on Wikipedia](https://en.wikipedia.org/wiki/Mean_shift)
* [Mean Shift, Mode Seeking, and Clustering (pdf)](http://users.isr.ist.utl.pt/~alex/Resources/meanshift.pdf)
### Constructors
* `ms = MeanShift(radius=0, maxIterations=1000)`
- Create a `MeanShift` object that will use the
default [`GaussianKernel`](../core.md#gaussiankernel) to weight points for
cluster centroid recalculations.
---
* `ms = MeanShift<false>(radius=0, maxIterations=1000)`
- Create a `MeanShift` object that will not weight points differently when
recalculating cluster centroids.
- Centroid recalculation will use all points within a distance of `radius`
from the current cluster centroid, uniformly weighted.
---
* `ms = MeanShift(radius, maxIterations, kernel)`
- Create a `MeanShift` object that will use the given `kernel` object (a
`GaussianKernel`) for weighting points during cluster centroid
recalculations.
---
* `ms = MeanShift<true, KernelType>(radius, maxIterations, kernel=KernelType())`
- Create a `MeanShift` object that will use the given
[`KernelType`](../core.md#kernels) for weighting points during cluster
centroid recalculations.
- [mlpack kernels](../core.md#kernels) or custom kernel classes implementing
a [`Gradient()` function](#advanced-functionality-template-parameters) can
be used for the `KernelType` template parameter.
- If `kernel` is not specified, a default-constructed `KernelType` will be
used.
- A list of usable `KernelType`s supplied with mlpack can be found in the
[advanced functionality section](#advanced-functionality-template-parameters).
---
#### Constructor Parameters:
| **name** | **type** | **description** | **default** |
|----------|----------|-----------------|-------------|
| `radius` | `double` | Radius around each centroid for weighting during centroid recomputation. Larger means higher weights for faraway points. Values less than or equal to 0 mean that the radius will be estimated from data. | `0.0` |
| `maxIterations` | `size_t` | Maximum number of iterations of the mean shift algorithm to run. | `1000` |
| `kernel` | [`KernelType`](#advanced-functionality-template-parameters) | Instantiated kernel object to use for density calculations. | [`GaussianKernel()`](../core.md#gaussiankernel) |
***Notes:***
- A larger `radius` value will generally result in fewer clusters (e.g. a
coarser clustering); smaller `radius` values will generally result in more
clusters.
- When `MeanShift<false>` is used, `radius` is the hard distance threshold for
points to be considered in the recomputation of a centroid.
### Clustering
* `ms.Cluster(data, centroids, forceConvergence=true, useSeeds=true)`
- Cluster the given data, storing the resulting cluster centroids in
`centroids`.
- `centroids` will be set to size `data.n_rows` x `numClusters`, where
`numClusters` is the number of clusters found by the mean shift algorithm.
- The `i`th cluster centroid can be obtained with `clusters.col(i)`.
---
* `ms.Cluster(data, assignments, centroids, forceConvergence=true, useSeeds=true)`
- Cluster the given data, storing the resulting cluster centroids in
`centroids` and cluster assignments for each data point in `assignments`.
- `centroids` will be set to size `data.n_rows` x `numClusters`, where
`numClusters` is the number of clusters found by the mean shift algorithm.
- `assignments` will be set to length `data.n_cols`; the assignment of the
`i`th point can be obtained with `assignments[i]`.
- The cluster centroid of the `i`th point's cluster can be obtained with
`centroids.col(assignments[i])`.
---
#### Clustering Parameters:
| **name** | **type** | **description** | **default** |
|----------|----------|-----------------|-------------|
| `data` | [`arma::mat`](../matrices.md) | [Column-major](../matrices.md#representing-data-in-mlpack) matrix holding the dataset to be clustered. | _(N/A)_ |
| `centroids` | [`arma::mat`](../matrices.md) | [Column-major](../matrices.md#representing-data-in-mlpack) matrix that centroids will be stored into. | _(N/A)_ |
| `assignments` | [`arma::Row<size_t>`](../matrices.md) | Vector to store cluster assignments for each point into. | _(N/A)_ |
| `forceConvergence` | `bool` | If `true`, forces convergence of every cluster, ignoring `maxIterations`. | `false` |
| `useSeeds` | `bool` | If `true`, estimates of high-density regions in the dataset will be used as initial centroids, instead of the full dataset. | `true`
***Notes***:
* It is recommended to leave `useSeeds` to its default value of `true`. When
`useSeeds` is set to `false`, the entire dataset is used as the initial set
of centroids. For large datasets, this can be slow!
* Different types can be used for `data` and `centroids` (e.g., `arma::fmat` or
any dense matrix type implementing the Armadillo API). The types of `data`
and `centroids` must be the same.
### Other Functionality
* A `MeanShift` object can be serialized with
[`data::Save()` and `data::Load()`](../load_save.md#mlpack-objects).
* `EstimateRadius(data, ratio=0.2)` returns a `double` that estimates a good
value to use for the radius parameter. `ratio` (between 0 and 1) controls
the percentage of the dataset used for the estimate.
- This function is called internally by `Cluster()` at the start of
clustering to choose a radius, if `radius` is less than or equal to 0.
* As an alternative to constructor parameters, the radius can be set with
`ms.Radius(newRadius)`, and the maximum number of iterations can be set with
`ms.MaxIterations() = newMaxIter`.
* `ms.Radius()` returns the current radius for clustering.
`ms.Radius(r)` sets the radius to `r`.
* `ms.MaxIterations()` returns the current maximum number of iterations for
clustering. `ms.MaxIterations() = m` sets the maximum number of iterations
to `m`.
### Simple Examples
Perform mean shift clustering on the satellite dataset and print the average
distance from each point to its assigned centroid.
```c++
// See https://datasets.mlpack.org/satellite.train.csv.
arma::mat dataset;
mlpack::data::Load("satellite.train.csv", dataset, true);
// Create MeanShift object with default parameters and perform clustering.
mlpack::MeanShift ms;
arma::mat centroids;
arma::Row<size_t> assignments;
ms.Cluster(dataset, assignments, centroids);
// Print the number of clusters.
std::cout << "MeanShift computed " << centroids.n_cols << " clusters."
<< std::endl;
// Compute the average distance from each point to its assigned centroid.
double sumDist = 0.0;
for (size_t i = 0; i < dataset.n_cols; ++i)
{
sumDist += mlpack::EuclideanDistance::Evaluate(
dataset.col(i), centroids.col(assignments[i]));
}
const double avgDist = sumDist / (double) dataset.n_cols;
std::cout << "Average distance from a point to its assigned centroid: "
<< avgDist << "." << std::endl;
```
---
Perform mean shift clustering with custom settings of `radius` and
`maxIterations` on the wave energy farm dataset, using `EstimateRadius()`
to set the initial radius.
```c++
// See https://datasets.mlpack.org/wave_energy_farm_100.csv.
arma::mat dataset;
mlpack::data::Load("wave_energy_farm_100.csv", dataset, true);
// Create MeanShift object and set parameters.
mlpack::MeanShift ms;
const double radiusEstimate = ms.EstimateRadius(dataset, 0.2);
// Use 2x the estimate for a coarser clustering.
ms.Radius(2.0 * radiusEstimate);
// Use only 100 iterations.
ms.MaxIterations() = 100;
// Perform the clustering.
arma::mat centroids;
ms.Cluster(dataset, centroids);
std::cout << "MeanShift found " << centroids.n_cols << " clusters."
<< std::endl;
// Save the centroids to disk.
mlpack::data::Save("wave_energy_centroids.csv", centroids);
```
---
Perform mean shift clustering with no kernel (e.g. unit weighting of points in a
centroid) on the cloud dataset.
```c++
// See https://datasets.mlpack.org/cloud.csv.
arma::mat dataset;
mlpack::data::Load("cloud.csv", dataset, true);
// Don't use a kernel for clustering. This means all points within the radius
// are weighted equally. Use a custom radius of 25.
mlpack::MeanShift<false> ms(25.0, 100 /* max iterations */);
arma::mat centroids;
arma::Row<size_t> assignments;
ms.Cluster(dataset, assignments, centroids);
// Print the number of clusters and the number of points in each cluster.
std::cout << "MeanShift found " << centroids.n_cols << " clusters."
<< std::endl;
for (size_t i = 0; i < centroids.n_cols; ++i)
{
std::cout << " - Cluster " << i << " has " << arma::accu(assignments == i)
<< " points assigned to it." << std::endl;
}
```
---
Perform mean shift clustering with the triangular kernel on the cloud dataset,
using 32-bit floating point matrices to represent the data.
```c++
// See https://datasets.mlpack.org/cloud.csv.
arma::fmat dataset;
mlpack::data::Load("cloud.csv", dataset, true);
// Create the MeanShift object using a TriangularKernel.
mlpack::TriangularKernel tk;
mlpack::MeanShift<true, mlpack::TriangularKernel> ms(50.0 /* radius */,
1000 /* max iterations */,
tk);
// Perform clustering.
arma::fmat centroids;
arma::Row<size_t> assignments;
ms.Cluster(dataset, assignments, centroids);
// Print the number of clusters and the number of points in each cluster.
std::cout << "MeanShift found " << centroids.n_cols << " clusters."
<< std::endl;
for (size_t i = 0; i < centroids.n_cols; ++i)
{
std::cout << " - Cluster " << i << " has " << arma::accu(assignments == i)
<< " points assigned to it." << std::endl;
}
```
---
### Advanced Functionality: Template Parameters
The `MeanShift` class has two template parameters that can be used for custom
behavior. The full signature of the class is:
```
MeanShift<UseKernel, KernelType>
```
* `UseKernel` (default `true`) is a `bool` parameter representing whether a
kernel function is used to weight points during centroid recomputation. If
it is `false`, then each point within distance `radius` of the centroid will
be used (without weighting) to recompute the centroid. This strategy (with
`UseKernel = false`) is also known as using a 'flat kernel'.
* `KernelType` represents the kernel function (or Parzen window) to be used to
weight points during centroid recomputation. Although many
[mlpack kernels](../core.md#kernels) are available, only those with
`Gradient()` functions (described below) are supported. Available kernels
for drop-in usage include:
- [`GaussianKernel`](../core.md#gaussiankernel) *(default)*
- [`EpanechnikovKernel`](../core.md#epanechnikovkernel)
- [`LaplacianKernel`](../core.md#laplaciankernel)
- [`SphericalKernel`](../core.md#sphericalkernel) *(note: this is equivalent
to the flat kernel, or, setting `UseKernel = false`)*
- [`TriangularKernel`](../core.md#triangularkernel)
Custom kernels for mean shift can be easily implemented, and must implement only
one function (`Gradient()`):
```c++
class CustomKernel
{
// Evaluate the gradient of the kernel function given the distance between two
// points. Specifically, given that the kernel function is K(t) (where t is
// the distance between the two points), this function should return K'(t).
double Gradient(const double t);
};
```
+440
View File
@@ -0,0 +1,440 @@
## NCA
The `NCA` class implements neighborhood components analysis, which can be used
as both a linear dimensionality reduction technique and a distance learning
technique (also called metric learning). Neighborhood components analysis finds
a linear transformation of the dataset that improves `k`-nearest-neighbor
classification performance.
Note that `NCA` is a computationally intensive technique (each optimization
iteration takes time quadratic in the data size!), and may be slow to run even
for datasets of only moderate size. See [`LMNN`](lmnn.md) for another distance
learning technique that scales better to larger datasets.
#### Simple usage example:
```c++
// Learn a distance metric that improves kNN classification performance.
// All data and labels are uniform random; 10 dimensional data, 5 classes.
// Replace with a data::Load() call or similar for a real application.
arma::mat dataset(10, 1000, arma::fill::randu); // 1000 points.
arma::Row<size_t> labels =
arma::randi<arma::Row<size_t>>(1000, arma::distr_param(0, 4));
mlpack::NCA nca; // Step 1: create object.
arma::mat distance;
nca.LearnDistance(dataset, labels, distance); // Step 2: learn distance.
// `distance` can now be used as a transformation matrix for the data.
arma::mat transformedData = distance * dataset;
// Or, you can create a MahalanobisDistance to evaluate points in the
// transformed dataset space.
arma::mat q = distance.t() * distance;
mlpack::MahalanobisDistance d(std::move(q));
std::cout << "Distance between points 0 and 1:" << std::endl;
std::cout << " - Before NCA: "
<< mlpack::EuclideanDistance::Evaluate(dataset.col(0), dataset.col(1))
<< "." << std::endl;
std::cout << " - After NCA: "
<< d.Evaluate(dataset.col(0), dataset.col(1)) << "." << std::endl;
```
<p style="text-align: center; font-size: 85%"><a href="#simple-examples">More examples...</a></p>
#### Quick links:
* [Constructors](#constructors): create `NCA` objects.
* [`LearnDistance()`](#learning-distances): learn distance metrics.
* [Other functionality](#other-functionality) for loading and saving.
* [Examples](#simple-examples) of simple usage and integration with other
techniques.
#### See also:
<!-- TODO: link to kNN -->
* [mlpack distance metrics](../core.md#distances)
* [`LMNN`](lmnn.md)
* [Metric learning on Wikipedia](https://en.wikipedia.org/wiki/Similarity_learning#Metric_learning)
* [Neighborhood Components Analysis on Wikipedia](https://en.wikipedia.org/wiki/Neighbourhood_components_analysis)
* [Neighbourhood Components Analysis (pdf)](https://proceedings.neurips.cc/paper_files/paper/2004/file/42fe880812925e520249e808937738d2-Paper.pdf)
### Constructors
* `nca = NCA()`
- Create an `NCA` object with default parameters.
---
* `nca = NCA<DistanceType>()`
* `nca = NCA<DistanceType>(distance)`
- Create an `NCA` object using a custom
[`DistanceType`](../core.md#distances).
- An instantiated `DistanceType` can optionally be passed with the `distance`
parameter.
- Using a custom `DistanceType` means that `LearnDistance()` will learn a
linear transformation for the data *in the metric space of the custom
`DistanceType`*.
* This means any learned distance may not necessarily improve
classification performance with the
[Euclidean distance](../core.md#lmetric).
* Instead, classification performance will be improved when the learned
distance is used with the given `DistanceType` only.
- Any mlpack `DistanceType` can be used as a drop-in replacement, or a
[custom `DistanceType`](../../developer/distances.md).
* A list of mlpack's provided distance metrics can be found
[here](../core.md#distances).
- ***Note: be sure that you understand the implications of a custom
`DistanceType` before using this version.***
---
### Learning Distances
Once an `NCA` object has been created, the `LearnDistance()` method can be used
to learn a distance.
* `nca.LearnDistance(data, labels, distance, [callbacks...])`
* `nca.LearnDistance(data, labels, distance, optimizer, [callbacks...])`
- Learn a distance metric on the given `data` and `labels`, filling
`distance` with a transformation matrix that can be used to map the data
into the space of the learned distance.
- Optionally, pass an instantiated
[ensmallen optimizer](https://www.ensmallen.org) and/or
[ensmallen callbacks](https://www.ensmallen.org/docs.html#callback-documentation)
to be used for the learning process.
- If `distance` already has size `r` x `data.n_rows` for some `r` less than
or equal to `data.n_rows`, it will be used as the starting point for
optimization. Otherwise, the identity matrix with size `data.n_rows` x
`data.n_rows` will be used.
- When optimization is complete, `distance` will have size `r` x
`data.n_rows`, where `r` is less than or equal to `data.n_rows`.
* *Note*: If `r < data.n_rows`, then NCA has learned a distance metric that
also reduces the dimensionality of the data. See the
[last example](#simple-examples).
To use `distance`, either:
* Compute a new transformed dataset as `distance * data`, or
* Use an instantiated [`MahalanobisDistance`](../core.md#mahalanobisdistance)
with `distance.t() * distance` as the `Q` matrix.
See the [examples section](#simple-examples) for more details.
***Caveat:*** NCA operates by repeatedly computing expressions of the form
`exp(-distance.Evaluate(data.col(i), data.col(j)))` (that is, the exponential of
the negative distance between two points). When distances are very large, this
***quantity underflows to 0*** and results will not be reasonable.
- This situation can be detected, usually by a result where `distance` is equal
to the identity matrix.
- Alternately, if the [`ens::ProgressBar()`
callback](https://www.ensmallen.org/docs.html#progressbar) is used, a loss of
0 often means this situation has occurred.
- To mitigate the problem, consider scaling data such that the maximum pairwise
distance is less than 10. See the [simple examples](#simple-examples) that
use the `vehicle` dataset.
#### `LearnDistance()` Parameters:
| **name** | **type** | **description** |
|----------|----------|-----------------|
| `data` | [`arma::mat`](../matrices.md) | [Column-major](../matrices.md#representing-data-in-mlpack) training matrix. |
| `labels` | [`arma::Row<size_t>`](../matrices.md) | Training labels, [between `0` and `numClasses - 1`](../load_save.md#normalizing-labels) (inclusive). Should have length `data.n_cols`. |
| `distance` | [`arma::mat`](../matrices.md) | Output matrix to store transformation matrix representing learned distance. |
| `optimizer` | [any ensmallen optimizer](https://www.ensmallen.org) | Instantiated ensmallen optimizer for [differentiable functions](https://www.ensmallen.org/docs.html#differentiable-functions) or [differentiable separable functions](https://www.ensmallen.org/docs.html#differentiable-separable-functions). | `ens::StandardSGD()` |
| `callbacks...` | [any set of ensmallen callbacks](https://www.ensmallen.org/docs.html#callback-documentation) | Optional callbacks for the ensmallen optimizer, such as e.g. `ens::ProgressBar()`, `ens::Report()`, or others. | _(N/A)_ |
***Note***: any matrix type can be used for `data` and `distance`, so long as
that type implements the Armadillo API. So, e.g., `arma::fmat` can be used.
### Other Functionality
* An `NCA` object can be serialized with
[`data::Save()` and `data::Load()`](../load_save.md#mlpack-objects).
Note that this is only meaningful if a custom `DistanceType` is being used,
and that custom `DistanceType` has state to be saved.
* `nca.Distance()` will return the `DistanceType` being used for learning.
Unless a custom `DistanceType` was specified in the constructor,
this simply returns a [`SquaredEuclideanDistance`](../core.md#lmetric)
object.
### Simple Examples
Learn a distance metric to improve classification performance on the iris
dataset, and show improved performance when using
[`NaiveBayesClassifier`](naive_bayes_classifier.md).
```c++
// See https://datasets.mlpack.org/iris.csv.
arma::mat dataset;
mlpack::data::Load("iris.csv", dataset, true);
// See https://datasets.mlpack.org/iris.labels.csv.
arma::Row<size_t> labels;
mlpack::data::Load("iris.labels.csv", labels, true);
// Create an NCA object and learn a distance.
arma::mat distance;
mlpack::NCA nca;
nca.LearnDistance(dataset, labels, distance);
// The distance matrix has size equal to the dimensionality of the data.
std::cout << "Learned distance size: " << distance.n_rows << " x "
<< distance.n_cols << "." << std::endl;
// Learn a NaiveBayesClassifier model on the data and print the performance.
mlpack::NaiveBayesClassifier nbc1(dataset, labels, 3);
arma::Row<size_t> predictions;
nbc1.Classify(dataset, predictions);
std::cout << "Naive Bayes Classifier without NCA: "
<< arma::accu(labels == predictions) << " of " << labels.n_elem
<< " correct." << std::endl;
// Now transform the data and learn another NaiveBayesClassifier.
arma::mat transformedDataset = distance * dataset;
mlpack::NaiveBayesClassifier nbc2(transformedDataset, labels, 3);
nbc2.Classify(transformedDataset, predictions);
std::cout << "Naive Bayes Classifier with NCA: "
<< arma::accu(labels == predictions) << " of " << labels.n_elem
<< " correct." << std::endl;
```
---
Learn a distance metric on the ionosphere dataset, using 32-bit floating point
to represent the data and metric.
```c++
// See https://datasets.mlpack.org/ionosphere.csv.
arma::fmat dataset;
mlpack::data::Load("ionosphere.csv", dataset, true);
// The labels are the last row of the dataset.
arma::Row<size_t> labels =
arma::conv_to<arma::Row<size_t>>::from(dataset.row(dataset.n_rows - 1));
dataset.shed_row(dataset.n_rows - 1);
// Create an NCA object and learn distance on float32 data.
// To keep computation time down, we use an instantiated optimizer that will
// only perform 10 epochs of training. (In a real application you may want to
// train for longer!)
arma::fmat distance;
mlpack::NCA nca;
ens::StandardSGD opt;
opt.MaxIterations() = 10 * dataset.n_cols;
nca.LearnDistance(dataset, labels, distance, opt, ens::ProgressBar());
// We want to compute six quantities:
//
// - Average distance to points of the same class before NCA.
// - Average distance to points of the same class after NCA, using
// MahalanobisDistance.
// - Average distance to points of the same class after NCA, using the
// transformed dataset.
//
// - The same three quantities above, but for points of the other class.
//
// NCA should reduce the average distance to points in the same class, while
// increasing the average distance to points in other classes.
float distSums[6] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
size_t sameCount = 0;
arma::fmat q = distance.t() * distance;
mlpack::MahalanobisDistance md(std::move(q));
arma::fmat transformedDataset = distance * dataset;
for (size_t i = 1; i < dataset.n_cols; ++i)
{
const double d1 = mlpack::EuclideanDistance::Evaluate(
dataset.col(0), dataset.col(i));
const double d2 = md.Evaluate(dataset.col(0), dataset.col(i));
const double d3 = mlpack::EuclideanDistance::Evaluate(
transformedDataset.col(0), transformedDataset.col(i));
// Determine whether the point has the same label as point 0.
if (labels[i] == labels[0])
{
distSums[0] += d1;
distSums[1] += d2;
distSums[2] += d3;
++sameCount;
}
else
{
distSums[3] += d1;
distSums[4] += d2;
distSums[5] += d3;
}
}
// Turn the results into average distances across the class.
distSums[0] /= sameCount;
distSums[1] /= sameCount;
distSums[2] /= sameCount;
distSums[3] /= (dataset.n_cols - sameCount);
distSums[4] /= (dataset.n_cols - sameCount);
distSums[5] /= (dataset.n_cols - sameCount);
// Print the results.
std::cout << "Average distance between point 0 and other points of the same "
<< "class:" << std::endl;
std::cout << " - Before NCA: " << distSums[0] << "."
<< std::endl;
std::cout << " - After NCA (with MahalanobisDistance): " << distSums[1] << "."
<< std::endl;
std::cout << " - After NCA (with transformed dataset): " << distSums[2] << "."
<< std::endl;
std::cout << std::endl;
std::cout << "Average distance between point 0 and points of other classes: "
<< std::endl;
std::cout << " - Before NCA: " << distSums[3] << "."
<< std::endl;
std::cout << " - After NCA (with MahalanobisDistance): " << distSums[4] << "."
<< std::endl;
std::cout << " - After NCA (with transformed dataset): " << distSums[5] << "."
<< std::endl;
std::cout << std::endl;
std::cout << "Ratio of other-class to same-class distances:" << std::endl;
std::cout << "(We expect this to go up.)" << std::endl;
std::cout << " - Before NCA: " << (distSums[3] / distSums[0]) << "."
<< std::endl;
std::cout << " - After NCA: " << (distSums[5] / distSums[2]) << "."
<< std::endl;
```
---
Learn a distance metric on the iris dataset, using the L-BFGS optimizer with
callbacks.
```c++
// See https://datasets.mlpack.org/iris.csv.
arma::mat dataset;
mlpack::data::Load("iris.csv", dataset, true);
// See https://datasets.mlpack.org/iris.labels.csv.
arma::Row<size_t> labels;
mlpack::data::Load("iris.labels.csv", labels, true);
// Learn a distance with ensmallen's L-BFGS optimizer.
ens::L_BFGS lbfgs;
lbfgs.NumBasis() = 5;
lbfgs.MaxIterations() = 1000;
arma::mat distance;
mlpack::NCA nca;
// Use a callback that prints a final optimization report.
nca.LearnDistance(dataset, labels, distance, lbfgs, ens::Report());
```
---
<!-- TODO: actually use a kNN classifier here... once we have it implemented! -->
Learn a distance metric on the vehicle dataset, but instead of using the
Euclidean distance as the underlying metric, use the Manhattan distance. This
means that NCA is optimizing k-NN performance under the Manhattan distance, not
under the Euclidean distance.
```c++
// See https://datasets.mlpack.org/vehicle.csv.
arma::mat dataset;
mlpack::data::Load("vehicle.csv", dataset, true);
// The labels are contained as the last row of the dataset.
arma::Row<size_t> labels =
arma::conv_to<arma::Row<size_t>>::from(dataset.row(dataset.n_rows - 1));
dataset.shed_row(dataset.n_rows - 1);
// Because typical distances between points in the vehicle dataset are large,
// we will center the dataset and scale it to have points in the unit ball.
// (That is, all points will have values in each dimension between -1 and 1.)
// This means that the maximum pairwise distance is 2.
dataset.each_col() -= arma::mean(dataset, 1);
dataset /= arma::max(arma::max(arma::abs(dataset)));
// Create the NCA object and optimize. Use Nesterov momentum SGD, printing a
// progress bar during optimization.
mlpack::NCA<mlpack::ManhattanDistance> nca;
arma::mat distance;
ens::NesterovMomentumSGD opt(0.01 /* step size */,
32 /* batch size */,
20 * dataset.n_cols /* 20 epochs */);
nca.LearnDistance(dataset, labels, distance, opt, ens::ProgressBar());
// Now inspect distances between points with the Euclidean distance and with the
// inner product distance.
arma::mat transformedDataset = distance * dataset;
// Points 0 and 1 have the same label (0). See their original distance---with
// both the Euclidean and Manhattan distances---and their transformed distances.
// We expect these points to get closer together, in the Manhattan distance.
const double d1 = mlpack::ManhattanDistance::Evaluate(
dataset.col(0), dataset.col(1));
const double d2 = mlpack::ManhattanDistance::Evaluate(
transformedDataset.col(0), transformedDataset.col(1));
std::cout << "Distance between points 0 and 1 (same class):" << std::endl;
std::cout << " - Manhattan distance:" << std::endl;
std::cout << " * Before NCA: " << d1 << std::endl;
std::cout << " * After NCA: " << d2 << std::endl;
std::cout << std::endl;
// Point 3 has a different label. We therefore expect this point to get further
// from point 0 with the Manhattan distance, but not necessarily with the
// Euclidean distance.
const double d3 = mlpack::ManhattanDistance::Evaluate(
dataset.col(0), dataset.col(3));
const double d4 = mlpack::ManhattanDistance::Evaluate(
transformedDataset.col(0), transformedDataset.col(3));
std::cout << "Distance between points 0 and 3 (different class):" << std::endl;
std::cout << " - Manhattan distance:" << std::endl;
std::cout << " * Before NCA: " << d3 << std::endl;
std::cout << " * After NCA: " << d4 << std::endl;
// Note that point 3 has been moved further away from point 0 than point 1.
```
---
Learn a distance metric while also performing dimensionality reduction, reducing
the dimensionality of the vehicle dataset by 2 dimensions.
```c++
// See https://datasets.mlpack.org/vehicle.csv.
arma::mat dataset;
mlpack::data::Load("vehicle.csv", dataset, true);
// The labels are contained as the last row of the dataset.
arma::Row<size_t> labels =
arma::conv_to<arma::Row<size_t>>::from(dataset.row(dataset.n_rows - 1));
dataset.shed_row(dataset.n_rows - 1);
// Because typical distances between points in the vehicle dataset are large,
// we will center the dataset and scale it to have points in the unit ball.
// (That is, all points will have values in each dimension between -1 and 1.)
// This means that the maximum pairwise distance is 2.
dataset.each_col() -= arma::mean(dataset, 1);
dataset /= arma::max(arma::max(arma::abs(dataset)));
// Use a random initialization for the distance transformation, with the
// specified output dimensionality.
arma::mat distance(dataset.n_rows - 2, dataset.n_rows, arma::fill::randu);
mlpack::NCA nca;
ens::L_BFGS opt;
opt.MaxIterations() = 10; // You may want more in a real application.
nca.LearnDistance(dataset, labels, distance, opt);
// Now transform the dataset.
arma::mat transformedData = distance * dataset;
std::cout << std::endl << std::endl;
std::cout << "Original data has size " << dataset.n_rows << " x "
<< dataset.n_cols << "." << std::endl;
std::cout << "Transformed data has size " << transformedData.n_rows << " x "
<< transformedData.n_cols << "." << std::endl;
```
+1
View File
@@ -422,6 +422,7 @@ then
--suppress-broken 405 \
--suppress-broken 503 \
--suppress-broken 301 \
--suppress-broken 400 \
-X "https://eigen.tuxfamily.org/index.php\?title=Main_Page" \
-X "https://mlpack.slack.com/" "$f" 2>&1 |
grep -v 'Use of uninitialized value' > checklink_out;
+1
View File
@@ -84,6 +84,7 @@
// Now include Armadillo and traits that we use for it.
#include <armadillo>
#include <mlpack/core/util/arma_traits.hpp>
#include <mlpack/core/util/omp_reductions.hpp>
// On Visual Studio, disable C4519 (default arguments for function templates)
// since it's by default an error, which doesn't even make any sense because
@@ -39,9 +39,7 @@ inline typename T::elem_type* GetMemory(T& m)
arma::access::rw(m.mem_state) = 1;
// With Armadillo 10 and newer, we must set `n_alloc` to 0 so that
// Armadillo does not deallocate the memory.
#if ARMA_VERSION_MAJOR >= 10
arma::access::rw(m.n_alloc) = 0;
#endif
arma::access::rw(m.n_alloc) = 0;
return m.memptr();
}
}
+7 -21
View File
@@ -428,9 +428,7 @@ double* GetParamMat(void* params, const char* paramName)
else
{
arma::access::rw(mat.mem_state) = 1;
#if ARMA_VERSION_MAJOR >= 10
arma::access::rw(mat.n_alloc) = 0;
#endif
arma::access::rw(mat.n_alloc) = 0;
return mat.memptr();
}
}
@@ -475,9 +473,7 @@ size_t* GetParamUMat(void* params, const char* paramName)
else
{
arma::access::rw(mat.mem_state) = 1;
#if ARMA_VERSION_MAJOR >= 10
arma::access::rw(mat.n_alloc) = 0;
#endif
arma::access::rw(mat.n_alloc) = 0;
return mat.memptr();
}
}
@@ -513,9 +509,7 @@ double* GetParamCol(void* params, const char* paramName)
else
{
arma::access::rw(vec.mem_state) = 1;
#if ARMA_VERSION_MAJOR >= 10
arma::access::rw(vec.n_alloc) = 0;
#endif
arma::access::rw(vec.n_alloc) = 0;
return vec.memptr();
}
}
@@ -552,9 +546,7 @@ size_t* GetParamUCol(void* params, const char* paramName)
else
{
arma::access::rw(vec.mem_state) = 1;
#if ARMA_VERSION_MAJOR >= 10
arma::access::rw(vec.n_alloc) = 0;
#endif
arma::access::rw(vec.n_alloc) = 0;
return vec.memptr();
}
}
@@ -590,9 +582,7 @@ double* GetParamRow(void* params, const char* paramName)
else
{
arma::access::rw(vec.mem_state) = 1;
#if ARMA_VERSION_MAJOR >= 10
arma::access::rw(vec.n_alloc) = 0;
#endif
arma::access::rw(vec.n_alloc) = 0;
return vec.memptr();
}
}
@@ -629,9 +619,7 @@ size_t* GetParamURow(void* params, const char* paramName)
else
{
arma::access::rw(vec.mem_state) = 1;
#if ARMA_VERSION_MAJOR >= 10
arma::access::rw(vec.n_alloc) = 0;
#endif
arma::access::rw(vec.n_alloc) = 0;
return vec.memptr();
}
}
@@ -707,9 +695,7 @@ double* GetParamMatWithInfoPtr(void* params, const char* paramName)
else
{
arma::access::rw(m.mem_state) = 1;
#if ARMA_VERSION_MAJOR >= 10
arma::access::rw(m.n_alloc) = 0;
#endif
arma::access::rw(m.n_alloc) = 0;
return m.memptr();
}
}
@@ -25,9 +25,8 @@ void SetMemState(T& t, int state)
// If we just "released" the memory, so that the matrix does not own it, with
// Armadillo 10 we must also ensure that the matrix does not deallocate the
// memory by specifying `n_alloc = 0`.
#if ARMA_VERSION_MAJOR >= 10
const_cast<arma::uword&>(t.n_alloc) = 0;
#endif
const_cast<arma::uword&>(t.n_alloc) = 0;
}
/**
@@ -160,7 +160,10 @@ def to_matrix_with_info(x, dtype, copy=False):
dims = len(x)
d = np.zeros([dims])
out = np.array(x, dtype=dtype, copy=copy) # Try to avoid copy...
if np.lib.NumpyVersion(np.__version__) >= '2.0.0b1':
out = np.array(x, dtype=dtype, copy=(True if copy else None))
else:
out = np.array(x, dtype=dtype, copy=copy)
# Since we don't have a great way to check if these are using the same
# memory location, we will probe manually (ugh).
+1
View File
@@ -37,6 +37,7 @@
// Now the core mlpack classes.
#include <mlpack/core/util/arma_traits.hpp>
#include <mlpack/core/util/ens_traits.hpp>
#include <mlpack/core/util/first_element_is_arma.hpp>
#include <mlpack/core/util/using.hpp>
#include <mlpack/core/util/conv_to.hpp>
#include <mlpack/core/util/log.hpp>
@@ -74,9 +74,9 @@ inline void GammaDistribution::Train(const arma::mat& rdata,
if (arma::size(rdata) == arma::size(arma::mat()))
return;
arma::vec meanLogxVec(rdata.n_rows, arma::fill::zeros);
arma::vec meanxVec(rdata.n_rows, arma::fill::zeros);
arma::vec logMeanxVec(rdata.n_rows, arma::fill::zeros);
arma::vec meanLogxVec(rdata.n_rows);
arma::vec meanxVec(rdata.n_rows);
arma::vec logMeanxVec(rdata.n_rows);
for (size_t i = 0; i < rdata.n_cols; ++i)
{
+2 -3
View File
@@ -27,12 +27,11 @@ namespace mlpack {
* @tparam VecType Type of vector (arma::vec or arma::sp_vec or similar).
*/
template<typename DistanceType = LMetric<2, true>,
typename VecType = arma::vec>
typename ElemType = double,
typename VecType = arma::Col<ElemType>>
class BallBound
{
public:
//! The underlying data type.
typedef typename VecType::elem_type ElemType;
//! A public version of the vector type.
typedef VecType Vec;
+54 -55
View File
@@ -20,8 +20,8 @@
namespace mlpack {
//! Empty Constructor.
template<typename DistanceType, typename VecType>
BallBound<DistanceType, VecType>::BallBound() :
template<typename DistanceType, typename ElemType, typename VecType>
BallBound<DistanceType, ElemType, VecType>::BallBound() :
radius(std::numeric_limits<ElemType>::lowest()),
distance(new DistanceType()),
ownsDistance(true)
@@ -32,8 +32,8 @@ BallBound<DistanceType, VecType>::BallBound() :
*
* @param dimension Dimensionality of ball bound.
*/
template<typename DistanceType, typename VecType>
BallBound<DistanceType, VecType>::BallBound(const size_t dimension) :
template<typename DistanceType, typename ElemType, typename VecType>
BallBound<DistanceType, ElemType, VecType>::BallBound(const size_t dimension) :
radius(std::numeric_limits<ElemType>::lowest()),
center(dimension),
distance(new DistanceType()),
@@ -46,9 +46,9 @@ BallBound<DistanceType, VecType>::BallBound(const size_t dimension) :
* @param radius Radius of ball bound.
* @param center Center of ball bound.
*/
template<typename DistanceType, typename VecType>
BallBound<DistanceType, VecType>::BallBound(const ElemType radius,
const VecType& center) :
template<typename DistanceType, typename ElemType, typename VecType>
BallBound<DistanceType, ElemType, VecType>::BallBound(const ElemType radius,
const VecType& center) :
radius(radius),
center(center),
distance(new DistanceType()),
@@ -56,8 +56,8 @@ BallBound<DistanceType, VecType>::BallBound(const ElemType radius,
{ /* Nothing to do. */ }
//! Copy Constructor. To prevent memory leaks.
template<typename DistanceType, typename VecType>
BallBound<DistanceType, VecType>::BallBound(const BallBound& other) :
template<typename DistanceType, typename ElemType, typename VecType>
BallBound<DistanceType, ElemType, VecType>::BallBound(const BallBound& other) :
radius(other.radius),
center(other.center),
distance(other.distance),
@@ -65,8 +65,9 @@ BallBound<DistanceType, VecType>::BallBound(const BallBound& other) :
{ /* Nothing to do. */ }
//! For the same reason as the copy constructor: to prevent memory leaks.
template<typename DistanceType, typename VecType>
BallBound<DistanceType, VecType>& BallBound<DistanceType, VecType>::operator=(
template<typename DistanceType, typename ElemType, typename VecType>
BallBound<DistanceType, ElemType, VecType>&
BallBound<DistanceType, ElemType, VecType>::operator=(
const BallBound& other)
{
if (this != &other)
@@ -80,8 +81,8 @@ BallBound<DistanceType, VecType>& BallBound<DistanceType, VecType>::operator=(
}
//! Move constructor.
template<typename DistanceType, typename VecType>
BallBound<DistanceType, VecType>::BallBound(BallBound&& other) :
template<typename DistanceType, typename ElemType, typename VecType>
BallBound<DistanceType, ElemType, VecType>::BallBound(BallBound&& other) :
radius(other.radius),
center(other.center),
distance(other.distance),
@@ -95,8 +96,9 @@ BallBound<DistanceType, VecType>::BallBound(BallBound&& other) :
}
//! Move assignment operator.
template<typename DistanceType, typename VecType>
BallBound<DistanceType, VecType>& BallBound<DistanceType, VecType>::operator=(
template<typename DistanceType, typename ElemType, typename VecType>
BallBound<DistanceType, ElemType, VecType>&
BallBound<DistanceType, ElemType, VecType>::operator=(
BallBound&& other)
{
if (this != &other)
@@ -115,29 +117,30 @@ BallBound<DistanceType, VecType>& BallBound<DistanceType, VecType>::operator=(
}
//! Destructor to release allocated memory.
template<typename DistanceType, typename VecType>
BallBound<DistanceType, VecType>::~BallBound()
template<typename DistanceType, typename ElemType, typename VecType>
BallBound<DistanceType, ElemType, VecType>::~BallBound()
{
if (ownsDistance)
delete distance;
}
//! Get the range in a certain dimension.
template<typename DistanceType, typename VecType>
RangeType<typename BallBound<DistanceType, VecType>::ElemType>
BallBound<DistanceType, VecType>::operator[](const size_t i) const
template<typename DistanceType, typename ElemType, typename VecType>
RangeType<ElemType>
BallBound<DistanceType, ElemType, VecType>::operator[](const size_t i) const
{
if (radius < 0)
return Range();
return RangeType<ElemType>();
else
return Range(center[i] - radius, center[i] + radius);
return RangeType<ElemType>(center[i] - radius, center[i] + radius);
}
/**
* Determines if a point is within the bound.
*/
template<typename DistanceType, typename VecType>
bool BallBound<DistanceType, VecType>::Contains(const VecType& point) const
template<typename DistanceType, typename ElemType, typename VecType>
bool BallBound<DistanceType, ElemType, VecType>::Contains(const VecType& point)
const
{
if (radius < 0)
return false;
@@ -148,10 +151,9 @@ bool BallBound<DistanceType, VecType>::Contains(const VecType& point) const
/**
* Calculates minimum bound-to-point squared distance.
*/
template<typename DistanceType, typename VecType>
template<typename DistanceType, typename ElemType, typename VecType>
template<typename OtherVecType>
typename BallBound<DistanceType, VecType>::ElemType
BallBound<DistanceType, VecType>::MinDistance(
ElemType BallBound<DistanceType, ElemType, VecType>::MinDistance(
const OtherVecType& point,
typename std::enable_if_t<IsVector<OtherVecType>::value>* /* junk */) const
{
@@ -164,10 +166,9 @@ BallBound<DistanceType, VecType>::MinDistance(
/**
* Calculates minimum bound-to-bound squared distance.
*/
template<typename DistanceType, typename VecType>
typename BallBound<DistanceType, VecType>::ElemType
BallBound<DistanceType, VecType>::MinDistance(const BallBound& other)
const
template<typename DistanceType, typename ElemType, typename VecType>
ElemType BallBound<DistanceType, ElemType, VecType>::MinDistance(
const BallBound& other) const
{
if (radius < 0)
return std::numeric_limits<ElemType>::max();
@@ -182,10 +183,9 @@ BallBound<DistanceType, VecType>::MinDistance(const BallBound& other)
/**
* Computes maximum distance.
*/
template<typename DistanceType, typename VecType>
template<typename DistanceType, typename ElemType, typename VecType>
template<typename OtherVecType>
typename BallBound<DistanceType, VecType>::ElemType
BallBound<DistanceType, VecType>::MaxDistance(
ElemType BallBound<DistanceType, ElemType, VecType>::MaxDistance(
const OtherVecType& point,
typename std::enable_if_t<IsVector<OtherVecType>::value>* /* junk */) const
{
@@ -198,10 +198,9 @@ BallBound<DistanceType, VecType>::MaxDistance(
/**
* Computes maximum distance.
*/
template<typename DistanceType, typename VecType>
typename BallBound<DistanceType, VecType>::ElemType
BallBound<DistanceType, VecType>::MaxDistance(const BallBound& other)
const
template<typename DistanceType, typename ElemType, typename VecType>
ElemType BallBound<DistanceType, ElemType, VecType>::MaxDistance(
const BallBound& other) const
{
if (radius < 0)
return std::numeric_limits<ElemType>::max();
@@ -214,36 +213,36 @@ BallBound<DistanceType, VecType>::MaxDistance(const BallBound& other)
*
* Example: bound1.MinDistanceSq(other) for minimum squared distance.
*/
template<typename DistanceType, typename VecType>
template<typename DistanceType, typename ElemType, typename VecType>
template<typename OtherVecType>
RangeType<typename BallBound<DistanceType, VecType>::ElemType>
BallBound<DistanceType, VecType>::RangeDistance(
RangeType<ElemType> BallBound<DistanceType, ElemType, VecType>::RangeDistance(
const OtherVecType& point,
typename std::enable_if_t<IsVector<OtherVecType>::value>* /* junk */) const
{
if (radius < 0)
return Range(std::numeric_limits<ElemType>::max(),
std::numeric_limits<ElemType>::max());
return RangeType<ElemType>(std::numeric_limits<ElemType>::max(),
std::numeric_limits<ElemType>::max());
else
{
const ElemType dist = distance->Evaluate(center, point);
return Range(std::max(dist - radius, (ElemType) 0.0), dist + radius);
return RangeType<ElemType>(std::max(dist - radius, (ElemType) 0.0),
dist + radius);
}
}
template<typename DistanceType, typename VecType>
RangeType<typename BallBound<DistanceType, VecType>::ElemType>
BallBound<DistanceType, VecType>::RangeDistance(
template<typename DistanceType, typename ElemType, typename VecType>
RangeType<ElemType> BallBound<DistanceType, ElemType, VecType>::RangeDistance(
const BallBound& other) const
{
if (radius < 0)
return Range(std::numeric_limits<ElemType>::max(),
std::numeric_limits<ElemType>::max());
return RangeType<ElemType>(std::numeric_limits<ElemType>::max(),
std::numeric_limits<ElemType>::max());
else
{
const ElemType dist = distance->Evaluate(center, other.center);
const ElemType sumradius = radius + other.radius;
return Range(std::max(dist - sumradius, (ElemType) 0.0), dist + sumradius);
return RangeType<ElemType>(std::max(dist - sumradius, (ElemType) 0.0),
dist + sumradius);
}
}
@@ -253,10 +252,10 @@ BallBound<DistanceType, VecType>::RangeDistance(
* The difference lies in the way we initialize the ball bound. The way we
* expand the bound is same.
*/
template<typename DistanceType, typename VecType>
template<typename DistanceType, typename ElemType, typename VecType>
template<typename MatType>
const BallBound<DistanceType, VecType>&
BallBound<DistanceType, VecType>::operator|=(const MatType& data)
const BallBound<DistanceType, ElemType, VecType>&
BallBound<DistanceType, ElemType, VecType>::operator|=(const MatType& data)
{
if (radius < 0)
{
@@ -284,9 +283,9 @@ BallBound<DistanceType, VecType>::operator|=(const MatType& data)
}
//! Serialize the BallBound.
template<typename DistanceType, typename VecType>
template<typename DistanceType, typename ElemType, typename VecType>
template<typename Archive>
void BallBound<DistanceType, VecType>::serialize(
void BallBound<DistanceType, ElemType, VecType>::serialize(
Archive& ar,
const uint32_t /* version */)
{
@@ -46,10 +46,11 @@ namespace mlpack {
template<typename DistanceType,
typename StatisticType = EmptyStatistic,
typename MatType = arma::mat,
template<typename BoundDistanceType, typename...> class BoundType =
HRectBound,
template<typename SplitBoundType, typename SplitMatType>
class SplitType = MidpointSplit>
template<typename BoundDistanceType,
typename BoundElemType,
typename...> class BoundType = HRectBound,
template<typename SplitBoundType,
typename SplitMatType> class SplitType = MidpointSplit>
class BinarySpaceTree
{
public:
@@ -58,7 +59,7 @@ class BinarySpaceTree
//! The type of element held in MatType.
typedef typename MatType::elem_type ElemType;
typedef SplitType<BoundType<DistanceType>, MatType> Split;
typedef SplitType<BoundType<DistanceType, ElemType>, MatType> Split;
private:
//! The left child node.
@@ -74,7 +75,7 @@ class BinarySpaceTree
//! children).
size_t count;
//! The bound object for this node.
BoundType<DistanceType> bound;
BoundType<DistanceType, ElemType> bound;
//! Any extra data contained in the node.
StatisticType stat;
//! The distance from the centroid of this node to the centroid of the parent.
@@ -210,7 +211,8 @@ class BinarySpaceTree
BinarySpaceTree(BinarySpaceTree* parent,
const size_t begin,
const size_t count,
SplitType<BoundType<DistanceType>, MatType>& splitter,
SplitType<BoundType<DistanceType, ElemType>, MatType>&
splitter,
const size_t maxLeafSize = 20);
/**
@@ -236,7 +238,8 @@ class BinarySpaceTree
const size_t begin,
const size_t count,
std::vector<size_t>& oldFromNew,
SplitType<BoundType<DistanceType>, MatType>& splitter,
SplitType<BoundType<DistanceType, ElemType>, MatType>&
splitter,
const size_t maxLeafSize = 20);
/**
@@ -266,7 +269,8 @@ class BinarySpaceTree
const size_t count,
std::vector<size_t>& oldFromNew,
std::vector<size_t>& newFromOld,
SplitType<BoundType<DistanceType>, MatType>& splitter,
SplitType<BoundType<DistanceType, ElemType>, MatType>&
splitter,
const size_t maxLeafSize = 20);
/**
@@ -315,9 +319,9 @@ class BinarySpaceTree
~BinarySpaceTree();
//! Return the bound object for this node.
const BoundType<DistanceType>& Bound() const { return bound; }
const BoundType<DistanceType, ElemType>& Bound() const { return bound; }
//! Return the bound object for this node.
BoundType<DistanceType>& Bound() { return bound; }
BoundType<DistanceType, ElemType>& Bound() { return bound; }
//! Return the statistic object for this node.
const StatisticType& Stat() const { return stat; }
@@ -517,8 +521,9 @@ class BinarySpaceTree
* @param maxLeafSize Maximum number of points held in a leaf.
* @param splitter Instantiated SplitType object.
*/
void SplitNode(const size_t maxLeafSize,
SplitType<BoundType<DistanceType>, MatType>& splitter);
void SplitNode(
const size_t maxLeafSize,
SplitType<BoundType<DistanceType, ElemType>, MatType>& splitter);
/**
* Splits the current node, assigning its left and right children recursively.
@@ -528,9 +533,10 @@ class BinarySpaceTree
* @param maxLeafSize Maximum number of points held in a leaf.
* @param splitter Instantiated SplitType object.
*/
void SplitNode(std::vector<size_t>& oldFromNew,
const size_t maxLeafSize,
SplitType<BoundType<DistanceType>, MatType>& splitter);
void SplitNode(
std::vector<size_t>& oldFromNew,
const size_t maxLeafSize,
SplitType<BoundType<DistanceType, ElemType>, MatType>& splitter);
/**
* Update the bound of the current node. This method does not take into
@@ -547,7 +553,7 @@ class BinarySpaceTree
*
* @param boundToUpdate The bound to update.
*/
void UpdateBound(HollowBallBound<DistanceType>& boundToUpdate);
void UpdateBound(HollowBallBound<DistanceType, ElemType>& boundToUpdate);
protected:
/**
@@ -24,9 +24,11 @@ namespace mlpack {
template<typename DistanceType,
typename StatisticType,
typename MatType,
template<typename BoundDistanceType, typename...> class BoundType,
template<typename SplitBoundType, typename SplitMatType>
class SplitType>
template<typename BoundDistanceType,
typename BoundElemType,
typename...> class BoundType,
template<typename SplitBoundType,
typename SplitMatType> class SplitType>
BinarySpaceTree<DistanceType, StatisticType, MatType, BoundType, SplitType>::
BinarySpaceTree(
const MatType& data,
@@ -41,7 +43,7 @@ BinarySpaceTree(
dataset(new MatType(data)) // Copies the dataset.
{
// Do the actual splitting of this node.
SplitType<BoundType<DistanceType>, MatType> splitter;
SplitType<BoundType<DistanceType, ElemType>, MatType> splitter;
SplitNode(maxLeafSize, splitter);
// Create the statistic depending on if we are a leaf or not.
@@ -51,9 +53,11 @@ BinarySpaceTree(
template<typename DistanceType,
typename StatisticType,
typename MatType,
template<typename BoundDistanceType, typename...> class BoundType,
template<typename SplitBoundType, typename SplitMatType>
class SplitType>
template<typename BoundDistanceType,
typename BoundElemType,
typename...> class BoundType,
template<typename SplitBoundType,
typename SplitMatType> class SplitType>
BinarySpaceTree<DistanceType, StatisticType, MatType, BoundType, SplitType>::
BinarySpaceTree(
const MatType& data,
@@ -74,7 +78,7 @@ BinarySpaceTree(
oldFromNew[i] = i; // Fill with unharmed indices.
// Now do the actual splitting.
SplitType<BoundType<DistanceType>, MatType> splitter;
SplitType<BoundType<DistanceType, ElemType>, MatType> splitter;
SplitNode(oldFromNew, maxLeafSize, splitter);
// Create the statistic depending on if we are a leaf or not.
@@ -84,9 +88,11 @@ BinarySpaceTree(
template<typename DistanceType,
typename StatisticType,
typename MatType,
template<typename BoundDistanceType, typename...> class BoundType,
template<typename SplitBoundType, typename SplitMatType>
class SplitType>
template<typename BoundDistanceType,
typename BoundElemType,
typename...> class BoundType,
template<typename SplitBoundType,
typename SplitMatType> class SplitType>
BinarySpaceTree<DistanceType, StatisticType, MatType, BoundType, SplitType>::
BinarySpaceTree(
const MatType& data,
@@ -108,7 +114,7 @@ BinarySpaceTree(
oldFromNew[i] = i; // Fill with unharmed indices.
// Now do the actual splitting.
SplitType<BoundType<DistanceType>, MatType> splitter;
SplitType<BoundType<DistanceType, ElemType>, MatType> splitter;
SplitNode(oldFromNew, maxLeafSize, splitter);
// Create the statistic depending on if we are a leaf or not.
@@ -123,9 +129,11 @@ BinarySpaceTree(
template<typename DistanceType,
typename StatisticType,
typename MatType,
template<typename BoundDistanceType, typename...> class BoundType,
template<typename SplitBoundType, typename SplitMatType>
class SplitType>
template<typename BoundDistanceType,
typename BoundElemType,
typename...> class BoundType,
template<typename SplitBoundType,
typename SplitMatType> class SplitType>
BinarySpaceTree<DistanceType, StatisticType, MatType, BoundType, SplitType>::
BinarySpaceTree(MatType&& data, const size_t maxLeafSize) :
left(NULL),
@@ -138,7 +146,7 @@ BinarySpaceTree(MatType&& data, const size_t maxLeafSize) :
dataset(new MatType(std::move(data)))
{
// Do the actual splitting of this node.
SplitType<BoundType<DistanceType>, MatType> splitter;
SplitType<BoundType<DistanceType, ElemType>, MatType> splitter;
SplitNode(maxLeafSize, splitter);
// Create the statistic depending on if we are a leaf or not.
@@ -148,9 +156,11 @@ BinarySpaceTree(MatType&& data, const size_t maxLeafSize) :
template<typename DistanceType,
typename StatisticType,
typename MatType,
template<typename BoundDistanceType, typename...> class BoundType,
template<typename SplitBoundType, typename SplitMatType>
class SplitType>
template<typename BoundDistanceType,
typename BoundElemType,
typename...> class BoundType,
template<typename SplitBoundType,
typename SplitMatType> class SplitType>
BinarySpaceTree<DistanceType, StatisticType, MatType, BoundType, SplitType>::
BinarySpaceTree(
MatType&& data,
@@ -171,7 +181,7 @@ BinarySpaceTree(
oldFromNew[i] = i; // Fill with unharmed indices.
// Now do the actual splitting.
SplitType<BoundType<DistanceType>, MatType> splitter;
SplitType<BoundType<DistanceType, ElemType>, MatType> splitter;
SplitNode(oldFromNew, maxLeafSize, splitter);
// Create the statistic depending on if we are a leaf or not.
@@ -181,9 +191,11 @@ BinarySpaceTree(
template<typename DistanceType,
typename StatisticType,
typename MatType,
template<typename BoundDistanceType, typename...> class BoundType,
template<typename SplitBoundType, typename SplitMatType>
class SplitType>
template<typename BoundDistanceType,
typename BoundElemType,
typename...> class BoundType,
template<typename SplitBoundType,
typename SplitMatType> class SplitType>
BinarySpaceTree<DistanceType, StatisticType, MatType, BoundType, SplitType>::
BinarySpaceTree(
MatType&& data,
@@ -205,7 +217,7 @@ BinarySpaceTree(
oldFromNew[i] = i; // Fill with unharmed indices.
// Now do the actual splitting.
SplitType<BoundType<DistanceType>, MatType> splitter;
SplitType<BoundType<DistanceType, ElemType>, MatType> splitter;
SplitNode(oldFromNew, maxLeafSize, splitter);
// Create the statistic depending on if we are a leaf or not.
@@ -220,15 +232,17 @@ BinarySpaceTree(
template<typename DistanceType,
typename StatisticType,
typename MatType,
template<typename BoundDistanceType, typename...> class BoundType,
template<typename SplitBoundType, typename SplitMatType>
class SplitType>
template<typename BoundDistanceType,
typename BoundElemType,
typename...> class BoundType,
template<typename SplitBoundType,
typename SplitMatType> class SplitType>
BinarySpaceTree<DistanceType, StatisticType, MatType, BoundType, SplitType>::
BinarySpaceTree(
BinarySpaceTree* parent,
const size_t begin,
const size_t count,
SplitType<BoundType<DistanceType>, MatType>& splitter,
SplitType<BoundType<DistanceType, ElemType>, MatType>& splitter,
const size_t maxLeafSize) :
left(NULL),
right(NULL),
@@ -248,16 +262,18 @@ BinarySpaceTree(
template<typename DistanceType,
typename StatisticType,
typename MatType,
template<typename BoundDistanceType, typename...> class BoundType,
template<typename SplitBoundType, typename SplitMatType>
class SplitType>
template<typename BoundDistanceType,
typename BoundElemType,
typename...> class BoundType,
template<typename SplitBoundType,
typename SplitMatType> class SplitType>
BinarySpaceTree<DistanceType, StatisticType, MatType, BoundType, SplitType>::
BinarySpaceTree(
BinarySpaceTree* parent,
const size_t begin,
const size_t count,
std::vector<size_t>& oldFromNew,
SplitType<BoundType<DistanceType>, MatType>& splitter,
SplitType<BoundType<DistanceType, ElemType>, MatType>& splitter,
const size_t maxLeafSize) :
left(NULL),
right(NULL),
@@ -281,9 +297,11 @@ BinarySpaceTree(
template<typename DistanceType,
typename StatisticType,
typename MatType,
template<typename BoundDistanceType, typename...> class BoundType,
template<typename SplitBoundType, typename SplitMatType>
class SplitType>
template<typename BoundDistanceType,
typename BoundElemType,
typename...> class BoundType,
template<typename SplitBoundType,
typename SplitMatType> class SplitType>
BinarySpaceTree<DistanceType, StatisticType, MatType, BoundType, SplitType>::
BinarySpaceTree(
BinarySpaceTree* parent,
@@ -291,7 +309,7 @@ BinarySpaceTree(
const size_t count,
std::vector<size_t>& oldFromNew,
std::vector<size_t>& newFromOld,
SplitType<BoundType<DistanceType>, MatType>& splitter,
SplitType<BoundType<DistanceType, ElemType>, MatType>& splitter,
const size_t maxLeafSize) :
left(NULL),
right(NULL),
@@ -324,9 +342,11 @@ BinarySpaceTree(
template<typename DistanceType,
typename StatisticType,
typename MatType,
template<typename BoundDistanceType, typename...> class BoundType,
template<typename SplitBoundType, typename SplitMatType>
class SplitType>
template<typename BoundDistanceType,
typename BoundElemType,
typename...> class BoundType,
template<typename SplitBoundType,
typename SplitMatType> class SplitType>
BinarySpaceTree<DistanceType, StatisticType, MatType, BoundType, SplitType>::
BinarySpaceTree(
const BinarySpaceTree& other) :
@@ -384,9 +404,11 @@ BinarySpaceTree(
template<typename DistanceType,
typename StatisticType,
typename MatType,
template<typename BoundDistanceType, typename...> class BoundType,
template<typename SplitBoundType, typename SplitMatType>
class SplitType>
template<typename BoundDistanceType,
typename BoundElemType,
typename...> class BoundType,
template<typename SplitBoundType,
typename SplitMatType> class SplitType>
BinarySpaceTree<DistanceType, StatisticType, MatType, BoundType, SplitType>&
BinarySpaceTree<DistanceType, StatisticType, MatType, BoundType, SplitType>::
operator=(const BinarySpaceTree& other)
@@ -456,9 +478,11 @@ operator=(const BinarySpaceTree& other)
template<typename DistanceType,
typename StatisticType,
typename MatType,
template<typename BoundDistanceType, typename...> class BoundType,
template<typename SplitBoundType, typename SplitMatType>
class SplitType>
template<typename BoundDistanceType,
typename BoundElemType,
typename...> class BoundType,
template<typename SplitBoundType,
typename SplitMatType> class SplitType>
BinarySpaceTree<DistanceType, StatisticType, MatType, BoundType, SplitType>&
BinarySpaceTree<DistanceType, StatisticType, MatType, BoundType, SplitType>::
operator=(BinarySpaceTree&& other)
@@ -504,9 +528,11 @@ operator=(BinarySpaceTree&& other)
template<typename DistanceType,
typename StatisticType,
typename MatType,
template<typename BoundDistanceType, typename...> class BoundType,
template<typename SplitBoundType, typename SplitMatType>
class SplitType>
template<typename BoundDistanceType,
typename BoundElemType,
typename...> class BoundType,
template<typename SplitBoundType,
typename SplitMatType> class SplitType>
BinarySpaceTree<DistanceType, StatisticType, MatType, BoundType, SplitType>::
BinarySpaceTree(BinarySpaceTree&& other) :
left(other.left),
@@ -546,9 +572,11 @@ BinarySpaceTree(BinarySpaceTree&& other) :
template<typename DistanceType,
typename StatisticType,
typename MatType,
template<typename BoundDistanceType, typename...> class BoundType,
template<typename SplitBoundType, typename SplitMatType>
class SplitType>
template<typename BoundDistanceType,
typename BoundElemType,
typename...> class BoundType,
template<typename SplitBoundType,
typename SplitMatType> class SplitType>
template<typename Archive>
BinarySpaceTree<DistanceType, StatisticType, MatType, BoundType, SplitType>::
BinarySpaceTree(
@@ -569,9 +597,11 @@ BinarySpaceTree(
template<typename DistanceType,
typename StatisticType,
typename MatType,
template<typename BoundDistanceType, typename...> class BoundType,
template<typename SplitBoundType, typename SplitMatType>
class SplitType>
template<typename BoundDistanceType,
typename BoundElemType,
typename...> class BoundType,
template<typename SplitBoundType,
typename SplitMatType> class SplitType>
BinarySpaceTree<DistanceType, StatisticType, MatType, BoundType, SplitType>::
~BinarySpaceTree()
{
@@ -586,9 +616,11 @@ BinarySpaceTree<DistanceType, StatisticType, MatType, BoundType, SplitType>::
template<typename DistanceType,
typename StatisticType,
typename MatType,
template<typename BoundDistanceType, typename...> class BoundType,
template<typename SplitBoundType, typename SplitMatType>
class SplitType>
template<typename BoundDistanceType,
typename BoundElemType,
typename...> class BoundType,
template<typename SplitBoundType,
typename SplitMatType> class SplitType>
inline bool BinarySpaceTree<DistanceType, StatisticType, MatType, BoundType,
SplitType>::IsLeaf() const
{
@@ -601,9 +633,11 @@ inline bool BinarySpaceTree<DistanceType, StatisticType, MatType, BoundType,
template<typename DistanceType,
typename StatisticType,
typename MatType,
template<typename BoundDistanceType, typename...> class BoundType,
template<typename SplitBoundType, typename SplitMatType>
class SplitType>
template<typename BoundDistanceType,
typename BoundElemType,
typename...> class BoundType,
template<typename SplitBoundType,
typename SplitMatType> class SplitType>
inline size_t BinarySpaceTree<DistanceType, StatisticType, MatType, BoundType,
SplitType>::NumChildren() const
{
@@ -622,9 +656,11 @@ inline size_t BinarySpaceTree<DistanceType, StatisticType, MatType, BoundType,
template<typename DistanceType,
typename StatisticType,
typename MatType,
template<typename BoundDistanceType, typename...> class BoundType,
template<typename SplitBoundType, typename SplitMatType>
class SplitType>
template<typename BoundDistanceType,
typename BoundElemType,
typename...> class BoundType,
template<typename SplitBoundType,
typename SplitMatType> class SplitType>
template<typename VecType>
size_t BinarySpaceTree<DistanceType, StatisticType, MatType, BoundType,
SplitType>::GetNearestChild(
@@ -646,9 +682,11 @@ size_t BinarySpaceTree<DistanceType, StatisticType, MatType, BoundType,
template<typename DistanceType,
typename StatisticType,
typename MatType,
template<typename BoundDistanceType, typename...> class BoundType,
template<typename SplitBoundType, typename SplitMatType>
class SplitType>
template<typename BoundDistanceType,
typename BoundElemType,
typename...> class BoundType,
template<typename SplitBoundType,
typename SplitMatType> class SplitType>
template<typename VecType>
size_t BinarySpaceTree<DistanceType, StatisticType, MatType, BoundType,
SplitType>::GetFurthestChild(
@@ -670,9 +708,11 @@ size_t BinarySpaceTree<DistanceType, StatisticType, MatType, BoundType,
template<typename DistanceType,
typename StatisticType,
typename MatType,
template<typename BoundDistanceType, typename...> class BoundType,
template<typename SplitBoundType, typename SplitMatType>
class SplitType>
template<typename BoundDistanceType,
typename BoundElemType,
typename...> class BoundType,
template<typename SplitBoundType,
typename SplitMatType> class SplitType>
size_t BinarySpaceTree<DistanceType, StatisticType, MatType, BoundType,
SplitType>::GetNearestChild(const BinarySpaceTree& queryNode)
{
@@ -695,9 +735,11 @@ size_t BinarySpaceTree<DistanceType, StatisticType, MatType, BoundType,
template<typename DistanceType,
typename StatisticType,
typename MatType,
template<typename BoundDistanceType, typename...> class BoundType,
template<typename SplitBoundType, typename SplitMatType>
class SplitType>
template<typename BoundDistanceType,
typename BoundElemType,
typename...> class BoundType,
template<typename SplitBoundType,
typename SplitMatType> class SplitType>
size_t BinarySpaceTree<DistanceType, StatisticType, MatType, BoundType,
SplitType>::GetFurthestChild(const BinarySpaceTree& queryNode)
{
@@ -720,9 +762,11 @@ size_t BinarySpaceTree<DistanceType, StatisticType, MatType, BoundType,
template<typename DistanceType,
typename StatisticType,
typename MatType,
template<typename BoundDistanceType, typename...> class BoundType,
template<typename SplitBoundType, typename SplitMatType>
class SplitType>
template<typename BoundDistanceType,
typename BoundElemType,
typename...> class BoundType,
template<typename SplitBoundType,
typename SplitMatType> class SplitType>
inline
typename BinarySpaceTree<DistanceType, StatisticType, MatType, BoundType,
SplitType>::ElemType
@@ -746,9 +790,11 @@ BinarySpaceTree<DistanceType, StatisticType, MatType, BoundType,
template<typename DistanceType,
typename StatisticType,
typename MatType,
template<typename BoundDistanceType, typename...> class BoundType,
template<typename SplitBoundType, typename SplitMatType>
class SplitType>
template<typename BoundDistanceType,
typename BoundElemType,
typename...> class BoundType,
template<typename SplitBoundType,
typename SplitMatType> class SplitType>
inline
typename BinarySpaceTree<DistanceType, StatisticType, MatType, BoundType,
SplitType>::ElemType
@@ -762,9 +808,11 @@ BinarySpaceTree<DistanceType, StatisticType, MatType, BoundType,
template<typename DistanceType,
typename StatisticType,
typename MatType,
template<typename BoundDistanceType, typename...> class BoundType,
template<typename SplitBoundType, typename SplitMatType>
class SplitType>
template<typename BoundDistanceType,
typename BoundElemType,
typename...> class BoundType,
template<typename SplitBoundType,
typename SplitMatType> class SplitType>
inline
typename BinarySpaceTree<DistanceType, StatisticType, MatType, BoundType,
SplitType>::ElemType
@@ -780,9 +828,11 @@ BinarySpaceTree<DistanceType, StatisticType, MatType, BoundType,
template<typename DistanceType,
typename StatisticType,
typename MatType,
template<typename BoundDistanceType, typename...> class BoundType,
template<typename SplitBoundType, typename SplitMatType>
class SplitType>
template<typename BoundDistanceType,
typename BoundElemType,
typename...> class BoundType,
template<typename SplitBoundType,
typename SplitMatType> class SplitType>
inline BinarySpaceTree<DistanceType, StatisticType, MatType, BoundType,
SplitType>&
BinarySpaceTree<DistanceType, StatisticType, MatType, BoundType,
@@ -800,9 +850,11 @@ inline BinarySpaceTree<DistanceType, StatisticType, MatType, BoundType,
template<typename DistanceType,
typename StatisticType,
typename MatType,
template<typename BoundDistanceType, typename...> class BoundType,
template<typename SplitBoundType, typename SplitMatType>
class SplitType>
template<typename BoundDistanceType,
typename BoundElemType,
typename...> class BoundType,
template<typename SplitBoundType,
typename SplitMatType> class SplitType>
inline size_t BinarySpaceTree<DistanceType, StatisticType, MatType, BoundType,
SplitType>::NumPoints() const
{
@@ -818,9 +870,11 @@ inline size_t BinarySpaceTree<DistanceType, StatisticType, MatType, BoundType,
template<typename DistanceType,
typename StatisticType,
typename MatType,
template<typename BoundDistanceType, typename...> class BoundType,
template<typename SplitBoundType, typename SplitMatType>
class SplitType>
template<typename BoundDistanceType,
typename BoundElemType,
typename...> class BoundType,
template<typename SplitBoundType,
typename SplitMatType> class SplitType>
inline size_t BinarySpaceTree<DistanceType, StatisticType, MatType, BoundType,
SplitType>::NumDescendants() const
{
@@ -833,9 +887,11 @@ inline size_t BinarySpaceTree<DistanceType, StatisticType, MatType, BoundType,
template<typename DistanceType,
typename StatisticType,
typename MatType,
template<typename BoundDistanceType, typename...> class BoundType,
template<typename SplitBoundType, typename SplitMatType>
class SplitType>
template<typename BoundDistanceType,
typename BoundElemType,
typename...> class BoundType,
template<typename SplitBoundType,
typename SplitMatType> class SplitType>
inline size_t BinarySpaceTree<DistanceType, StatisticType, MatType, BoundType,
SplitType>::Descendant(const size_t index) const
{
@@ -848,9 +904,11 @@ inline size_t BinarySpaceTree<DistanceType, StatisticType, MatType, BoundType,
template<typename DistanceType,
typename StatisticType,
typename MatType,
template<typename BoundDistanceType, typename...> class BoundType,
template<typename SplitBoundType, typename SplitMatType>
class SplitType>
template<typename BoundDistanceType,
typename BoundElemType,
typename...> class BoundType,
template<typename SplitBoundType,
typename SplitMatType> class SplitType>
inline size_t BinarySpaceTree<DistanceType, StatisticType, MatType, BoundType,
SplitType>::Point(const size_t index) const
{
@@ -860,13 +918,15 @@ inline size_t BinarySpaceTree<DistanceType, StatisticType, MatType, BoundType,
template<typename DistanceType,
typename StatisticType,
typename MatType,
template<typename BoundDistanceType, typename...> class BoundType,
template<typename SplitBoundType, typename SplitMatType>
class SplitType>
template<typename BoundDistanceType,
typename BoundElemType,
typename...> class BoundType,
template<typename SplitBoundType,
typename SplitMatType> class SplitType>
void
BinarySpaceTree<DistanceType, StatisticType, MatType, BoundType, SplitType>::
SplitNode(const size_t maxLeafSize,
SplitType<BoundType<DistanceType>, MatType>& splitter)
SplitType<BoundType<DistanceType, ElemType>, MatType>& splitter)
{
// We need to expand the bounds of this node properly.
UpdateBound(bound);
@@ -927,14 +987,16 @@ BinarySpaceTree<DistanceType, StatisticType, MatType, BoundType, SplitType>::
template<typename DistanceType,
typename StatisticType,
typename MatType,
template<typename BoundDistanceType, typename...> class BoundType,
template<typename SplitBoundType, typename SplitMatType>
class SplitType>
template<typename BoundDistanceType,
typename BoundElemType,
typename...> class BoundType,
template<typename SplitBoundType,
typename SplitMatType> class SplitType>
void
BinarySpaceTree<DistanceType, StatisticType, MatType, BoundType, SplitType>::
SplitNode(std::vector<size_t>& oldFromNew,
const size_t maxLeafSize,
SplitType<BoundType<DistanceType>, MatType>& splitter)
SplitType<BoundType<DistanceType, ElemType>, MatType>& splitter)
{
// We need to expand the bounds of this node properly.
UpdateBound(bound);
@@ -996,9 +1058,11 @@ SplitNode(std::vector<size_t>& oldFromNew,
template<typename DistanceType,
typename StatisticType,
typename MatType,
template<typename BoundDistanceType, typename...> class BoundType,
template<typename SplitBoundType, typename SplitMatType>
class SplitType>
template<typename BoundDistanceType,
typename BoundElemType,
typename...> class BoundType,
template<typename SplitBoundType,
typename SplitMatType> class SplitType>
template<typename BoundType2>
void
BinarySpaceTree<DistanceType, StatisticType, MatType, BoundType, SplitType>::
@@ -1011,12 +1075,14 @@ UpdateBound(BoundType2& boundToUpdate)
template<typename DistanceType,
typename StatisticType,
typename MatType,
template<typename BoundDistanceType, typename...> class BoundType,
template<typename SplitBoundType, typename SplitMatType>
class SplitType>
template<typename BoundDistanceType,
typename BoundElemType,
typename...> class BoundType,
template<typename SplitBoundType,
typename SplitMatType> class SplitType>
void
BinarySpaceTree<DistanceType, StatisticType, MatType, BoundType, SplitType>::
UpdateBound(HollowBallBound<DistanceType>& boundToUpdate)
UpdateBound(HollowBallBound<DistanceType, ElemType>& boundToUpdate)
{
if (!parent)
{
@@ -1039,9 +1105,11 @@ UpdateBound(HollowBallBound<DistanceType>& boundToUpdate)
template<typename DistanceType,
typename StatisticType,
typename MatType,
template<typename BoundDistanceType, typename...> class BoundType,
template<typename SplitBoundType, typename SplitMatType>
class SplitType>
template<typename BoundDistanceType,
typename BoundElemType,
typename...> class BoundType,
template<typename SplitBoundType,
typename SplitMatType> class SplitType>
BinarySpaceTree<DistanceType, StatisticType, MatType, BoundType, SplitType>::
BinarySpaceTree() :
left(NULL),
@@ -1063,9 +1131,11 @@ BinarySpaceTree<DistanceType, StatisticType, MatType, BoundType, SplitType>::
template<typename DistanceType,
typename StatisticType,
typename MatType,
template<typename BoundDistanceType, typename...> class BoundType,
template<typename SplitBoundType, typename SplitMatType>
class SplitType>
template<typename BoundDistanceType,
typename BoundElemType,
typename...> class BoundType,
template<typename SplitBoundType,
typename SplitMatType> class SplitType>
template<typename Archive>
void
BinarySpaceTree<DistanceType, StatisticType, MatType, BoundType, SplitType>::
@@ -35,9 +35,11 @@ struct QueueFrame
template<typename DistanceType,
typename StatisticType,
typename MatType,
template<typename BoundDistanceType, typename...> class BoundType,
template<typename SplitBoundType, typename SplitMatType>
class SplitType>
template<typename BoundDistanceType,
typename BoundElemType,
typename...> class BoundType,
template<typename SplitBoundType,
typename SplitMatType> class SplitType>
template<typename RuleType>
class BinarySpaceTree<DistanceType, StatisticType, MatType, BoundType,
SplitType>::BreadthFirstDualTreeTraverser
@@ -22,9 +22,11 @@ namespace mlpack {
template<typename DistanceType,
typename StatisticType,
typename MatType,
template<typename BoundDistanceType, typename...> class BoundType,
template<typename SplitBoundType, typename SplitMatType>
class SplitType>
template<typename BoundDistanceType,
typename BoundElemType,
typename...> class BoundType,
template<typename SplitBoundType,
typename SplitMatType> class SplitType>
template<typename RuleType>
BinarySpaceTree<DistanceType, StatisticType, MatType, BoundType, SplitType>::
BreadthFirstDualTreeTraverser<RuleType>::BreadthFirstDualTreeTraverser(
@@ -50,9 +52,11 @@ bool operator<(const QueueFrame<TreeType, TraversalInfoType>& a,
template<typename DistanceType,
typename StatisticType,
typename MatType,
template<typename BoundDistanceType, typename...> class BoundType,
template<typename SplitBoundType, typename SplitMatType>
class SplitType>
template<typename BoundDistanceType,
typename BoundElemType,
typename...> class BoundType,
template<typename SplitBoundType,
typename SplitMatType> class SplitType>
template<typename RuleType>
void
BinarySpaceTree<DistanceType, StatisticType, MatType, BoundType, SplitType>::
@@ -91,9 +95,11 @@ BreadthFirstDualTreeTraverser<RuleType>::Traverse(
template<typename DistanceType,
typename StatisticType,
typename MatType,
template<typename BoundDistanceType, typename...> class BoundType,
template<typename SplitBoundType, typename SplitMatType>
class SplitType>
template<typename BoundDistanceType,
typename BoundElemType,
typename...> class BoundType,
template<typename SplitBoundType,
typename SplitMatType> class SplitType>
template<typename RuleType>
void BinarySpaceTree<DistanceType, StatisticType, MatType, BoundType, SplitType>::
BreadthFirstDualTreeTraverser<RuleType>::Traverse(
@@ -24,9 +24,11 @@ namespace mlpack {
template<typename DistanceType,
typename StatisticType,
typename MatType,
template<typename BoundDistanceType, typename...> class BoundType,
template<typename SplitBoundType, typename SplitMatType>
class SplitType>
template<typename BoundDistanceType,
typename BoundElemType,
typename...> class BoundType,
template<typename SplitBoundType,
typename SplitMatType> class SplitType>
template<typename RuleType>
class BinarySpaceTree<DistanceType, StatisticType, MatType, BoundType,
SplitType>::DualTreeTraverser
@@ -22,9 +22,11 @@ namespace mlpack {
template<typename DistanceType,
typename StatisticType,
typename MatType,
template<typename BoundDistanceType, typename...> class BoundType,
template<typename SplitBoundType, typename SplitMatType>
class SplitType>
template<typename BoundDistanceType,
typename BoundElemType,
typename...> class BoundType,
template<typename SplitBoundType,
typename SplitMatType> class SplitType>
template<typename RuleType>
BinarySpaceTree<DistanceType, StatisticType, MatType, BoundType, SplitType>::
DualTreeTraverser<RuleType>::DualTreeTraverser(RuleType& rule) :
@@ -38,9 +40,11 @@ DualTreeTraverser<RuleType>::DualTreeTraverser(RuleType& rule) :
template<typename DistanceType,
typename StatisticType,
typename MatType,
template<typename BoundDistanceType, typename...> class BoundType,
template<typename SplitBoundType, typename SplitMatType>
class SplitType>
template<typename BoundDistanceType,
typename BoundElemType,
typename...> class BoundType,
template<typename SplitBoundType,
typename SplitMatType> class SplitType>
template<typename RuleType>
void
BinarySpaceTree<DistanceType, StatisticType, MatType, BoundType, SplitType>::
@@ -23,9 +23,11 @@ namespace mlpack {
template<typename DistanceType,
typename StatisticType,
typename MatType,
template<typename BoundDistanceType, typename...> class BoundType,
template<typename SplitBoundType, typename SplitMatType>
class SplitType>
template<typename BoundDistanceType,
typename BoundElemType,
typename...> class BoundType,
template<typename SplitBoundType,
typename SplitMatType> class SplitType>
template<typename RuleType>
class BinarySpaceTree<DistanceType, StatisticType, MatType, BoundType,
SplitType>::SingleTreeTraverser
@@ -24,9 +24,11 @@ namespace mlpack {
template<typename DistanceType,
typename StatisticType,
typename MatType,
template<typename BoundDistanceType, typename...> class BoundType,
template<typename SplitBoundType, typename SplitMatType>
class SplitType>
template<typename BoundDistanceType,
typename BoundElemType,
typename...> class BoundType,
template<typename SplitBoundType,
typename SplitMatType> class SplitType>
template<typename RuleType>
BinarySpaceTree<DistanceType, StatisticType, MatType, BoundType, SplitType>::
SingleTreeTraverser<RuleType>::SingleTreeTraverser(RuleType& rule) :
@@ -37,9 +39,11 @@ SingleTreeTraverser<RuleType>::SingleTreeTraverser(RuleType& rule) :
template<typename DistanceType,
typename StatisticType,
typename MatType,
template<typename BoundDistanceType, typename...> class BoundType,
template<typename SplitBoundType, typename SplitMatType>
class SplitType>
template<typename BoundDistanceType,
typename BoundElemType,
typename...> class BoundType,
template<typename SplitBoundType,
typename SplitMatType> class SplitType>
template<typename RuleType>
void
BinarySpaceTree<DistanceType, StatisticType, MatType, BoundType, SplitType>::
@@ -26,9 +26,11 @@ namespace mlpack {
template<typename DistanceType,
typename StatisticType,
typename MatType,
template<typename BoundDistanceType, typename...> class BoundType,
template<typename SplitBoundType, typename SplitMatType>
class SplitType>
template<typename BoundDistanceType,
typename BoundElemType,
typename...> class BoundType,
template<typename SplitBoundType,
typename SplitMatType> class SplitType>
class TreeTraits<BinarySpaceTree<
DistanceType, StatisticType, MatType, BoundType, SplitType>>
{
@@ -80,7 +82,9 @@ class TreeTraits<BinarySpaceTree<
template<typename DistanceType,
typename StatisticType,
typename MatType,
template<typename BoundDistanceType, typename...> class BoundType>
template<typename BoundDistanceType,
typename BoundElemType,
typename...> class BoundType>
class TreeTraits<BinarySpaceTree<
DistanceType, StatisticType, MatType, BoundType, RPTreeMaxSplit>>
{
@@ -130,9 +134,11 @@ class TreeTraits<BinarySpaceTree<
template<typename DistanceType,
typename StatisticType,
typename MatType,
template<typename BoundDistanceType, typename...> class BoundType>
class TreeTraits<BinarySpaceTree<DistanceType, StatisticType, MatType, BoundType,
RPTreeMeanSplit>>
template<typename BoundDistanceType,
typename BoundElemType,
typename...> class BoundType>
class TreeTraits<BinarySpaceTree<DistanceType, StatisticType, MatType,
BoundType, RPTreeMeanSplit>>
{
public:
/**
@@ -243,7 +243,7 @@ CalculateValue(const VecType& pt,
res(i) ^= t;
// We should rearrange bits in order to compare two Hilbert values faster.
arma::Col<HilbertElemType> rearrangedResult(pt.n_rows, arma::fill::zeros);
arma::Col<HilbertElemType> rearrangedResult(pt.n_rows);
for (size_t i = 0; i < order; ++i)
for (size_t j = 0; j < pt.n_rows; ++j)
@@ -106,9 +106,9 @@ void RStarTreeSplit::PickLeafSplit(TreeType* tree,
// We'll store each of the three scores for each distribution.
const size_t numPossibleSplits = tree->MaxLeafSize() -
2 * tree->MinLeafSize() + 2;
arma::Col<ElemType> areas(numPossibleSplits, arma::fill::zeros);
arma::Col<ElemType> margins(numPossibleSplits, arma::fill::zeros);
arma::Col<ElemType> overlaps(numPossibleSplits, arma::fill::zeros);
arma::Col<ElemType> areas(numPossibleSplits);
arma::Col<ElemType> margins(numPossibleSplits);
arma::Col<ElemType> overlaps(numPossibleSplits);
for (size_t i = 0; i < numPossibleSplits; ++i)
{
@@ -310,9 +310,9 @@ bool RStarTreeSplit::SplitNonLeafNode(
// each rectangle.
const size_t numPossibleSplits = tree->MaxNumChildren() -
2 * tree->MinNumChildren() + 2;
arma::Col<ElemType> areas(2 * numPossibleSplits, arma::fill::zeros);
arma::Col<ElemType> margins(2 * numPossibleSplits, arma::fill::zeros);
arma::Col<ElemType> overlaps(2 * numPossibleSplits, arma::fill::zeros);
arma::Col<ElemType> areas(2 * numPossibleSplits);
arma::Col<ElemType> margins(2 * numPossibleSplits);
arma::Col<ElemType> overlaps(2 * numPossibleSplits);
for (size_t i = 0; i < numPossibleSplits; ++i)
{
@@ -67,9 +67,9 @@ class AxisParallelProjVector
* @param bound Bound to be projected.
* @return Range of projected values.
*/
template<typename DistanceType, typename VecType>
RangeType<typename VecType::elem_type> Project(
const BallBound<DistanceType, VecType>& bound) const
template<typename DistanceType, typename ElemType, typename VecType>
RangeType<ElemType> Project(
const BallBound<DistanceType, ElemType, VecType>& bound) const
{
return bound[dim];
}
@@ -128,11 +128,10 @@ class ProjVector
* @param bound Bound to be projected.
* @return Range of projected values.
*/
template<typename DistanceType, typename VecType>
RangeType<typename VecType::elem_type> Project(
const BallBound<DistanceType, VecType>& bound) const
template<typename DistanceType, typename ElemType, typename VecType>
RangeType<ElemType> Project(
const BallBound<DistanceType, ElemType, VecType>& bound) const
{
typedef typename VecType::elem_type ElemType;
const double center = Project(bound.Center());
const ElemType radius = bound.Radius();
return RangeType<ElemType>(center - radius, center + radius);
+11 -29
View File
@@ -50,7 +50,7 @@ struct IsCube
};
// Commenting out the first template per case, because
// Visual Studio doesn't like this instantiaion pattern (error C2910).
// Visual Studio doesn't like this instantiation pattern (error C2910).
// template<>
template<typename eT>
struct IsVector<arma::Col<eT> >
@@ -105,35 +105,17 @@ struct IsCube<arma::Cube<eT> >
const static bool value = true;
};
template<typename eT>
struct IsVector<arma::SpSubview_col<eT> >
{
const static bool value = true;
};
#if ((ARMA_VERSION_MAJOR >= 10) || \
((ARMA_VERSION_MAJOR == 9) && (ARMA_VERSION_MINOR >= 869)))
// Armadillo 9.869+ has SpSubview_col and SpSubview_row
template<typename eT>
struct IsVector<arma::SpSubview_col<eT> >
{
const static bool value = true;
};
template<typename eT>
struct IsVector<arma::SpSubview_row<eT> >
{
const static bool value = true;
};
#else
// fallback for older Armadillo versions
template<typename eT>
struct IsVector<arma::SpSubview<eT> >
{
const static bool value = true;
};
#endif
template<typename eT>
struct IsVector<arma::SpSubview_row<eT> >
{
const static bool value = true;
};
// Get the row vector type corresponding to a given MatType.
@@ -0,0 +1,44 @@
/**
* @file core/util/first_element_is_arma.hpp
* @author Ryan Curtin
*
* Utility struct to detect whether the first element in a parameter pack is an
* Armadillo type.
*/
#ifndef MLPACK_CORE_UTIL_FIRST_ELEMENT_IS_ARMA_HPP
#define MLPACK_CORE_UTIL_FIRST_ELEMENT_IS_ARMA_HPP
#include <mlpack/prereqs.hpp>
namespace mlpack {
// This utility struct returns the first type of a parameter pack.
template<typename... CallbackTypes>
struct First
{
typedef void type;
};
// This matches whenever CallbackTypes has one or more elements.
template<typename T, typename... CallbackTypes>
struct First<T, CallbackTypes...>
{
typedef T type;
};
// This utility template struct detects whether the first element in a
// parameter pack is an Armadillo type. It is entirely for the deprecated
// constructor below and can be removed when that is removed during the
// release of mlpack 5.0.0.
template<typename... CallbackTypes>
struct FirstElementIsArma
{
static constexpr bool value = arma::is_arma_type<
typename std::remove_reference<
typename First<CallbackTypes...>::type
>::type>::value;
};
}
#endif
+27
View File
@@ -0,0 +1,27 @@
/**
* @file core/util/omp_reductions.hpp
* @author Mark Fischinger
*
* Custom OpenMP reductions.
*
* 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_CORE_UTIL_OMP_REDUCTIONS_HPP
#define MLPACK_CORE_UTIL_OMP_REDUCTIONS_HPP
namespace mlpack {
// Custom reduction for arma::mat
#pragma omp declare reduction(matAdd : arma::mat : omp_out += omp_in) \
initializer(omp_priv = arma::mat(omp_orig.n_rows, omp_orig.n_cols))
// Custom reduction for arma::Col<size_t>
#pragma omp declare reduction(colAdd : arma::Col<size_t> : omp_out += omp_in) \
initializer(omp_priv = arma::Col<size_t>(omp_orig.n_elem))
} // namespace mlpack
#endif
+27
View File
@@ -1,6 +1,8 @@
/**
* @file core/util/using.hpp
* @author Omar Shrit
* @author Ryan Curtin
* @author Conrad Sanderson
*
* This is a set of `using` statements to mitigate any possible risks or
* conflicts with local functions. The compiler is supposed to proritise the
@@ -75,6 +77,31 @@ namespace mlpack {
#endif
// By default, assume that we are using an Armadillo object.
template<typename MatType>
struct GetFillType
{
static constexpr const decltype(arma::fill::none)& none = arma::fill::none;
static constexpr const decltype(arma::fill::zeros)& zeros = arma::fill::zeros;
static constexpr const decltype(arma::fill::ones)& ones = arma::fill::ones;
static constexpr const decltype(arma::fill::randu)& randu = arma::fill::randu;
static constexpr const decltype(arma::fill::randn)& randn = arma::fill::randn;
};
#ifdef MLPACK_HAS_COOT
// If the matrix type is a Bandicoot type, use Bandicoot fill objects instead.
template<typename MatType,
typename = typename std::enable_if<is_coot_type<MatType>::value>::type*>
struct GetFillType
{
static constexpr const decltype(coot::fill::none)& none = coot::fill::none;
static constexpr const decltype(coot::fill::zeros)& zeros = coot::fill::zeros;
static constexpr const decltype(coot::fill::ones)& ones = coot::fill::ones;
static constexpr const decltype(coot::fill::randu)& randu = coot::fill::randu;
static constexpr const decltype(coot::fill::randn)& randn = coot::fill::randn;
};
#endif
} // namespace mlpack
#endif
+1 -1
View File
@@ -26,7 +26,7 @@ add_all_bindings(hmm hmm_train "Misc. / Other")
add_all_bindings(hmm hmm_generate "Misc. / Other")
add_all_bindings(hmm hmm_loglik "Misc. / Other")
add_all_bindings(hmm hmm_viterbi "Misc. / Other")
add_all_bindings(hoeffding_trees hoeffding_tree "Clustering")
add_all_bindings(hoeffding_trees hoeffding_tree "Classification")
add_all_bindings(kde kde "Misc. / Other")
add_all_bindings(kernel_pca kernel_pca "Transformations")
add_all_bindings(kmeans kmeans "Clustering")
@@ -132,7 +132,7 @@ class NaiveConvolution
// Pad filter and input to the working output shape.
InMatType inputPadded(input.n_rows + 2 * paddingRows,
input.n_cols + 2 * paddingCols, arma::fill::zeros);
input.n_cols + 2 * paddingCols);
inputPadded.submat(paddingRows, paddingCols, paddingRows + input.n_rows - 1,
paddingCols + input.n_cols - 1) = input;
+2 -1
View File
@@ -470,7 +470,8 @@ typename MatType::elem_type FFN<
{
typename MatType::elem_type res = 0;
res += EvaluateWithGradient(parameters, 0, gradient, 1);
MatType tmpGradient(gradient.n_rows, gradient.n_cols, arma::fill::none);
MatType tmpGradient(gradient.n_rows, gradient.n_cols,
GetFillType<MatType>::none);
for (size_t i = 1; i < predictors.n_cols; ++i)
{
res += EvaluateWithGradient(parameters, i, tmpGradient, 1);
@@ -401,7 +401,7 @@ void ConvolutionType<
dilatedMappedError.zeros(mappedError.n_rows * strideWidth -
(strideWidth - 1), mappedError.n_cols * strideHeight -
(strideHeight - 1), mappedError.n_slices);
#pragma omp parallel for collapse(3)
#pragma omp parallel for collapse(3) schedule(static)
for (size_t i = 0; i < mappedError.n_slices; ++i)
{
for (size_t j = 0; j < mappedError.n_cols; ++j)
@@ -415,26 +415,26 @@ void ConvolutionType<
}
}
#pragma omp parallel for
#pragma omp parallel for schedule(static)
for (size_t map = 0; map < (size_t) (maps * inMaps); ++map)
{
Rotate180(weight.slice(map), rotatedFilters.slice(map));
}
MatType output(apparentWidth * apparentHeight * inMaps * higherInDimensions,
batchSize, arma::fill::zeros);
batchSize);
CubeType outputCube;
MakeAlias(outputCube, output, apparentWidth, apparentHeight,
inMaps * higherInDimensions * batchSize);
// See Forward() for the overall iteration strategy.
#pragma omp parallel for schedule(dynamic)
for (size_t offset = 0; offset < (higherInDimensions * batchSize); ++offset)
{
const size_t fullInputOffset = offset * inMaps;
const size_t fullOutputOffset = offset * maps;
// Iterate over input maps.
#pragma omp parallel for
for (size_t inMap = 0; inMap < (size_t) inMaps; ++inMap)
{
// Iterate over output maps.
@@ -87,8 +87,15 @@ void DropoutType<MatType>::Forward(const MatType& input, MatType& output)
// Scale with input / (1 - ratio) and set values to zero with probability
// 'ratio'.
mask.randu(input.n_rows, input.n_cols);
mask.transform([&](double val) { return (val > ratio); });
output = input % mask * scale;
#pragma omp parallel for collapse(2)
for (size_t i = 0; i < input.n_rows; ++i)
{
for (size_t j = 0; j < input.n_cols; ++j)
{
mask(i, j) = (mask(i, j) > this->ratio) ? 1.0 : 0.0;
}
}
output = input % mask * this->scale;
}
}
@@ -440,7 +440,7 @@ void GroupedConvolutionType<
}
MatType output(apparentWidth * apparentHeight * inMaps * higherInDimensions,
batchSize, arma::fill::zeros);
batchSize);
CubeType outputCube;
MakeAlias(outputCube, output, apparentWidth, apparentHeight,
inMaps * higherInDimensions * batchSize);
@@ -46,6 +46,7 @@
#include <mlpack/methods/ann/layer/max_pooling.hpp>
#include <mlpack/methods/ann/layer/mean_pooling.hpp>
#include <mlpack/methods/ann/layer/multihead_attention.hpp>
#include <mlpack/methods/ann/layer/nearest_interpolation.hpp>
#include <mlpack/methods/ann/layer/noisylinear.hpp>
#include <mlpack/methods/ann/layer/padding.hpp>
#include <mlpack/methods/ann/layer/parametric_relu.hpp>
@@ -0,0 +1,112 @@
//
/**
* @filer methods/ann/layer/nearest_interpolation.hpp
* @author Andrew Furey
*
* 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_NEAREST_INTERPOLATION_HPP
#define MLPACK_METHODS_ANN_LAYER_NEAREST_INTERPOLATION_HPP
#include <mlpack/prereqs.hpp>
#include "layer.hpp"
namespace mlpack {
/**
* Definition and Implementation of the Nearest Interpolation Layer.
*
* Nearest interpolation is an mathematical technique, primarily used for
* scaling purposes. The input should be a 2D matrix and it can have
* a number of channels/units.
*
* @tparam InputType Type of the input data (arma::colvec, arma::mat,
* arma::sp_mat or arma::cube).
* @tparam MatType Type of the output data (arma::colvec, arma::mat,
* arma::sp_mat or arma::cube).
*/
template<typename MatType = arma::mat>
class NearestInterpolationType : public Layer<MatType>
{
public:
//! Create the NearestInterpolation object.
NearestInterpolationType();
/**Create NearestInterpolation Object with the same scaleFactor along
* each dimension.
* NOTE: scaleFactors must be a two element vector, the first element
* for scaling the first dimension and the second element for scaling
* the second dimension.
*
* If the input dimensions are n x m x ..., then the output dimensions
* will be (n x scaleFactors[0]) x (m x scaleFactors[1]) x ...
*
* @param scaleFactor Scale factors to scale each dimension by.
*/
NearestInterpolationType(const std::vector<double> scaleFactors);
NearestInterpolationType* Clone() const {
return new NearestInterpolationType(*this);
}
virtual ~NearestInterpolationType() { }
//! Copy the given NearestInterpolationType layer.
NearestInterpolationType(const NearestInterpolationType& other);
//! Take ownership of the given NearestInterpolationType layer.
NearestInterpolationType(NearestInterpolationType&& other);
//! Copy the given NearestInterpolationType layer.
NearestInterpolationType& operator=(const NearestInterpolationType& other);
//! Take ownership of the given NearestInterpolationType layer.
NearestInterpolationType& operator=(NearestInterpolationType&& other);
/**
* Forward pass through the layer. The layer interpolates
* the matrix using the given Nearest Interpolation method.
*
* @param input The input matrix.
* @param output The resulting interpolated output matrix.
*/
void Forward(const MatType& input, MatType& 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. Since the layer does not have any learn-able parameters,
* we just have to down-sample the gradient to make its size compatible with
* the input size.
*
* @param * (input) The input matrix.
* @param gradient The computed backward gradient.
* @param output The resulting down-sampled output.
*/
void Backward(const MatType& /*input*/,
const MatType& gradient,
MatType& output);
//! Compute the output dimensions of the layer, based on the internal values
//! of `InputDimensions()`.
void ComputeOutputDimensions();
/**
* Serialize the layer.
*/
template<typename Archive>
void serialize(Archive& ar, const uint32_t /* version */);
private:
//! Vector of scale factors to scale different dimensions.
std::vector<double> scaleFactors;
}; // class NearestInterpolation
typedef NearestInterpolationType<arma::mat> NearestInterpolation;
} // namespace mlpack
// Include implementation.
#include "nearest_interpolation_impl.hpp"
#endif
@@ -0,0 +1,177 @@
/**
* @file methods/ann/layer/nearest_interpolation_impl.hpp
* @author Andrew Furey
*
* Implementation of the NearestInterpolation layer.
*
* 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_NEAREST_INTERPOLATION_IMPL_HPP
#define MLPACK_METHODS_ANN_LAYER_NEAREST_INTERPOLATION_IMPL_HPP
// In case it hasn't yet been included.
#include "nearest_interpolation.hpp"
#include <stdexcept>
namespace mlpack {
template<typename MatType>
NearestInterpolationType<MatType>::NearestInterpolationType():
Layer<MatType>()
{
// Nothing to do here.
}
template<typename MatType>
NearestInterpolationType<MatType>::
NearestInterpolationType(const std::vector<double> scaleFactors) :
Layer<MatType>()
{
if (scaleFactors.size() != 2) {
throw std::runtime_error("Scale factors must have 2 dimensions");
}
this->scaleFactors = std::move(scaleFactors);
}
template<typename MatType>
NearestInterpolationType<MatType>::
NearestInterpolationType(const NearestInterpolationType& other) :
Layer<MatType>(),
scaleFactors(other.scaleFactors)
{
// Nothing to do here.
}
template<typename MatType>
NearestInterpolationType<MatType>::
NearestInterpolationType(NearestInterpolationType&& other) :
Layer<MatType>(std::move(other)),
scaleFactors(std::move(other.scaleFactors))
{
// Nothing to do here.
}
template<typename MatType>
NearestInterpolationType<MatType>&
NearestInterpolationType<MatType>::
operator=(const NearestInterpolationType& other)
{
if (&other != this)
{
Layer<MatType>::operator=(other);
scaleFactors = other.scaleFactors;
}
return *this;
}
template<typename MatType>
NearestInterpolationType<MatType>&
NearestInterpolationType<MatType>::
operator=(NearestInterpolationType&& other)
{
if (&other != this)
{
Layer<MatType>::operator=(std::move(other));
scaleFactors = std::move(other.scaleFactors);
}
return *this;
}
template<typename MatType>
void NearestInterpolationType<MatType>::Forward(
const MatType& input, MatType& output)
{
const size_t channels = this->inputDimensions[2];
const size_t outRowSize = this->outputDimensions[0];
const size_t outColSize = this->outputDimensions[1];
const size_t inRowSize = this->inputDimensions[0];
const size_t inColSize = this->inputDimensions[1];
arma::cube inputAsCube;
arma::cube outputAsCube;
MakeAlias(inputAsCube, input, inRowSize, inColSize, channels, 0, false);
MakeAlias(outputAsCube, output, outRowSize, outColSize, channels, 0, true);
for (size_t i = 0; i < outRowSize; ++i)
{
size_t rOrigin = std::floor(i / scaleFactors[0]);
for (size_t j = 0; j < outColSize; ++j)
{
size_t cOrigin = std::floor(j / scaleFactors[1]);
for (size_t k = 0; k < channels; ++k)
{
outputAsCube(i, j, k) = inputAsCube(rOrigin, cOrigin, k);
}
}
}
}
template<typename MatType>
void NearestInterpolationType<MatType>::Backward(
const MatType& /*input*/,
const MatType& gradient,
MatType& output)
{
const size_t channels = this->inputDimensions[2];
const size_t outRowSize = this->outputDimensions[0];
const size_t outColSize = this->outputDimensions[1];
const size_t inRowSize = this->inputDimensions[0];
const size_t inColSize = this->inputDimensions[1];
arma::cube outputAsCube;
arma::cube gradientAsCube;
MakeAlias(outputAsCube, output, inRowSize, inColSize, channels, 0, true);
MakeAlias(gradientAsCube, gradient, outRowSize, outColSize, channels, 0, false);
for (size_t i = 0; i < outRowSize; ++i)
{
size_t rOrigin = std::floor(i / scaleFactors[0]);
for (size_t j = 0; j < outColSize; ++j)
{
size_t cOrigin = std::floor(j / scaleFactors[1]);
for (size_t k = 0; k < channels; ++k)
{
outputAsCube(rOrigin, cOrigin, k) += gradientAsCube(i, j, k);
}
}
}
}
template<typename MatType>
void NearestInterpolationType<MatType>::ComputeOutputDimensions()
{
if (this->inputDimensions.size() < scaleFactors.size()) {
std::ostringstream oss;
oss << "NearestInterpolation::ComputeOutputDimensions(): input dimensions "
<< "must be at least 2 (received input with " << this->inputDimensions.size()
<< " dimensions)!";
throw std::runtime_error(oss.str());
}
this->outputDimensions = this->inputDimensions;
for (size_t i = 0; i < scaleFactors.size(); i++)
{
this->outputDimensions[i] = std::round(
(double)this->outputDimensions[i] * scaleFactors[i]);
}
}
template<typename MatType>
template<typename Archive>
void NearestInterpolationType<MatType>::serialize(
Archive& ar, const uint32_t /* version */)
{
ar(CEREAL_NVP(scaleFactors));
}
} // namespace mlpack
#endif
@@ -40,6 +40,8 @@ class BicubicInterpolation
//! Create the Bicubic Interpolation object.
BicubicInterpolation();
// TODO: use scaleFactors instead of outRowSize and outColSize
/**
* The constructor for the Bicubic Interpolation.
*
@@ -42,6 +42,8 @@ class BilinearInterpolationType : public Layer<InputType, OutputType>
//! Create the BilinearInterpolationType object.
BilinearInterpolationType();
// TODO: use scaleFactors instead of outRowSize and outColSize
/**
* The constructor for the Bilinear Interpolation. The input size will be set
* by the given input when the layer is used.
@@ -1,151 +0,0 @@
/**
* @file methods/ann/layer/nearest_interpolation.hpp
* @author Abhinav Anand
*
* 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_NEAREST_INTERPOLATION_HPP
#define MLPACK_METHODS_ANN_LAYER_NEAREST_INTERPOLATION_HPP
#include <mlpack/prereqs.hpp>
namespace mlpack {
/**
* Definition and Implementation of the Nearest Interpolation Layer.
*
* Nearest interpolation is an mathematical technique, primarily used for
* scaling purposes. The input should be a 2D matrix and it can have
* a number of channels/units.
*
* @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 NearestInterpolation
{
public:
//! Create the NearestInterpolation object.
NearestInterpolation();
/**
* The constructor for the NearestInterpolation.
*
* @param inRowSize Number of input rows.
* @param inColSize Number of input columns.
* @param outRowSize Number of output rows.
* @param outColSize Number of output columns.
* @param depth Number of input slices.
*/
NearestInterpolation(const size_t inRowSize,
const size_t inColSize,
const size_t outRowSize,
const size_t outColSize,
const size_t depth);
/**
* Forward pass through the layer. The layer interpolates
* the matrix using the given Nearest Interpolation method.
*
* @param input The input matrix.
* @param output The resulting interpolated output matrix.
*/
template<typename eT>
void Forward(const arma::Mat<eT>& input, arma::Mat<eT>& 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. Since the layer does not have any learn-able parameters,
* we just have to down-sample the gradient to make its size compatible with
* the input size.
*
* @param * (input) The input matrix.
* @param gradient The computed backward gradient.
* @param output The resulting down-sampled output.
*/
template<typename eT>
void Backward(const arma::Mat<eT>& /*input*/,
const arma::Mat<eT>& gradient,
arma::Mat<eT>& output);
//! 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 row size of the input.
size_t const& InRowSize() const { return inRowSize; }
//! Modify the row size of the input.
size_t& InRowSize() { return inRowSize; }
//! Get the column size of the input.
size_t const& InColSize() const { return inColSize; }
//! Modify the column size of the input.
size_t& InColSize() { return inColSize; }
//! Get the row size of the output.
size_t const& OutRowSize() const { return outRowSize; }
//! Modify the row size of the output.
size_t& OutRowSize() { return outRowSize; }
//! Get the column size of the output.
size_t const& OutColSize() const { return outColSize; }
//! Modify the column size of the output.
size_t& OutColSize() { return outColSize; }
//! Get the depth of the input.
size_t const& InDepth() const { return depth; }
//! Modify the depth of the input.
size_t& InDepth() { return depth; }
//! Get the shape of the input.
size_t InputShape() const
{
return inRowSize;
}
/**
* Serialize the layer.
*/
template<typename Archive>
void serialize(Archive& ar, const uint32_t /* version */);
private:
//! Locally stored row size of the input.
size_t inRowSize;
//! Locally stored column size of the input.
size_t inColSize;
//! Locally stored row size of the output.
size_t outRowSize;
//! Locally stored column size of the input.
size_t outColSize;
//! Locally stored depth of the input.
size_t depth;
//! Locally stored number of input points.
size_t batchSize;
//! Locally-stored delta object.
OutputDataType delta;
//! Locally-stored output parameter object.
OutputDataType outputParameter;
}; // class NearestInterpolation
} // namespace mlpack
// Include implementation.
#include "nearest_interpolation_impl.hpp"
#endif
@@ -1,159 +0,0 @@
/**
* @file methods/ann/layer/nearest_interpolation_impl.hpp
* @author Abhinav Anand
*
* Implementation of the NearestInterpolation layer.
*
* 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_NEAREST_INTERPOLATION_IMPL_HPP
#define MLPACK_METHODS_ANN_LAYER_NEAREST_INTERPOLATION_IMPL_HPP
// In case it hasn't yet been included.
#include "nearest_interpolation.hpp"
namespace mlpack {
template<typename InputDataType, typename OutputDataType>
NearestInterpolation<InputDataType, OutputDataType>::
NearestInterpolation():
inRowSize(0),
inColSize(0),
outRowSize(0),
outColSize(0),
depth(0),
batchSize(0)
{
// Nothing to do here.
}
template<typename InputDataType, typename OutputDataType>
NearestInterpolation<InputDataType, OutputDataType>::
NearestInterpolation(const size_t inRowSize,
const size_t inColSize,
const size_t outRowSize,
const size_t outColSize,
const size_t depth) :
inRowSize(inRowSize),
inColSize(inColSize),
outRowSize(outRowSize),
outColSize(outColSize),
depth(depth),
batchSize(0)
{
// Nothing to do here.
}
template<typename InputDataType, typename OutputDataType>
template<typename eT>
void NearestInterpolation<InputDataType, OutputDataType>::Forward(
const arma::Mat<eT>& input, arma::Mat<eT>& output)
{
batchSize = input.n_cols;
if (output.is_empty())
output.set_size(outRowSize * outColSize * depth, batchSize);
else
{
assert(output.n_rows == outRowSize * outColSize * depth);
assert(output.n_cols == batchSize);
}
assert(inRowSize >= 2);
assert(inColSize >= 2);
arma::cube inputAsCube(const_cast<arma::Mat<eT>&>(input).memptr(),
inRowSize, inColSize, depth * batchSize, false, false);
arma::cube outputAsCube(output.memptr(), outRowSize, outColSize,
depth * batchSize, false, true);
double scaleRow = (double) inRowSize / (double) outRowSize;
double scaleCol = (double) inColSize / (double) outColSize;
for (size_t i = 0; i < outRowSize; ++i)
{
const size_t rOrigin = std::floor(i * scaleRow);
for (size_t j = 0; j < outColSize; ++j)
{
const size_t cOrigin = std::floor(j * scaleCol);
for (size_t k = 0; k < depth * batchSize; ++k)
{
outputAsCube(i, j, k) = inputAsCube.slice(k)(
rOrigin, cOrigin);
}
}
}
}
template<typename InputDataType, typename OutputDataType>
template<typename eT>
void NearestInterpolation<InputDataType, OutputDataType>::Backward(
const arma::Mat<eT>& /*input*/,
const arma::Mat<eT>& gradient,
arma::Mat<eT>& output)
{
if (output.is_empty())
{
output.zeros(inRowSize * inColSize * depth, batchSize);
}
else
{
assert(output.n_rows == inRowSize * inColSize * depth);
assert(output.n_cols == batchSize);
}
assert(outRowSize >= 2);
assert(outColSize >= 2);
arma::cube outputAsCube(output.memptr(), inRowSize, inColSize,
depth * batchSize, false, true);
arma::cube gradientAsCube(((arma::Mat<eT>&) gradient).memptr(), outRowSize,
outColSize, depth * batchSize, false, false);
double scaleRow = (double)(inRowSize) / outRowSize;
double scaleCol = (double)(inColSize) / outColSize;
if (gradient.n_elem == output.n_elem)
{
outputAsCube = gradientAsCube;
}
else
{
for (size_t i = 0; i < outRowSize; ++i)
{
const size_t rOrigin = std::floor(i * scaleRow);
for (size_t j = 0; j < outColSize; ++j)
{
const size_t cOrigin = std::floor(j * scaleCol);
for (size_t k = 0; k < depth * batchSize; ++k)
{
outputAsCube(rOrigin, cOrigin, k) +=
gradientAsCube(i, j, k);
}
}
}
}
}
template<typename InputDataType, typename OutputDataType>
template<typename Archive>
void NearestInterpolation<InputDataType, OutputDataType>::serialize(
Archive& ar, const uint32_t /* version */)
{
ar(CEREAL_NVP(inRowSize));
ar(CEREAL_NVP(inColSize));
ar(CEREAL_NVP(outRowSize));
ar(CEREAL_NVP(outColSize));
ar(CEREAL_NVP(depth));
}
} // namespace mlpack
#endif
+1 -1
View File
@@ -156,7 +156,7 @@ void RepeatType<MatType>::ComputeOutputDimensions()
// element to the input elements. This will be used in the backward
// pass with a simple matrix multiplication.
backIdxs.set_size(inputSize, sizeMult);
UintCol counts(inputSize, arma::fill::zeros);
UintCol counts(inputSize);
for (size_t i = 0; i < outIdxs.n_elem; i++)
{
arma::uword r = outIdxs.at(i);
@@ -31,9 +31,9 @@ typename MatType::elem_type HingeLossType<MatType>::Forward(
const MatType& target)
{
MatType temp = target - (target == 0);
MatType temp_zeros(size(target), arma::fill::zeros);
MatType tempZeros(size(target));
MatType loss = max(temp_zeros, 1 - prediction % temp);
MatType loss = max(tempZeros, 1 - prediction % temp);
typename MatType::elem_type lossSum = accu(loss);
@@ -96,7 +96,7 @@ class SVDPlusPlusPolicy
{
// Iterate through each item which the user interacted with to calculate
// user vector.
arma::vec userVec(h.n_rows, arma::fill::zeros);
arma::vec userVec(h.n_rows);
arma::sp_mat::const_iterator it = implicitData.begin_col(user);
arma::sp_mat::const_iterator it_end = implicitData.end_col(user);
size_t implicitCount = 0;
@@ -124,7 +124,7 @@ class SVDPlusPlusPolicy
{
// Iterate through each item which the user interacted with to calculate
// user vector.
arma::vec userVec(h.n_rows, arma::fill::zeros);
arma::vec userVec(h.n_rows);
arma::sp_mat::const_iterator it = implicitData.begin_col(user);
arma::sp_mat::const_iterator it_end = implicitData.end_col(user);
size_t implicitCount = 0;
@@ -49,9 +49,9 @@ class ItemMeanNormalization
void Normalize(arma::mat& data)
{
const size_t itemNum = max(data.row(1)) + 1;
itemMean = arma::vec(itemNum, arma::fill::zeros);
itemMean = arma::vec(itemNum);
// Number of ratings for each item.
arma::Row<size_t> ratingNum(itemNum, arma::fill::zeros);
arma::Row<size_t> ratingNum(itemNum);
// Sum ratings for each item.
data.each_col([&](arma::vec& datapoint)
@@ -89,8 +89,8 @@ class ItemMeanNormalization
void Normalize(arma::sp_mat& cleanedData)
{
// Calculate itemMean.
itemMean = arma::vec(cleanedData.n_rows, arma::fill::zeros);
arma::Col<size_t> ratingNum(cleanedData.n_rows, arma::fill::zeros);
itemMean = arma::vec(cleanedData.n_rows);
arma::Col<size_t> ratingNum(cleanedData.n_rows);
arma::sp_mat::iterator it = cleanedData.begin();
arma::sp_mat::iterator it_end = cleanedData.end();
for (; it != it_end; ++it)
@@ -49,9 +49,9 @@ class UserMeanNormalization
void Normalize(arma::mat& data)
{
const size_t userNum = max(data.row(0)) + 1;
userMean = arma::vec(userNum, arma::fill::zeros);
userMean = arma::vec(userNum);
// Number of ratings for each user.
arma::Row<size_t> ratingNum(userNum, arma::fill::zeros);
arma::Row<size_t> ratingNum(userNum);
// Sum ratings for each user.
data.each_col([&](arma::vec& datapoint)
@@ -89,8 +89,8 @@ class UserMeanNormalization
void Normalize(arma::sp_mat& cleanedData)
{
// Calculate userMean.
userMean = arma::vec(cleanedData.n_cols, arma::fill::zeros);
arma::Col<size_t> ratingNum(cleanedData.n_cols, arma::fill::zeros);
userMean = arma::vec(cleanedData.n_cols);
arma::Col<size_t> ratingNum(cleanedData.n_cols);
arma::sp_mat::iterator it = cleanedData.begin();
arma::sp_mat::iterator it_end = cleanedData.end();
for (; it != it_end; ++it)
+1 -1
View File
@@ -112,7 +112,7 @@ size_t DBSCAN<RangeSearchType, PointSelectionPolicy>::Cluster(
// Get a count of all clusters.
const size_t numClusters = max(assignments) + 1;
arma::Col<size_t> counts(numClusters, arma::fill::zeros);
arma::Col<size_t> counts(numClusters);
for (size_t i = 0; i < assignments.n_elem; ++i)
counts[assignments[i]]++;
@@ -15,20 +15,9 @@
#include <mlpack/core.hpp>
#include "gini_gain.hpp"
#include "information_gain.hpp"
#include "mad_gain.hpp"
#include "mse_gain.hpp"
#include "best_binary_numeric_split.hpp"
#include "random_binary_numeric_split.hpp"
#include "best_binary_categorical_split.hpp"
#include "all_categorical_split.hpp"
#include "all_dimension_select.hpp"
#include "random_dimension_select.hpp"
#include "multiple_random_dimension_select.hpp"
#include "fitness_functions/fitness_functions.hpp"
#include "split_functions/split_functions.hpp"
#include "select_functions/select_functions.hpp"
namespace mlpack {
@@ -727,7 +727,7 @@ double DecisionTree<FitnessFunction,
}
// Figure out counts of children.
arma::Row<size_t> childCounts(numChildren, arma::fill::zeros);
arma::Row<size_t> childCounts(numChildren);
for (size_t i = begin; i < begin + count; ++i)
childCounts[childAssignments[i - begin]]++;
@@ -15,12 +15,9 @@
#include <mlpack/core.hpp>
#include "mad_gain.hpp"
#include "mse_gain.hpp"
#include "best_binary_numeric_split.hpp"
#include "all_categorical_split.hpp"
#include "random_binary_numeric_split.hpp"
#include "all_dimension_select.hpp"
#include "fitness_functions/fitness_functions.hpp"
#include "split_functions/split_functions.hpp"
#include "select_functions/select_functions.hpp"
namespace mlpack {
@@ -708,7 +708,7 @@ double DecisionTreeRegressor<FitnessFunction,
}
// Figure out counts of children.
arma::Row<size_t> childCounts(numChildren, arma::fill::zeros);
arma::Row<size_t> childCounts(numChildren);
for (size_t i = begin; i < begin + count; ++i)
childCounts[childAssignments[i - begin]]++;
@@ -0,0 +1,4 @@
#include "gini_gain.hpp"
#include "information_gain.hpp"
#include "mad_gain.hpp"
#include "mse_gain.hpp"
@@ -1,5 +1,5 @@
/**
* @file methods/decision_tree/gini_gain.hpp
* @file methods/decision_tree/fitness_functions/gini_gain.hpp
* @author Ryan Curtin
*
* The GiniGain class, which is a fitness function (FitnessFunction) for
@@ -68,7 +68,7 @@ class GiniGain
// Count the number of elements in each class. Use four auxiliary vectors
// to exploit SIMD instructions if possible.
arma::vec countSpace(4 * numClasses, arma::fill::zeros);
arma::vec countSpace(4 * numClasses);
arma::vec counts(countSpace.memptr(), numClasses, false, true);
arma::vec counts2(countSpace.memptr() + numClasses, numClasses, false,
true);
@@ -1,5 +1,5 @@
/**
* @file methods/decision_tree/information_gain.hpp
* @file methods/decision_tree/fitness_functions/information_gain.hpp
* @author Ryan Curtin
*
* An implementation of information gain, which can be used in place of Gini
@@ -69,7 +69,7 @@ class InformationGain
// Count the number of elements in each class. Use four auxiliary vectors
// to exploit SIMD instructions if possible.
arma::vec countSpace(4 * numClasses, arma::fill::zeros);
arma::vec countSpace(4 * numClasses);
arma::vec counts(countSpace.memptr(), numClasses, false, true);
arma::vec counts2(countSpace.memptr() + numClasses, numClasses, false,
true);
@@ -1,5 +1,5 @@
/**
* @file methods/decision_tree/mad_gain.hpp
* @file methods/decision_tree/fitness_functions/mad_gain.hpp
* @author Rishabh Garg
*
* The mean absolute deviation gain class, a fitness function for regression
@@ -15,7 +15,7 @@ n.
#define MLPACK_METHODS_DECISION_TREE_MAD_GAIN_HPP
#include <mlpack/prereqs.hpp>
#include "utils.hpp"
#include "mlpack/methods/decision_tree/utils.hpp"
namespace mlpack {
@@ -1,5 +1,5 @@
/**
* @file methods/decision_tree/mse_gain.hpp
* @file methods/decision_tree/fitness_functions/mse_gain.hpp
* @author Rishabh Garg
*
* The mean squared error gain class, which is a fitness funtion for
@@ -14,7 +14,7 @@
#define MLPACK_METHODS_DECISION_TREE_MSE_GAIN_HPP
#include <mlpack/prereqs.hpp>
#include "utils.hpp"
#include <mlpack/methods/decision_tree/utils.hpp>
namespace mlpack {
@@ -1,5 +1,5 @@
/**
* @file methods/decision_tree/all_dimension_select.hpp
* @file methods/decision_tree/select_functions/all_dimension_select.hpp
* @author Ryan Curtin
*
* Selects all dimensions for a split.
@@ -1,5 +1,5 @@
/**
* @file methods/decision_tree/multiple_random_dimension_select.hpp
* @file methods/decision_tree/select_functions/multiple_random_dimension_select.hpp
* @author Ryan Curtin
*
* Select a number of random dimensions to pick from.
@@ -1,5 +1,5 @@
/**
* @file methods/decision_tree/random_dimension_select.hpp
* @file methods/decision_tree/select_functions/random_dimension_select.hpp
* @author Ryan Curtin
*
* Selects one single random dimension to split on.
@@ -0,0 +1,3 @@
#include "all_dimension_select.hpp"
#include "multiple_random_dimension_select.hpp"
#include "random_dimension_select.hpp"
@@ -1,5 +1,5 @@
/**
* @file methods/decision_tree/all_categorical_split.hpp
* @file methods/decision_tree/split_functions/all_categorical_split.hpp
* @author Ryan Curtin
*
* This file defines a tree splitter that split a categorical feature into all
@@ -1,5 +1,5 @@
/**
* @file methods/decision_tree/all_categorical_split_impl.hpp
* @file methods/decision_tree/split_functions/all_categorical_split_impl.hpp
* @author Ryan Curtin
*
* Implementation of the AllCategoricalSplit categorical split class.
@@ -32,7 +32,7 @@ double AllCategoricalSplit<FitnessFunction>::SplitIfBetter(
{
// Count the number of elements in each potential child.
const double epsilon = 1e-7; // Tolerance for floating-point errors.
arma::Col<size_t> counts(numCategories, arma::fill::zeros);
arma::Col<size_t> counts(numCategories);
// If we are using weighted training, split the weights for each child too.
arma::vec childWeightSums;
@@ -58,7 +58,7 @@ double AllCategoricalSplit<FitnessFunction>::SplitIfBetter(
// Calculate the gain of the split. First we have to calculate the labels
// that would be assigned to each child.
arma::uvec childPositions(numCategories, arma::fill::zeros);
arma::uvec childPositions(numCategories);
std::vector<arma::Row<size_t>> childLabels(numCategories);
std::vector<arma::Row<double>> childWeights(numCategories);
@@ -129,7 +129,7 @@ double AllCategoricalSplit<FitnessFunction>::SplitIfBetter(
{
// Count the number of elements in each potential child.
const double epsilon = 1e-7; // Tolerance for floating-point errors.
arma::Col<size_t> counts(numCategories, arma::fill::zeros);
arma::Col<size_t> counts(numCategories);
// If we are using weighted training, split the weights for each child too.
arma::vec childWeightSums;
@@ -155,7 +155,7 @@ double AllCategoricalSplit<FitnessFunction>::SplitIfBetter(
// Calculate the gain of the split. First we have to calculate the labels
// that would be assigned to each child.
arma::uvec childPositions(numCategories, arma::fill::zeros);
arma::uvec childPositions(numCategories);
std::vector<arma::rowvec> childResponses(numCategories);
std::vector<arma::rowvec> childWeights(numCategories);
@@ -1,5 +1,5 @@
/**
* @file methods/decision_tree/all_categorical_split_impl.hpp
* @file methods/decision_tree/split_functions/all_categorical_split_impl.hpp
* @author Nikolay Apanasov (nikolay@apanasov.org)
*
* Implementation of the BestBinaryCategoricalSplit categorical split class.
@@ -46,7 +46,7 @@ double BestBinaryCategoricalSplit<FitnessFunction>::SplitIfBetter(
{
// Order the categories of variable vₖ by their proportion in class C₁
// and map each categorical vₖ to its categorical rank
arma::umat categoryCounts(numCategories, 2, arma::fill::zeros);
arma::umat categoryCounts(numCategories, 2);
arma::vec categoryP(numCategories);
size_t totalCount;
@@ -172,8 +172,8 @@ double BestBinaryCategoricalSplit<FitnessFunction>::SplitIfBetter(
// Order the categories of variable vₖ by increasing mean
// of the response y. categoryResponse[i, 0] will contain
// the mean response for category Cᵢ.
arma::vec categoryResponse(numCategories, arma::fill::zeros);
arma::uvec categoryCounts(numCategories, arma::fill::zeros);
arma::vec categoryResponse(numCategories);
arma::uvec categoryCounts(numCategories);
for (size_t i = 0; i < n; ++i)
{
@@ -1,5 +1,5 @@
/**
* @file methods/decision_tree/best_binary_numeric_split.hpp
* @file methods/decision_tree/split_functions/best_binary_numeric_split.hpp
* @author Ryan Curtin
*
* A tree splitter that finds the best binary numeric split.
@@ -13,7 +13,7 @@
#define MLPACK_METHODS_DECISION_TREE_BEST_BINARY_NUMERIC_SPLIT_HPP
#include <mlpack/prereqs.hpp>
#include "mse_gain.hpp"
#include <mlpack/methods/decision_tree/fitness_functions/mse_gain.hpp>
#include <mlpack/core/util/sfinae_utility.hpp>
@@ -1,5 +1,5 @@
/**
* @file methods/decision_tree/best_binary_numeric_split_impl.hpp
* @file methods/decision_tree/split_functions/best_binary_numeric_split_impl.hpp
* @author Ryan Curtin
*
* Implementation of strategy that finds the best binary numeric split.
@@ -1,5 +1,5 @@
/**
* @file methods/decision_tree/random_binary_numeric_split.hpp
* @file methods/decision_tree/split_functions/random_binary_numeric_split.hpp
* @author Rishabh Garg
*
* A tree splitter that finds a random binary numeric split.
@@ -1,5 +1,5 @@
/**
* @file methods/decision_tree/random_binary_numeric_split_impl.hpp
* @file methods/decision_tree/split_functions/random_binary_numeric_split_impl.hpp
* @author Rishabh Garg
*
* Implementation of strategy that finds the random binary numeric split.
@@ -0,0 +1,4 @@
#include "all_categorical_split.hpp"
#include "best_binary_numeric_split.hpp"
#include "random_binary_numeric_split.hpp"
#include "best_binary_categorical_split.hpp"
+2 -2
View File
@@ -56,11 +56,11 @@ KDERules<DistanceType, KernelType, TreeType>::KDERules(
scores(0)
{
// Initialize accumError.
accumError = arma::vec(querySet.n_cols, arma::fill::zeros);
accumError = arma::vec(querySet.n_cols);
// Initialize accumMCAlpha only if Monte Carlo estimations are available.
if (monteCarlo && kernelIsGaussian)
accumMCAlpha = arma::vec(querySet.n_cols, arma::fill::zeros);
accumMCAlpha = arma::vec(querySet.n_cols);
}
//! The base case.
@@ -50,6 +50,7 @@ double HamerlyKMeans<DistanceType, MatType>::Iterate(const arma::mat& centroids,
// Calculate minimum intra-cluster distance for each cluster.
minClusterDistances.fill(DBL_MAX);
#pragma omp parallel for reduction(+:distanceCalculations) schedule(static)
for (size_t i = 0; i < centroids.n_cols; ++i)
{
for (size_t j = i + 1; j < centroids.n_cols; ++j)
@@ -59,13 +60,13 @@ double HamerlyKMeans<DistanceType, MatType>::Iterate(const arma::mat& centroids,
++distanceCalculations;
// Update bounds, if this intra-cluster distance is smaller.
if (dist < minClusterDistances(i))
minClusterDistances(i) = dist;
if (dist < minClusterDistances(j))
minClusterDistances(j) = dist;
minClusterDistances(i) = std::min(minClusterDistances(i), dist);
minClusterDistances(j) = std::min(minClusterDistances(j), dist);
}
}
#pragma omp parallel for reduction(+:hamerlyPruned,distanceCalculations) \
reduction(matAdd:newCentroids) reduction(colAdd:counts) schedule(static)
for (size_t i = 0; i < dataset.n_cols; ++i)
{
const double m = std::max(minClusterDistances(assignments[i]),
@@ -132,6 +133,8 @@ double HamerlyKMeans<DistanceType, MatType>::Iterate(const arma::mat& centroids,
size_t furthestMovingCluster = 0;
arma::vec centroidMovements(centroids.n_cols);
double centroidMovement = 0.0;
#pragma omp parallel for reduction(+: distanceCalculations, centroidMovement) \
schedule(static)
for (size_t c = 0; c < centroids.n_cols; ++c)
{
if (counts(c) > 0)
@@ -144,19 +147,23 @@ double HamerlyKMeans<DistanceType, MatType>::Iterate(const arma::mat& centroids,
centroidMovement += std::pow(movement, 2.0);
++distanceCalculations;
if (movement > furthestMovement)
#pragma omp critical
{
secondFurthestMovement = furthestMovement;
furthestMovement = movement;
furthestMovingCluster = c;
}
else if (movement > secondFurthestMovement)
{
secondFurthestMovement = movement;
if (movement > furthestMovement)
{
secondFurthestMovement = furthestMovement;
furthestMovement = movement;
furthestMovingCluster = c;
}
else if (movement > secondFurthestMovement)
{
secondFurthestMovement = movement;
}
}
}
// Now update bounds (lines 3-8 of Update-Bounds()).
#pragma omp parallel for schedule(static)
for (size_t i = 0; i < dataset.n_cols; ++i)
{
upperBounds(i) += centroidMovements(assignments[i]);
@@ -43,11 +43,10 @@ double NaiveKMeans<DistanceType, MatType>::Iterate(const arma::mat& centroids,
#pragma omp parallel
{
// The current state of the K-means is private for each thread
arma::mat localCentroids(centroids.n_rows, centroids.n_cols,
arma::fill::zeros);
arma::Col<size_t> localCounts(centroids.n_cols, arma::fill::zeros);
arma::mat localCentroids(centroids.n_rows, centroids.n_cols);
arma::Col<size_t> localCounts(centroids.n_cols);
#pragma omp for
#pragma omp for schedule(static) nowait
for (size_t i = 0; i < (size_t) dataset.n_cols; ++i)
{
// Find the closest centroid to this point.
@@ -57,7 +56,7 @@ double NaiveKMeans<DistanceType, MatType>::Iterate(const arma::mat& centroids,
for (size_t j = 0; j < centroids.n_cols; ++j)
{
const double dist = distance.Evaluate(dataset.col(i),
centroids.unsafe_col(j));
centroids.col(j));
if (dist < minDistance)
{
minDistance = dist;
@@ -68,7 +67,7 @@ double NaiveKMeans<DistanceType, MatType>::Iterate(const arma::mat& centroids,
Log::Assert(closestCluster != centroids.n_cols);
// We now have the minimum distance centroid index. Update that centroid.
localCentroids.unsafe_col(closestCluster) += dataset.col(i);
localCentroids.col(closestCluster) += dataset.col(i);
localCounts(closestCluster)++;
}
// Combine calculated state from each thread
@@ -80,6 +79,7 @@ double NaiveKMeans<DistanceType, MatType>::Iterate(const arma::mat& centroids,
}
// Now normalize the centroid.
#pragma omp parallel for schedule(static)
for (size_t i = 0; i < centroids.n_cols; ++i)
if (counts(i) != 0)
newCentroids.col(i) /= counts(i);
@@ -88,6 +88,7 @@ double NaiveKMeans<DistanceType, MatType>::Iterate(const arma::mat& centroids,
// Calculate cluster distortion for this iteration.
double cNorm = 0.0;
#pragma omp parallel for reduction(+:cNorm) schedule(static)
for (size_t i = 0; i < centroids.n_cols; ++i)
{
cNorm += std::pow(distance.Evaluate(centroids.col(i), newCentroids.col(i)),
+2 -2
View File
@@ -573,8 +573,8 @@ LARS<ModelMatType>::Train(const MatType& matX,
isIgnored.resize(dataRef.n_cols, false);
// Initialize yHat and beta.
arma::Col<ElemType> beta(dataRef.n_cols, arma::fill::zeros);
arma::Col<ElemType> yHat(dataRef.n_rows, arma::fill::zeros);
arma::Col<ElemType> beta(dataRef.n_cols);
arma::Col<ElemType> yHat(dataRef.n_rows);
arma::Col<ElemType> yHatDirection(dataRef.n_rows, arma::fill::none);
bool lassocond = false;
+60 -47
View File
@@ -27,12 +27,25 @@ namespace mlpack {
* data point) and Triplets() (Generates sets of {dataset, target neighbors,
* impostors} tripltets.)
*/
template<typename DistanceType = SquaredEuclideanDistance>
template<typename MatType = arma::mat,
typename LabelsType = arma::Row<size_t>,
typename DistanceType = SquaredEuclideanDistance>
class Constraints
{
public:
//! Convenience typedef.
typedef NeighborSearch<NearestNeighborSort, DistanceType> KNN;
typedef NeighborSearch<NearestNeighborSort, DistanceType, MatType> KNN;
// Convenience typedef for element type of data.
typedef typename MatType::elem_type ElemType;
// Convenience typedef for column vector of data.
typedef typename GetColType<MatType>::type VecType;
// Convenience typedef for cube of data.
typedef typename GetCubeType<MatType>::type CubeType;
// Convenience typedef for dense matrix of indices.
typedef typename GetUDenseMatType<MatType>::type UMatType;
// Convenience typedef for dense vector of indices.
typedef typename GetColType<UMatType>::type UVecType;
/**
* Constructor for creating a Constraints instance.
@@ -41,8 +54,8 @@ class Constraints
* @param labels Input dataset labels.
* @param k Number of target neighbors, impostors & triplets.
*/
Constraints(const arma::mat& dataset,
const arma::Row<size_t>& labels,
Constraints(const MatType& dataset,
const LabelsType& labels,
const size_t k);
/**
@@ -54,10 +67,10 @@ class Constraints
* @param labels Input dataset labels.
* @param norms Input dataset norms.
*/
void TargetNeighbors(arma::Mat<size_t>& outputMatrix,
const arma::mat& dataset,
const arma::Row<size_t>& labels,
const arma::vec& norms);
void TargetNeighbors(UMatType& outputMatrix,
const MatType& dataset,
const LabelsType& labels,
const VecType& norms);
/**
* Calculates k similar labeled nearest neighbors for a batch of dataset and
@@ -70,10 +83,10 @@ class Constraints
* @param begin Index of the initial point of dataset.
* @param batchSize Number of data points to use.
*/
void TargetNeighbors(arma::Mat<size_t>& outputMatrix,
const arma::mat& dataset,
const arma::Row<size_t>& labels,
const arma::vec& norms,
void TargetNeighbors(UMatType& outputMatrix,
const MatType& dataset,
const LabelsType& labels,
const VecType& norms,
const size_t begin,
const size_t batchSize);
@@ -86,10 +99,10 @@ class Constraints
* @param labels Input dataset labels.
* @param norms Input dataset norms.
*/
void Impostors(arma::Mat<size_t>& outputMatrix,
const arma::mat& dataset,
const arma::Row<size_t>& labels,
const arma::vec& norms);
void Impostors(UMatType& outputMatrix,
const MatType& dataset,
const LabelsType& labels,
const VecType& norms);
/**
* Calculates k differently labeled nearest neighbors & distances to
@@ -101,11 +114,11 @@ class Constraints
* @param labels Input dataset labels.
* @param norms Input dataset norms.
*/
void Impostors(arma::Mat<size_t>& outputNeighbors,
arma::mat& outputDistance,
const arma::mat& dataset,
const arma::Row<size_t>& labels,
const arma::vec& norms);
void Impostors(UMatType& outputNeighbors,
MatType& outputDistance,
const MatType& dataset,
const LabelsType& labels,
const VecType& norms);
/**
* Calculates k differently labeled nearest neighbors for a batch of dataset
@@ -118,10 +131,10 @@ class Constraints
* @param begin Index of the initial point of dataset.
* @param batchSize Number of data points to use.
*/
void Impostors(arma::Mat<size_t>& outputMatrix,
const arma::mat& dataset,
const arma::Row<size_t>& labels,
const arma::vec& norms,
void Impostors(UMatType& outputMatrix,
const MatType& dataset,
const LabelsType& labels,
const VecType& norms,
const size_t begin,
const size_t batchSize);
@@ -137,11 +150,11 @@ class Constraints
* @param begin Index of the initial point of dataset.
* @param batchSize Number of data points to use.
*/
void Impostors(arma::Mat<size_t>& outputNeighbors,
arma::mat& outputDistance,
const arma::mat& dataset,
const arma::Row<size_t>& labels,
const arma::vec& norms,
void Impostors(UMatType& outputNeighbors,
MatType& outputDistance,
const MatType& dataset,
const LabelsType& labels,
const VecType& norms,
const size_t begin,
const size_t batchSize);
@@ -158,12 +171,12 @@ class Constraints
* @param points Indices of data points to calculate impostors on.
* @param numPoints Number of points to actually calculate impostors on.
*/
void Impostors(arma::Mat<size_t>& outputNeighbors,
arma::mat& outputDistance,
const arma::mat& dataset,
const arma::Row<size_t>& labels,
const arma::vec& norms,
const arma::uvec& points,
void Impostors(UMatType& outputNeighbors,
MatType& outputDistance,
const MatType& dataset,
const LabelsType& labels,
const VecType& norms,
const UVecType& points,
const size_t numPoints);
/**
@@ -175,10 +188,10 @@ class Constraints
* @param labels Input dataset labels.
* @param norms Input dataset norms.
*/
void Triplets(arma::Mat<size_t>& outputMatrix,
const arma::mat& dataset,
const arma::Row<size_t>& labels,
const arma::vec& norms);
void Triplets(UMatType& outputMatrix,
const MatType& dataset,
const LabelsType& labels,
const VecType& norms);
//! Get the number of target neighbors (k).
const size_t& K() const { return k; }
@@ -195,13 +208,13 @@ class Constraints
size_t k;
//! Store unique labels.
arma::Row<size_t> uniqueLabels;
LabelsType uniqueLabels;
//! Store indices of data points having similar label.
std::vector<arma::uvec> indexSame;
std::vector<UVecType> indexSame;
//! Store indices of data points having different label.
std::vector<arma::uvec> indexDiff;
std::vector<UVecType> indexDiff;
//! False if nothing has ever been precalculated.
bool precalculated;
@@ -210,15 +223,15 @@ class Constraints
* Precalculate the unique labels, and indices of similar
* and different datapoints on the basis of labels.
*/
inline void Precalculate(const arma::Row<size_t>& labels);
inline void Precalculate(const LabelsType& labels);
/**
* Re-order neighbors on the basis of increasing norm in case
* of ties among distances.
*/
inline void ReorderResults(const arma::mat& distances,
arma::Mat<size_t>& neighbors,
const arma::vec& norms);
inline void ReorderResults(const MatType& distances,
UMatType& neighbors,
const VecType& norms);
};
} // namespace mlpack
+107 -99
View File
@@ -17,10 +17,10 @@
namespace mlpack {
template<typename DistanceType>
Constraints<DistanceType>::Constraints(
const arma::mat& /* dataset */,
const arma::Row<size_t>& labels,
template<typename MatType, typename LabelsType, typename DistanceType>
Constraints<MatType, LabelsType, DistanceType>::Constraints(
const MatType& /* dataset */,
const LabelsType& labels,
const size_t k) :
k(k),
precalculated(false)
@@ -36,11 +36,11 @@ Constraints<DistanceType>::Constraints(
}
}
template<typename DistanceType>
inline void Constraints<DistanceType>::ReorderResults(
const arma::mat& distances,
arma::Mat<size_t>& neighbors,
const arma::vec& norms)
template<typename MatType, typename LabelsType, typename DistanceType>
inline void Constraints<MatType, LabelsType, DistanceType>::ReorderResults(
const MatType& distances,
UMatType& neighbors,
const VecType& norms)
{
// Shortcut...
if (neighbors.n_rows == 1)
@@ -64,24 +64,21 @@ inline void Constraints<DistanceType>::ReorderResults(
if (start != end)
{
// We must sort these elements by norm.
arma::Col<size_t> newNeighbors =
neighbors.col(i).subvec(start, end - 1);
arma::uvec indices = ConvTo<arma::uvec>::From(newNeighbors);
arma::uvec order = arma::sort_index(norms.elem(indices));
neighbors.col(i).subvec(start, end - 1) =
newNeighbors.elem(order);
UVecType indices = neighbors.col(i).subvec(start, end - 1);
UVecType order = arma::sort_index(norms.elem(indices));
neighbors.col(i).subvec(start, end - 1) = indices.elem(order);
}
}
}
}
// Calculates k similar labeled nearest neighbors.
template<typename DistanceType>
void Constraints<DistanceType>::TargetNeighbors(arma::Mat<size_t>& outputMatrix,
const arma::mat& dataset,
const arma::Row<size_t>& labels,
const arma::vec& norms)
template<typename MatType, typename LabelsType, typename DistanceType>
void Constraints<MatType, LabelsType, DistanceType>::TargetNeighbors(
UMatType& outputMatrix,
const MatType& dataset,
const LabelsType& labels,
const VecType& norms)
{
// Perform pre-calculation. If neccesary.
Precalculate(labels);
@@ -89,8 +86,8 @@ void Constraints<DistanceType>::TargetNeighbors(arma::Mat<size_t>& outputMatrix,
// KNN instance.
KNN knn;
arma::Mat<size_t> neighbors;
arma::mat distances;
UMatType neighbors;
MatType distances;
for (size_t i = 0; i < uniqueLabels.n_cols; ++i)
{
@@ -114,28 +111,29 @@ void Constraints<DistanceType>::TargetNeighbors(arma::Mat<size_t>& outputMatrix,
// Calculates k similar labeled nearest neighbors on a
// batch of data points.
template<typename DistanceType>
void Constraints<DistanceType>::TargetNeighbors(arma::Mat<size_t>& outputMatrix,
const arma::mat& dataset,
const arma::Row<size_t>& labels,
const arma::vec& norms,
const size_t begin,
const size_t batchSize)
template<typename MatType, typename LabelsType, typename DistanceType>
void Constraints<MatType, LabelsType, DistanceType>::TargetNeighbors(
UMatType& outputMatrix,
const MatType& dataset,
const LabelsType& labels,
const VecType& norms,
const size_t begin,
const size_t batchSize)
{
// Perform pre-calculation. If neccesary.
Precalculate(labels);
arma::mat subDataset = dataset.cols(begin, begin + batchSize - 1);
arma::Row<size_t> sublabels = labels.cols(begin, begin + batchSize - 1);
MatType subDataset = dataset.cols(begin, begin + batchSize - 1);
LabelsType sublabels = labels.cols(begin, begin + batchSize - 1);
// KNN instance.
KNN knn;
arma::Mat<size_t> neighbors;
arma::mat distances;
UMatType neighbors;
MatType distances;
// Vectors to store indices.
arma::uvec subIndexSame;
UVecType subIndexSame;
for (size_t i = 0; i < uniqueLabels.n_cols; ++i)
{
@@ -161,11 +159,12 @@ void Constraints<DistanceType>::TargetNeighbors(arma::Mat<size_t>& outputMatrix,
}
// Calculates k differently labeled nearest neighbors.
template<typename DistanceType>
void Constraints<DistanceType>::Impostors(arma::Mat<size_t>& outputMatrix,
const arma::mat& dataset,
const arma::Row<size_t>& labels,
const arma::vec& norms)
template<typename MatType, typename LabelsType, typename DistanceType>
void Constraints<MatType, LabelsType, DistanceType>::Impostors(
UMatType& outputMatrix,
const MatType& dataset,
const LabelsType& labels,
const VecType& norms)
{
// Perform pre-calculation. If neccesary.
Precalculate(labels);
@@ -173,8 +172,8 @@ void Constraints<DistanceType>::Impostors(arma::Mat<size_t>& outputMatrix,
// KNN instance.
KNN knn;
arma::Mat<size_t> neighbors;
arma::mat distances;
UMatType neighbors;
MatType distances;
for (size_t i = 0; i < uniqueLabels.n_cols; ++i)
{
@@ -198,12 +197,13 @@ void Constraints<DistanceType>::Impostors(arma::Mat<size_t>& outputMatrix,
// Calculates k differently labeled nearest neighbors. The function
// writes back calculated neighbors & distances to passed matrices.
template<typename DistanceType>
void Constraints<DistanceType>::Impostors(arma::Mat<size_t>& outputNeighbors,
arma::mat& outputDistance,
const arma::mat& dataset,
const arma::Row<size_t>& labels,
const arma::vec& norms)
template<typename MatType, typename LabelsType, typename DistanceType>
void Constraints<MatType, LabelsType, DistanceType>::Impostors(
UMatType& outputNeighbors,
MatType& outputDistance,
const MatType& dataset,
const LabelsType& labels,
const VecType& norms)
{
// Perform pre-calculation. If neccesary.
Precalculate(labels);
@@ -211,8 +211,8 @@ void Constraints<DistanceType>::Impostors(arma::Mat<size_t>& outputNeighbors,
// KNN instance.
KNN knn;
arma::Mat<size_t> neighbors;
arma::mat distances;
UMatType neighbors;
MatType distances;
for (size_t i = 0; i < uniqueLabels.n_cols; ++i)
{
@@ -237,28 +237,29 @@ void Constraints<DistanceType>::Impostors(arma::Mat<size_t>& outputNeighbors,
// Calculates k differently labeled nearest neighbors on a
// batch of data points.
template<typename DistanceType>
void Constraints<DistanceType>::Impostors(arma::Mat<size_t>& outputMatrix,
const arma::mat& dataset,
const arma::Row<size_t>& labels,
const arma::vec& norms,
const size_t begin,
const size_t batchSize)
template<typename MatType, typename LabelsType, typename DistanceType>
void Constraints<MatType, LabelsType, DistanceType>::Impostors(
UMatType& outputMatrix,
const MatType& dataset,
const LabelsType& labels,
const VecType& norms,
const size_t begin,
const size_t batchSize)
{
// Perform pre-calculation. If neccesary.
Precalculate(labels);
arma::mat subDataset = dataset.cols(begin, begin + batchSize - 1);
arma::Row<size_t> sublabels = labels.cols(begin, begin + batchSize - 1);
MatType subDataset = dataset.cols(begin, begin + batchSize - 1);
LabelsType sublabels = labels.cols(begin, begin + batchSize - 1);
// KNN instance.
KNN knn;
arma::Mat<size_t> neighbors;
arma::mat distances;
UMatType neighbors;
MatType distances;
// Vectors to store indices.
arma::uvec subIndexSame;
UVecType subIndexSame;
for (size_t i = 0; i < uniqueLabels.n_cols; ++i)
{
@@ -285,29 +286,30 @@ void Constraints<DistanceType>::Impostors(arma::Mat<size_t>& outputMatrix,
// Calculates k differently labeled nearest neighbors & distances on a
// batch of data points.
template<typename DistanceType>
void Constraints<DistanceType>::Impostors(arma::Mat<size_t>& outputNeighbors,
arma::mat& outputDistance,
const arma::mat& dataset,
const arma::Row<size_t>& labels,
const arma::vec& norms,
const size_t begin,
const size_t batchSize)
template<typename MatType, typename LabelsType, typename DistanceType>
void Constraints<MatType, LabelsType, DistanceType>::Impostors(
UMatType& outputNeighbors,
MatType& outputDistance,
const MatType& dataset,
const LabelsType& labels,
const VecType& norms,
const size_t begin,
const size_t batchSize)
{
// Perform pre-calculation. If neccesary.
Precalculate(labels);
arma::mat subDataset = dataset.cols(begin, begin + batchSize - 1);
arma::Row<size_t> sublabels = labels.cols(begin, begin + batchSize - 1);
MatType subDataset = dataset.cols(begin, begin + batchSize - 1);
LabelsType sublabels = labels.cols(begin, begin + batchSize - 1);
// KNN instance.
KNN knn;
arma::Mat<size_t> neighbors;
arma::mat distances;
UMatType neighbors;
MatType distances;
// Vectors to store indices.
arma::uvec subIndexSame;
UVecType subIndexSame;
for (size_t i = 0; i < uniqueLabels.n_cols; ++i)
{
@@ -335,14 +337,15 @@ void Constraints<DistanceType>::Impostors(arma::Mat<size_t>& outputNeighbors,
// Calculates k differently labeled nearest neighbors & distances over some
// data points.
template<typename DistanceType>
void Constraints<DistanceType>::Impostors(arma::Mat<size_t>& outputNeighbors,
arma::mat& outputDistance,
const arma::mat& dataset,
const arma::Row<size_t>& labels,
const arma::vec& norms,
const arma::uvec& points,
const size_t numPoints)
template<typename MatType, typename LabelsType, typename DistanceType>
void Constraints<MatType, LabelsType, DistanceType>::Impostors(
UMatType& outputNeighbors,
MatType& outputDistance,
const MatType& dataset,
const LabelsType& labels,
const VecType& norms,
const UVecType& points,
const size_t numPoints)
{
// Perform pre-calculation. If neccesary.
Precalculate(labels);
@@ -350,11 +353,11 @@ void Constraints<DistanceType>::Impostors(arma::Mat<size_t>& outputNeighbors,
// KNN instance.
KNN knn;
arma::Mat<size_t> neighbors;
arma::mat distances;
UMatType neighbors;
MatType distances;
// Vectors to store indices.
arma::uvec subIndexSame;
UVecType subIndexSame;
for (size_t i = 0; i < uniqueLabels.n_cols; ++i)
{
@@ -384,31 +387,35 @@ void Constraints<DistanceType>::Impostors(arma::Mat<size_t>& outputNeighbors,
// Generates {data point, target neighbors, impostors} triplets using
// TargetNeighbors() and Impostors().
template<typename DistanceType>
void Constraints<DistanceType>::Triplets(arma::Mat<size_t>& outputMatrix,
const arma::mat& dataset,
const arma::Row<size_t>& labels,
const arma::vec& norms)
template<typename MatType, typename LabelsType, typename DistanceType>
void Constraints<MatType, LabelsType, DistanceType>::Triplets(
UMatType& outputMatrix,
const MatType& dataset,
const LabelsType& labels,
const VecType& norms)
{
// Perform pre-calculation. If neccesary.
Precalculate(labels);
size_t N = dataset.n_cols;
arma::Mat<size_t> impostors(k, dataset.n_cols);
UMatType impostors(k, dataset.n_cols);
Impostors(impostors, dataset, labels, norms);
arma::Mat<size_t> targetNeighbors(k, dataset.n_cols);;
UMatType targetNeighbors(k, dataset.n_cols);;
TargetNeighbors(targetNeighbors, dataset, labels, norms);
outputMatrix = arma::Mat<size_t>(3, k * k * N , arma::fill::zeros);
outputMatrix = UMatType(3, k * k * N);
for (size_t i = 0, r = 0; i < N; ++i)
#pragma omp parallel for collapse(3)
for (size_t i = 0; i < N; ++i)
{
for (size_t j = 0; j < k; ++j)
{
for (size_t l = 0; l < k; l++, r++)
for (size_t l = 0; l < k; l++)
{
const size_t r = i * (k * k) + j * k + l;
// Generate triplets.
outputMatrix(0, r) = i;
outputMatrix(1, r) = targetNeighbors(j, i);
@@ -418,9 +425,9 @@ void Constraints<DistanceType>::Triplets(arma::Mat<size_t>& outputMatrix,
}
}
template<typename DistanceType>
inline void Constraints<DistanceType>::Precalculate(
const arma::Row<size_t>& labels)
template<typename MatType, typename LabelsType, typename DistanceType>
inline void Constraints<MatType, LabelsType, DistanceType>::Precalculate(
const LabelsType& labels)
{
// Make sure the calculation is necessary.
if (precalculated)
@@ -431,6 +438,7 @@ inline void Constraints<DistanceType>::Precalculate(
indexSame.resize(uniqueLabels.n_elem);
indexDiff.resize(uniqueLabels.n_elem);
#pragma omp parallel for
for (size_t i = 0; i < uniqueLabels.n_elem; ++i)
{
// Store same and diff indices.

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