Merge branch 'master' into HEAD

This commit is contained in:
Ryan Curtin
2020-04-06 12:50:45 -04:00
302 changed files with 7704 additions and 4036 deletions
+2 -2
View File
@@ -85,8 +85,8 @@ build_script:
- cd C:\projects\mlpack && mkdir build && cd build
- >
cmake -G "%VSVER%"
-DBLAS_LIBRARY:FILEPATH=%BLAS_LIBRARY%
-DLAPACK_LIBRARY:FILEPATH=%BLAS_LIBRARY%
-DBLAS_LIBRARIES:FILEPATH=%BLAS_LIBRARY%
-DLAPACK_LIBRARIES:FILEPATH=%BLAS_LIBRARY%
-DARMADILLO_INCLUDE_DIR="C:/projects/mlpack/armadillo-8.400.0/include"
-DARMADILLO_LIBRARY:FILEPATH=%ARMADILLO_LIBRARY%
-DBOOST_INCLUDEDIR:PATH=%BOOST_INCLUDE%
+10 -18
View File
@@ -1,3 +1,12 @@
trigger:
branches:
include:
- '*'
pr:
branches:
include:
- '*'
jobs:
- job: Linux
timeoutInMinutes: 360
@@ -28,7 +37,7 @@ jobs:
- job: macOS
timeoutInMinutes: 360
pool:
vmImage: macOS-10.13
vmImage: macOS-10.14
strategy:
matrix:
Plain:
@@ -48,23 +57,6 @@ jobs:
steps:
- template: macos-steps.yaml
- job: WindowsVS14
timeoutInMinutes: 360
displayName: Windows VS14
pool:
vmImage: vs2015-win2012r2
strategy:
matrix:
Plain:
CMakeArgs: '-DDEBUG=ON -DPROFILE=OFF -DBUILD_PYTHON_BINDINGS=OFF'
CMakeGenerator: '-G "Visual Studio 14 2015 Win64"'
MSBuildVersion: '14.0'
ArchiveNoLibs: 'mlpack-windows-vs14-no-libs.zip'
ArchiveLibs: 'mlpack-windows-vs14.zip'
ArchiveTests: 'mlpack_test-vs14.xml'
steps:
- template: windows-steps.yaml
- job: WindowsVS15
timeoutInMinutes: 360
displayName: Windows VS15
+1 -2
View File
@@ -14,8 +14,7 @@ steps:
set -e
sudo xcode-select --switch /Applications/Xcode_10.1.app/Contents/Developer
unset BOOST_ROOT
pip install cython numpy pandas zipp
brew update
pip install cython numpy pandas zipp configparser
brew install openblas armadillo boost
if [ "a$(julia.version)" != "a" ]; then
+4 -3
View File
@@ -28,7 +28,7 @@ steps:
# Configure armadillo
- bash: |
git clone --depth 1 https://github.com/mlpack/jenkins-conf.git conf
curl -O http://masterblaster.mlpack.org:5005/armadillo-8.400.0.tar.gz -o armadillo-8.400.0.tar.gz
tar -xzvf armadillo-8.400.0.tar.gz
@@ -60,12 +60,13 @@ steps:
cmake $(CMakeGenerator) `
$(CMakeArgs) `
-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 `
-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-8.400.0\include" `
-DARMADILLO_LIBRARY="..\armadillo-8.400.0\Release\armadillo.lib" `
-DBOOST_INCLUDEDIR=$(Agent.ToolsDirectory)\boost.1.60.0.0\lib\native\include `
-DBOOST_LIBRARYDIR=$(Agent.ToolsDirectory)\boost_libs `
-DBUILD_JULIA_BINDINGS=OFF `
-DCMAKE_BUILD_TYPE=Release ..
displayName: 'Configure mlpack'
-37
View File
@@ -1,37 +0,0 @@
# - Find AMD's ACML library (no includes) which provides optimised BLAS and LAPACK functions
# This module defines
# ACML_LIBRARIES, the libraries needed to use ACML.
# ACML_FOUND, If false, do not try to use ACML.
# also defined, but not for general use are
# ACML_LIBRARY, where to find the ACML library.
set(ACML_NAMES ${ACML_NAMES} acml)
find_library(ACML_LIBRARY
NAMES ${ACML_NAMES}
PATHS /usr/lib64 /usr/lib /usr/*/lib64 /usr/*/lib /usr/*/gfortran64/lib/ /usr/*/gfortran32/lib/ /usr/local/lib64 /usr/local/lib /opt/lib64 /opt/lib /opt/*/lib64 /opt/*/lib /opt/*/gfortran64/lib/ /opt/*/gfortran32/lib/
)
if (ACML_LIBRARY)
set(ACML_LIBRARIES ${ACML_LIBRARY})
set(ACML_FOUND "YES")
else ()
set(ACML_FOUND "NO")
endif ()
if (ACML_FOUND)
if (NOT ACML_FIND_QUIETLY)
message(STATUS "Found the ACML library: ${ACML_LIBRARIES}")
endif ()
else ()
if (ACML_FIND_REQUIRED)
message(FATAL_ERROR "Could not find the ACML library")
endif ()
endif ()
# Deprecated declarations.
get_filename_component (NATIVE_ACML_LIB_PATH ${ACML_LIBRARY} PATH)
mark_as_advanced(
ACML_LIBRARY
)
-37
View File
@@ -1,37 +0,0 @@
# - Find AMD's ACMLMP library (no includes) which provides optimised and parallelised BLAS and LAPACK functions
# This module defines
# ACMLMP_LIBRARIES, the libraries needed to use ACMLMP.
# ACMLMP_FOUND, If false, do not try to use ACMLMP.
# also defined, but not for general use are
# ACMLMP_LIBRARY, where to find the ACMLMP library.
set(ACMLMP_NAMES ${ACMLMP_NAMES} acml_mp)
find_library(ACMLMP_LIBRARY
NAMES ${ACMLMP_NAMES}
PATHS /usr/lib64 /usr/lib /usr/*/lib64 /usr/*/lib /usr/*/gfortran64_mp/lib/ /usr/*/gfortran32_mp/lib/ /usr/local/lib64 /usr/local/lib /opt/lib64 /opt/lib /opt/*/lib64 /opt/*/lib /opt/*/gfortran64_mp/lib/ /opt/*/gfortran32_mp/lib/
)
if (ACMLMP_LIBRARY)
set(ACMLMP_LIBRARIES ${ACMLMP_LIBRARY})
set(ACMLMP_FOUND "YES")
else ()
set(ACMLMP_FOUND "NO")
endif ()
if (ACMLMP_FOUND)
if (NOT ACMLMP_FIND_QUIETLY)
message(STATUS "Found the ACMLMP library: ${ACMLMP_LIBRARIES}")
endif ()
else ()
if (ACMLMP_FIND_REQUIRED)
message(FATAL_ERROR "Could not find the ACMLMP library")
endif ()
endif ()
# Deprecated declarations.
get_filename_component (NATIVE_ACMLMP_LIB_PATH ${ACMLMP_LIBRARY} PATH)
mark_as_advanced(
ACMLMP_LIBRARY
)
-39
View File
@@ -1,39 +0,0 @@
# - Try to find ARPACK
# Once done this will define
#
# ARPACK_FOUND - system has ARPACK
# ARPACK_LIBRARY - Link this to use ARPACK
find_library(ARPACK_LIBRARY
NAMES arpack
PATHS /usr/lib64 /usr/lib /usr/local/lib64 /usr/local/lib
)
if (ARPACK_LIBRARY)
set(ARPACK_FOUND YES)
else ()
# Search for PARPACK.
find_library(ARPACK_LIBRARY
NAMES parpack
PATHS /usr/lib64 /usr/lib /usr/local/lib64 /usr/local/lib
)
if (ARPACK_LIBRARY)
set(ARPACK_FOUND YES)
else ()
set(ARPACK_FOUND NO)
endif ()
endif ()
if (ARPACK_FOUND)
if (NOT ARPACK_FIND_QUIETLY)
message(STATUS "Found an ARPACK library: ${ARPACK_LIBRARY}")
endif ()
else ()
if (ARPACK_FIND_REQUIRED)
message(FATAL_ERROR "Could not find an ARPACK library")
endif ()
endif ()
-44
View File
@@ -1,44 +0,0 @@
# - Find a BLAS library (no includes)
# This module defines
# BLAS_LIBRARIES, the libraries needed to use BLAS.
# BLAS_FOUND, If false, do not try to use BLAS.
# also defined, but not for general use are
# BLAS_LIBRARY, where to find the BLAS library.
set(BLAS_NAMES ${BLAS_NAMES} blas)
# Find the ATLAS version preferentially.
find_library(BLAS_LIBRARY
NAMES ${BLAS_NAMES}
PATHS /usr/lib64/atlas /usr/lib/atlas /usr/local/lib64/atlas /usr/local/lib/atlas
NO_DEFAULT_PATH)
find_library(BLAS_LIBRARY
NAMES ${BLAS_NAMES}
PATHS /usr/lib64/atlas /usr/lib/atlas /usr/lib64 /usr/lib /usr/local/lib64 /usr/local/lib
)
if (BLAS_LIBRARY)
set(BLAS_LIBRARIES ${BLAS_LIBRARY})
set(BLAS_FOUND "YES")
else ()
set(BLAS_FOUND "NO")
endif ()
if (BLAS_FOUND)
if (NOT BLAS_FIND_QUIETLY)
message(STATUS "Found BLAS: ${BLAS_LIBRARIES}")
endif ()
else ()
if (BLAS_FIND_REQUIRED)
message(FATAL_ERROR "Could not find BLAS")
endif ()
endif ()
# Deprecated declarations.
get_filename_component (NATIVE_BLAS_LIB_PATH ${BLAS_LIBRARY} PATH)
mark_as_advanced(
BLAS_LIBRARY
)
-47
View File
@@ -1,47 +0,0 @@
# - Find CBLAS (includes and library)
# This module defines
# CBLAS_INCLUDE_DIR
# CBLAS_LIBRARIES
# CBLAS_FOUND
# also defined, but not for general use are
# CBLAS_LIBRARY, where to find the library.
find_path(CBLAS_INCLUDE_DIR cblas.h
/usr/include/atlas/
/usr/local/include/atlas/
/usr/include/
/usr/local/include/
)
set(CBLAS_NAMES ${CBLAS_NAMES} cblas)
find_library(CBLAS_LIBRARY
NAMES ${CBLAS_NAMES}
PATHS /usr/lib64/atlas-sse3 /usr/lib64/atlas /usr/lib64 /usr/local/lib64/atlas /usr/local/lib64 /usr/lib/atlas-sse3 /usr/lib/atlas-sse2 /usr/lib/atlas-sse /usr/lib/atlas-3dnow /usr/lib/atlas /usr/lib /usr/local/lib/atlas /usr/local/lib
)
if (CBLAS_LIBRARY AND CBLAS_INCLUDE_DIR)
set(CBLAS_LIBRARIES ${CBLAS_LIBRARY})
set(CBLAS_FOUND "YES")
else ()
set(CBLAS_FOUND "NO")
endif ()
if (CBLAS_FOUND)
if (NOT CBLAS_FIND_QUIETLY)
message(STATUS "Found a CBLAS library: ${CBLAS_LIBRARIES}")
endif ()
else ()
if (CBLAS_FIND_REQUIRED)
message(FATAL_ERROR "Could not find a CBLAS library")
endif ()
endif ()
# Deprecated declarations.
set (NATIVE_CBLAS_INCLUDE_PATH ${CBLAS_INCLUDE_DIR} )
get_filename_component (NATIVE_CBLAS_LIB_PATH ${CBLAS_LIBRARY} PATH)
mark_as_advanced(
CBLAS_LIBRARY
CBLAS_INCLUDE_DIR
)
-48
View File
@@ -1,48 +0,0 @@
# - Find a version of CLAPACK (includes and library)
# This module defines
# CLAPACK_INCLUDE_DIR
# CLAPACK_LIBRARIES
# CLAPACK_FOUND
# also defined, but not for general use are
# CLAPACK_LIBRARY, where to find the library.
find_path(CLAPACK_INCLUDE_DIR clapack.h
/usr/include/atlas/
/usr/local/include/atlas/
/usr/include/
/usr/local/include/
)
set(CLAPACK_NAMES ${CLAPACK_NAMES} lapack_atlas)
set(CLAPACK_NAMES ${CLAPACK_NAMES} clapack)
find_library(CLAPACK_LIBRARY
NAMES ${CLAPACK_NAMES}
PATHS /usr/lib64/atlas-sse3 /usr/lib64/atlas /usr/lib64 /usr/local/lib64/atlas /usr/local/lib64 /usr/lib/atlas-sse3 /usr/lib/atlas-sse2 /usr/lib/atlas-sse /usr/lib/atlas-3dnow /usr/lib/atlas /usr/lib /usr/local/lib/atlas /usr/local/lib
)
if (CLAPACK_LIBRARY AND CLAPACK_INCLUDE_DIR)
set(CLAPACK_LIBRARIES ${CLAPACK_LIBRARY})
set(CLAPACK_FOUND "YES")
else ()
set(CLAPACK_FOUND "NO")
endif ()
if (CLAPACK_FOUND)
if (NOT CLAPACK_FIND_QUIETLY)
message(STATUS "Found a CLAPACK library: ${CLAPACK_LIBRARIES}")
endif ()
else ()
if (CLAPACK_FIND_REQUIRED)
message(FATAL_ERROR "Could not find a CLAPACK library")
endif ()
endif ()
# Deprecated declarations.
set (NATIVE_CLAPACK_INCLUDE_PATH ${CLAPACK_INCLUDE_DIR} )
get_filename_component (NATIVE_CLAPACK_LIB_PATH ${CLAPACK_LIBRARY} PATH)
mark_as_advanced(
CLAPACK_LIBRARY
CLAPACK_INCLUDE_DIR
)
-44
View File
@@ -1,44 +0,0 @@
# - Find a LAPACK library (no includes)
# This module defines
# LAPACK_LIBRARIES, the libraries needed to use LAPACK.
# LAPACK_FOUND, If false, do not try to use LAPACK.
# also defined, but not for general use are
# LAPACK_LIBRARY, where to find the LAPACK library.
set(LAPACK_NAMES ${LAPACK_NAMES} lapack)
# Check ATLAS paths preferentially, using this necessary hack (I love CMake).
find_library(LAPACK_LIBRARY
NAMES ${LAPACK_NAMES}
PATHS /usr/lib64/atlas /usr/lib/atlas /usr/local/lib64/atlas /usr/local/lib/atlas
NO_DEFAULT_PATH)
find_library(LAPACK_LIBRARY
NAMES ${LAPACK_NAMES}
PATHS /usr/lib64 /usr/lib /usr/local/lib64 /usr/local/lib
)
if (LAPACK_LIBRARY)
set(LAPACK_LIBRARIES ${LAPACK_LIBRARY})
set(LAPACK_FOUND "YES")
else ()
set(LAPACK_FOUND "NO")
endif ()
if (LAPACK_FOUND)
if (NOT LAPACK_FIND_QUIETLY)
message(STATUS "Found LAPACK: ${LAPACK_LIBRARIES}")
endif ()
else ()
if (LAPACK_FIND_REQUIRED)
message(FATAL_ERROR "Could not find LAPACK")
endif ()
endif ()
# Deprecated declarations.
get_filename_component (NATIVE_LAPACK_LIB_PATH ${LAPACK_LIBRARY} PATH)
mark_as_advanced(
LAPACK_LIBRARY
)
-49
View File
@@ -1,49 +0,0 @@
# - Find the MKL libraries (no includes)
# This module defines
# MKL_LIBRARIES, the libraries needed to use Intel's implementation of BLAS & LAPACK.
# MKL_FOUND, If false, do not try to use MKL.
set(MKL_NAMES ${MKL_NAMES} mkl_lapack)
set(MKL_NAMES ${MKL_NAMES} mkl_intel_thread)
set(MKL_NAMES ${MKL_NAMES} mkl_core)
set(MKL_NAMES ${MKL_NAMES} guide)
set(MKL_NAMES ${MKL_NAMES} mkl)
set(MKL_NAMES ${MKL_NAMES} iomp5)
#set(MKL_NAMES ${MKL_NAMES} pthread)
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(MKL_NAMES ${MKL_NAMES} mkl_intel_lp64)
else()
set(MKL_NAMES ${MKL_NAMES} mkl_intel)
endif()
foreach (MKL_NAME ${MKL_NAMES})
find_library(${MKL_NAME}_LIBRARY
NAMES ${MKL_NAME}
PATHS /usr/lib64 /usr/lib /usr/local/lib64 /usr/local/lib /opt/intel/lib/intel64 /opt/intel/lib/ia32 /opt/intel/mkl/lib/lib64 /opt/intel/mkl/lib/intel64 /opt/intel/mkl/lib/ia32 /opt/intel/mkl/lib /opt/intel/*/mkl/lib/intel64 /opt/intel/*/mkl/lib/ia32/ /opt/mkl/*/lib/em64t /opt/mkl/*/lib/32 /opt/intel/mkl/*/lib/em64t /opt/intel/mkl/*/lib/32
)
set(TMP_LIBRARY ${${MKL_NAME}_LIBRARY})
if(TMP_LIBRARY)
set(MKL_LIBRARIES ${MKL_LIBRARIES} ${TMP_LIBRARY})
endif()
endforeach()
if (MKL_LIBRARIES)
set(MKL_FOUND "YES")
else ()
set(MKL_FOUND "NO")
endif ()
if (MKL_FOUND)
if (NOT MKL_FIND_QUIETLY)
message(STATUS "Found MKL libraries: ${MKL_LIBRARIES}")
endif ()
else ()
if (MKL_FIND_REQUIRED)
message(FATAL_ERROR "Could not find MKL libraries")
endif ()
endif ()
# mark_as_advanced(MKL_LIBRARY)
-37
View File
@@ -1,37 +0,0 @@
# - Find the OpenBLAS library (no includes)
# This module defines
# OpenBLAS_LIBRARIES, the libraries needed to use OpenBLAS.
# OpenBLAS_FOUND, If false, do not try to use OpenBLAS.
# also defined, but not for general use are
# OpenBLAS_LIBRARY, where to find the OpenBLAS library.
set(OpenBLAS_NAMES ${OpenBLAS_NAMES} openblas)
find_library(OpenBLAS_LIBRARY
NAMES ${OpenBLAS_NAMES}
PATHS /lib64 /lib /usr/lib64 /usr/lib /usr/local/lib64 /usr/local/lib
)
if (OpenBLAS_LIBRARY)
set(OpenBLAS_LIBRARIES ${OpenBLAS_LIBRARY})
set(OpenBLAS_FOUND "YES")
else ()
set(OpenBLAS_FOUND "NO")
endif ()
if (OpenBLAS_FOUND)
if (NOT OpenBLAS_FIND_QUIETLY)
message(STATUS "Found the OpenBLAS library: ${OpenBLAS_LIBRARIES}")
endif ()
else ()
if (OpenBLAS_FIND_REQUIRED)
message(FATAL_ERROR "Could not find the OpenBLAS library")
endif ()
endif ()
# Deprecated declarations.
get_filename_component (NATIVE_OpenBLAS_LIB_PATH ${OpenBLAS_LIBRARY} PATH)
mark_as_advanced(
OpenBLAS_LIBRARY
)
+55
View File
@@ -0,0 +1,55 @@
# Searches for an installation of the ARPACK library. On success, it sets the following variables:
#
# ARPACK_FOUND Set to true to indicate the library was found
# ARPACK_LIBRARIES All libraries needed to use ARPACK (with full path)
#
# To specify an additional directory to search, set ARPACK_ROOT.
#
# TODO: Do we need to explicitly search for BLAS and LAPACK as well? The source distribution statically links these to
# libarpack. Are there any installations that don't do this or the equivalent?
#
# Author: Siddhartha Chaudhuri, 2009
#
SET(ARPACK_FOUND FALSE)
# First look in user-provided root directory, then look in system locations
FIND_LIBRARY(ARPACK_LIBRARIES NAMES arpack libarpack ARPACK libARPACK PATHS "${ARPACK_ROOT}" "${ARPACK_ROOT}/lib"
NO_DEFAULT_PATH)
IF(NOT ARPACK_LIBRARIES)
FIND_LIBRARY(ARPACK_LIBRARIES NAMES arpack libarpack ARPACK libARPACK)
ENDIF(NOT ARPACK_LIBRARIES)
IF(ARPACK_LIBRARIES)
# On OS X we probably also need gfortran and BLAS and LAPACK libraries
IF(APPLE)
FIND_LIBRARY(ARPACK_LAPACK_LIBRARY NAMES lapack LAPACK PATHS "${ARPACK_ROOT}" "${ARPACK_ROOT}/lib")
FIND_LIBRARY(ARPACK_BLAS_LIBRARY NAMES blas BLAS PATHS "${ARPACK_ROOT}" "${ARPACK_ROOT}/lib")
FIND_LIBRARY(ARPACK_GFORTRAN_LIBRARY NAMES gfortran PATHS "${ARPACK_ROOT}" "${ARPACK_ROOT}/lib"
PATH_SUFFIXES "" "gfortran/lib" "../gfortran/lib")
IF(ARPACK_BLAS_LIBRARY)
SET(ARPACK_LIBRARIES ${ARPACK_LIBRARIES} ${ARPACK_BLAS_LIBRARY})
ENDIF(ARPACK_BLAS_LIBRARY)
IF(ARPACK_LAPACK_LIBRARY)
SET(ARPACK_LIBRARIES ${ARPACK_LIBRARIES} ${ARPACK_LAPACK_LIBRARY})
ENDIF(ARPACK_LAPACK_LIBRARY)
IF(ARPACK_GFORTRAN_LIBRARY)
SET(ARPACK_LIBRARIES ${ARPACK_LIBRARIES} ${ARPACK_GFORTRAN_LIBRARY})
ENDIF(ARPACK_GFORTRAN_LIBRARY)
ENDIF(APPLE)
SET(ARPACK_FOUND TRUE)
ENDIF(ARPACK_LIBRARIES)
IF(ARPACK_FOUND)
IF(NOT ARPACK_FIND_QUIETLY)
MESSAGE(STATUS "Found ARPACK: libraries at ${ARPACK_LIBRARIES}")
ENDIF(NOT ARPACK_FIND_QUIETLY)
ELSE(ARPACK_FOUND)
IF(ARPACK_FIND_REQUIRED)
MESSAGE(FATAL_ERROR "ARPACK not found")
ENDIF(ARPACK_FIND_REQUIRED)
ENDIF(ARPACK_FOUND)
+118 -319
View File
@@ -1,41 +1,41 @@
# - Find Armadillo
# Find the Armadillo C++ library
#
# Using Armadillo:
# find_package(Armadillo REQUIRED)
# include_directories(${ARMADILLO_INCLUDE_DIRS})
# add_executable(foo foo.cc)
# target_link_libraries(foo ${ARMADILLO_LIBRARIES})
# This module sets the following variables:
# ARMADILLO_FOUND - set to true if the library is found
# ARMADILLO_INCLUDE_DIRS - list of required include directories
# ARMADILLO_LIBRARIES - list of libraries to be linked
# ARMADILLO_VERSION_MAJOR - major version number
# ARMADILLO_VERSION_MINOR - minor version number
# ARMADILLO_VERSION_PATCH - patch version number
# ARMADILLO_VERSION_STRING - version number as a string (ex: "1.0.4")
# ARMADILLO_VERSION_NAME - name of the version (ex: "Antipodean Antileech")
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
# file Copyright.txt or https://cmake.org/licensing for details.
#=============================================================================
# Copyright 2011 Clement Creusot <creusot@cs.york.ac.uk>
#
# Distributed under the OSI-approved BSD License (the "License");
# see accompanying file Copyright.txt for details.
#
# This software is distributed WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the License for more information.
#=============================================================================
# (To distribute this file outside of CMake, substitute the full
# License text for the above reference.)
#[=======================================================================[.rst:
FindArmadillo
-------------
Find the Armadillo C++ library.
Armadillo is a library for linear algebra & scientific computing.
Using Armadillo:
::
find_package(Armadillo REQUIRED)
include_directories(${ARMADILLO_INCLUDE_DIRS})
add_executable(foo foo.cc)
target_link_libraries(foo ${ARMADILLO_LIBRARIES})
This module sets the following variables:
::
ARMADILLO_FOUND - set to true if the library is found
ARMADILLO_INCLUDE_DIRS - list of required include directories
ARMADILLO_LIBRARIES - list of libraries to be linked
ARMADILLO_VERSION_MAJOR - major version number
ARMADILLO_VERSION_MINOR - minor version number
ARMADILLO_VERSION_PATCH - patch version number
ARMADILLO_VERSION_STRING - version number as a string (ex: "1.0.4")
ARMADILLO_VERSION_NAME - name of the version (ex: "Antipodean Antileech")
#]=======================================================================]
find_path(ARMADILLO_INCLUDE_DIR
NAMES armadillo
PATHS "$ENV{ProgramFiles}/Armadillo/include"
)
if(ARMADILLO_INCLUDE_DIR)
# ------------------------------------------------------------------------
# Extract version information from <armadillo>
@@ -52,318 +52,117 @@ if(ARMADILLO_INCLUDE_DIR)
if(EXISTS "${ARMADILLO_INCLUDE_DIR}/armadillo_bits/arma_version.hpp")
# Read and parse armdillo version header file for version number
file(READ "${ARMADILLO_INCLUDE_DIR}/armadillo_bits/arma_version.hpp" _armadillo_HEADER_CONTENTS)
string(REGEX REPLACE ".*#define ARMA_VERSION_MAJOR ([0-9]+).*" "\\1" ARMADILLO_VERSION_MAJOR "${_armadillo_HEADER_CONTENTS}")
string(REGEX REPLACE ".*#define ARMA_VERSION_MINOR ([0-9]+).*" "\\1" ARMADILLO_VERSION_MINOR "${_armadillo_HEADER_CONTENTS}")
string(REGEX REPLACE ".*#define ARMA_VERSION_PATCH ([0-9]+).*" "\\1" ARMADILLO_VERSION_PATCH "${_armadillo_HEADER_CONTENTS}")
file(STRINGS "${ARMADILLO_INCLUDE_DIR}/armadillo_bits/arma_version.hpp" _ARMA_HEADER_CONTENTS REGEX "#define ARMA_VERSION_[A-Z]+ ")
string(REGEX REPLACE ".*#define ARMA_VERSION_MAJOR ([0-9]+).*" "\\1" ARMADILLO_VERSION_MAJOR "${_ARMA_HEADER_CONTENTS}")
string(REGEX REPLACE ".*#define ARMA_VERSION_MINOR ([0-9]+).*" "\\1" ARMADILLO_VERSION_MINOR "${_ARMA_HEADER_CONTENTS}")
string(REGEX REPLACE ".*#define ARMA_VERSION_PATCH ([0-9]+).*" "\\1" ARMADILLO_VERSION_PATCH "${_ARMA_HEADER_CONTENTS}")
# WARNING: The number of spaces before the version name is not one.
string(REGEX REPLACE ".*#define ARMA_VERSION_NAME\ +\"([0-9a-zA-Z\ _-]+)\".*" "\\1" ARMADILLO_VERSION_NAME "${_armadillo_HEADER_CONTENTS}")
string(REGEX REPLACE ".*#define ARMA_VERSION_NAME\ +\"([0-9a-zA-Z\ _-]+)\".*" "\\1" ARMADILLO_VERSION_NAME "${_ARMA_HEADER_CONTENTS}")
endif()
set(ARMADILLO_VERSION_STRING "${ARMADILLO_VERSION_MAJOR}.${ARMADILLO_VERSION_MINOR}.${ARMADILLO_VERSION_PATCH}")
endif ()
#======================
# Determine what support libraries are being used, and whether or not we need to
# link against them. We need to look in config.hpp.
set(SUPPORT_INCLUDE_DIRS "")
set(SUPPORT_LIBRARIES "")
set(ARMA_NEED_LIBRARY true) # Assume true.
if(EXISTS "${ARMADILLO_INCLUDE_DIR}/armadillo_bits/config.hpp")
file(READ "${ARMADILLO_INCLUDE_DIR}/armadillo_bits/config.hpp" _armadillo_CONFIG_CONTENTS)
# ARMA_USE_WRAPPER
string(REGEX MATCH "\r?\n[\t ]*#define[ \t]+ARMA_USE_WRAPPER[ \t]*\r?\n" ARMA_USE_WRAPPER "${_armadillo_CONFIG_CONTENTS}")
# ARMA_USE_LAPACK
string(REGEX MATCH "\r?\n[\t ]*#if[\t ]+!defined[(]ARMA_USE_LAPACK[)][\t ]*\r?\n[\t ]*#define[ \t]+ARMA_USE_LAPACK[ \t]*\r?\n" ARMA_USE_LAPACK "${_armadillo_CONFIG_CONTENTS}")
# ARMA_USE_BLAS
string(REGEX MATCH "\r?\n[\t ]*#if[\t ]+!defined[(]ARMA_USE_BLAS[)][\t ]*\r?\n[\t ]*#define[ \t]+ARMA_USE_BLAS[ \t]*\r?\n" ARMA_USE_BLAS "${_armadillo_CONFIG_CONTENTS}")
# ARMA_USE_ARPACK
# ARMA_USE_ARPACK
string(REGEX MATCH "\r?\n[\t ]*#if[\t ]+!defined[(]ARMA_USE_ARPACK[)][\t ]*\r?\n[\t ]*#define[ \t]+ARMA_USE_ARPACK[ \t]*\r?\n" ARMA_USE_ARPACK "${_armadillo_CONFIG_CONTENTS}")
# Look for #define ARMA_USE_HDF5.
string(REGEX MATCH "\r?\n[\t ]*#if[\t ]+!defined[(]ARMA_USE_HDF5[)][\t ]*\r?\n[\t ]*#define[ \t]+ARMA_USE_HDF5[ \t]*\r?\n" ARMA_USE_HDF5 "${_armadillo_CONFIG_CONTENTS}")
# If we aren't wrapping, things get a little more complex.
if("${ARMA_USE_WRAPPER}" STREQUAL "")
set(ARMA_NEED_LIBRARY false)
message(STATUS "ARMA_USE_WRAPPER is not defined, so all dependencies of "
"Armadillo must be manually linked.")
set(HAVE_LAPACK false)
set(HAVE_BLAS false)
# Search for LAPACK/BLAS (or replacement).
if ((NOT "${ARMA_USE_LAPACK}" STREQUAL "") AND
(NOT "${ARMA_USE_BLAS}" STREQUAL ""))
# In order of preference: MKL, ACML, OpenBLAS, ATLAS
set(MKL_FIND_QUIETLY true)
include(ARMA_FindMKL)
set(ACMLMP_FIND_QUIETLY true)
include(ARMA_FindACMLMP)
set(ACML_FIND_QUIETLY true)
include(ARMA_FindACML)
if (MKL_FOUND)
message(STATUS "Using MKL for LAPACK/BLAS: ${MKL_LIBRARIES}")
set(SUPPORT_LIBRARIES "${SUPPORT_LIBRARIES}" "${MKL_LIBRARIES}")
set(HAVE_LAPACK true)
set(HAVE_BLAS true)
elseif (ACMLMP_FOUND)
message(STATUS "Using multi-core ACML libraries for LAPACK/BLAS:
${ACMLMP_LIBRARIES}")
set(SUPPORT_LIBRARIES "${SUPPORT_LIBRARIES}" "${ACMLMP_LIBRARIES}")
set(HAVE_LAPACK true)
set(HAVE_BLAS true)
elseif (ACML_FOUND)
message(STATUS "Using ACML for LAPACK/BLAS: ${ACML_LIBRARIES}")
set(SUPPORT_LIBRARIES "${SUPPORT_LIBRARIES}" "${ACML_LIBRARIES}")
set(HAVE_LAPACK true)
set(HAVE_BLAS true)
endif ()
endif ()
# If we haven't found BLAS, try.
if (NOT "${ARMA_USE_BLAS}" STREQUAL "" AND NOT HAVE_BLAS)
# Search for BLAS.
set(OpenBLAS_FIND_QUIETLY true)
include(ARMA_FindOpenBLAS)
set(CBLAS_FIND_QUIETLY true)
include(ARMA_FindCBLAS)
set(BLAS_FIND_QUIETLY true)
include(ARMA_FindBLAS)
if (OpenBLAS_FOUND)
# Warn if ATLAS is found also.
if (CBLAS_FOUND)
message(STATUS "Warning: both OpenBLAS and ATLAS have been found; "
"ATLAS will not be used.")
endif ()
message(STATUS "Using OpenBLAS for BLAS: ${OpenBLAS_LIBRARIES}")
set(SUPPORT_LIBRARIES "${SUPPORT_LIBRARIES}" "${OpenBLAS_LIBRARIES}")
set(HAVE_BLAS true)
elseif (CBLAS_FOUND)
message(STATUS "Using ATLAS for BLAS: ${CBLAS_LIBRARIES}")
set(SUPPORT_LIBRARIES "${SUPPORT_LIBRARIES}" "${CBLAS_LIBRARIES}")
set(SUPPORT_INCLUDE_DIRS "${SUPPORT_INCLUDE_DIRS}"
"${CBLAS_INCLUDE_DIR}")
set(HAVE_BLAS true)
elseif (BLAS_FOUND)
message(STATUS "Using standard BLAS: ${BLAS_LIBRARIES}")
set(SUPPORT_LIBRARIES "${SUPPORT_LIBRARIES}" "${BLAS_LIBRARIES}")
set(HAVE_BLAS true)
endif ()
endif ()
# If we haven't found LAPACK, try.
if (NOT "${ARMA_USE_LAPACK}" STREQUAL "" AND NOT HAVE_LAPACK)
# Search for LAPACK.
set(CLAPACK_FIND_QUIETLY true)
include(ARMA_FindCLAPACK)
set(LAPACK_FIND_QUIETLY true)
include(ARMA_FindLAPACK)
# Only use ATLAS if OpenBLAS isn't being used.
if (CLAPACK_FOUND AND NOT OpenBLAS_FOUND)
message(STATUS "Using ATLAS for LAPACK: ${CLAPACK_LIBRARIES}")
set(SUPPORT_LIBRARIES "${SUPPORT_LIBRARIES}" "${CLAPACK_LIBRARIES}")
set(SUPPORT_INCLUDE_DIRS "${SUPPORT_INCLUDE_DIRS}"
"${CLAPACK_INCLUDE_DIR}")
set(HAVE_LAPACK true)
elseif (LAPACK_FOUND)
message(STATUS "Using standard LAPACK: ${LAPACK_LIBRARIES}")
set(SUPPORT_LIBRARIES "${SUPPORT_LIBRARIES}" "${LAPACK_LIBRARIES}")
set(HAVE_LAPACK true)
endif ()
endif ()
if (NOT "${ARMA_USE_LAPACK}" STREQUAL "" AND NOT HAVE_LAPACK)
message(FATAL_ERROR "Cannot find LAPACK library, but ARMA_USE_LAPACK is "
"set. Try specifying LAPACK libraries manually by setting the "
"LAPACK_LIBRARY variable.")
endif ()
if (NOT "${ARMA_USE_BLAS}" STREQUAL "" AND NOT HAVE_BLAS)
message(FATAL_ERROR "Cannot find BLAS library, but ARMA_USE_BLAS is set. "
"Try specifying BLAS libraries manually by setting the BLAS_LIBRARY "
"variable.")
endif ()
# Search for ARPACK (or replacement).
if (NOT "${ARMA_USE_ARPACK}" STREQUAL "")
# Use Armadillo ARPACK-finding procedure.
set(ARPACK_FIND_QUIETLY true)
include(ARMA_FindARPACK)
if (NOT ARPACK_FOUND)
message(FATAL_ERROR "ARMA_USE_ARPACK is defined in "
"armadillo_bits/config.hpp, but ARPACK cannot be found. Try "
"specifying ARPACK_LIBRARY.")
endif ()
set(SUPPORT_LIBRARIES "${SUPPORT_LIBRARIES}" "${ARPACK_LIBRARY}")
endif ()
# Search for HDF5 (or replacement).
if (NOT "${ARMA_USE_HDF5}" STREQUAL "")
find_package(HDF5 QUIET)
if(NOT HDF5_FOUND)
# On Debian systems, the HDF5 package has been split into multiple
# packages so that it is co-installable. But this may mean that the
# include files are hidden somewhere very odd that the FindHDF5.cmake
# script will not find. Thus, we'll also quickly check pkgconfig to see
# if there is information on what to use there.
find_package(PkgConfig)
if (PKG_CONFIG_FOUND)
pkg_check_modules(HDF5 hdf5)
# But using pkgconfig is a little weird because HDF5_LIBRARIES won't
# be filled with exact library paths, like the other scripts. So
# instead what we get is HDF5_LIBRARY_DIRS which is the equivalent of
# what we'd pass to -L.
if (HDF5_FOUND)
# I'm not sure what I think of doing this here...
link_directories("${HDF5_LIBRARY_DIRS}")
endif()
endif()
endif()
if(NOT HDF5_FOUND)
# We tried but didn't find it.
message(FATAL_ERROR "Armadillo HDF5 support is enabled, but HDF5 "
"cannot be found on the system. Consider disabling HDF5 support.")
endif()
set(SUPPORT_INCLUDE_DIRS "${SUPPORT_INCLUDE_DIRS}" "${HDF5_INCLUDE_DIRS}")
set(SUPPORT_LIBRARIES "${SUPPORT_LIBRARIES}" "${HDF5_LIBRARIES}")
endif ()
else()
# Some older versions still require linking against HDF5 since they did not
# wrap libhdf5. This was true for versions older than 4.300.
if(NOT "${ARMA_USE_HDF5}" STREQUAL "" AND
"${ARMADILLO_VERSION_STRING}" VERSION_LESS "4.300.0")
message(STATUS "Armadillo HDF5 support is enabled and manual linking is "
"required.")
# We have HDF5 support and need to link against HDF5.
find_package(HDF5)
if(NOT HDF5_FOUND)
# On Debian systems, the HDF5 package has been split into multiple
# packages so that it is co-installable. But this may mean that the
# include files are hidden somewhere very odd that the FindHDF5.cmake
# script will not find. Thus, we'll also quickly check pkgconfig to see
# if there is information on what to use there.
find_package(PkgConfig)
if (PKG_CONFIG_FOUND)
pkg_check_modules(HDF5 hdf5)
# But using pkgconfig is a little weird because HDF5_LIBRARIES won't
# be filled with exact library paths, like the other scripts. So
# instead what we get is HDF5_LIBRARY_DIRS which is the equivalent of
# what we'd pass to -L.
if (HDF5_FOUND)
# I'm not sure what I think of doing this here...
link_directories("${HDF5_LIBRARY_DIRS}")
endif()
endif()
endif()
if(NOT HDF5_FOUND)
# We tried but didn't find it.
message(FATAL_ERROR "Armadillo HDF5 support is enabled, but HDF5 "
"cannot be found on the system. Consider disabling HDF5 support.")
endif()
set(SUPPORT_INCLUDE_DIRS "${HDF5_INCLUDE_DIRS}")
set(SUPPORT_LIBRARIES "${HDF5_LIBRARIES}")
endif()
# Versions between 4.300 and 4.500 did successfully wrap HDF5, but didn't have good support for setting the include directory correctly.
if(NOT "${ARMA_USE_HDF5}" STREQUAL "" AND
"${ARMADILLO_VERSION_STRING}" VERSION_GREATER "4.299.0" AND
"${ARMADILLO_VERSION_STRING}" VERSION_LESS "4.450.0")
message(STATUS "Armadillo HDF5 support is enabled and include "
"directories must be found.")
find_package(HDF5)
if(NOT HDF5_FOUND)
# On Debian systems, the HDF5 package has been split into multiple
# packages so that it is co-installable. But this may mean that the
# include files are hidden somewhere very odd that the FindHDF5.cmake
# script will not find. Thus, we'll also quickly check pkgconfig to see
# if there is information on what to use there.
find_package(PkgConfig)
if (PKG_CONFIG_FOUND)
pkg_check_modules(HDF5 hdf5)
endif()
endif()
if(NOT HDF5_FOUND)
# We tried but didn't find it.
message(FATAL_ERROR "Armadillo HDF5 support is enabled, but HDF5 "
"cannot be found on the system. Consider disabling HDF5 support.")
endif()
set(SUPPORT_INCLUDE_DIRS "${HDF5_INCLUDE_DIRS}")
endif()
endif()
else()
message(FATAL_ERROR "${ARMADILLO_INCLUDE_DIR}/armadillo_bits/config.hpp not "
"found! Cannot determine what to link against.")
file(STRINGS "${ARMADILLO_INCLUDE_DIR}/armadillo_bits/config.hpp" _ARMA_CONFIG_CONTENTS REGEX "^#define ARMA_USE_[A-Z]+")
string(REGEX MATCH "ARMA_USE_WRAPPER" _ARMA_USE_WRAPPER "${_ARMA_CONFIG_CONTENTS}")
string(REGEX MATCH "ARMA_USE_LAPACK" _ARMA_USE_LAPACK "${_ARMA_CONFIG_CONTENTS}")
string(REGEX MATCH "ARMA_USE_BLAS" _ARMA_USE_BLAS "${_ARMA_CONFIG_CONTENTS}")
string(REGEX MATCH "ARMA_USE_ARPACK" _ARMA_USE_ARPACK "${_ARMA_CONFIG_CONTENTS}")
string(REGEX MATCH "ARMA_USE_HDF5" _ARMA_USE_HDF5 "${_ARMA_CONFIG_CONTENTS}")
endif()
if (ARMA_NEED_LIBRARY)
include(FindPackageHandleStandardArgs)
# If _ARMA_USE_WRAPPER is set, then we just link to armadillo, but if it's not then we need support libraries instead
set(_ARMA_SUPPORT_LIBRARIES)
if(_ARMA_USE_WRAPPER)
# UNIX paths are standard, no need to write.
find_library(ARMADILLO_LIBRARY
NAMES armadillo
PATHS "$ENV{ProgramFiles}/Armadillo/lib" "$ENV{ProgramFiles}/Armadillo/lib64" "$ENV{ProgramFiles}/Armadillo"
)
set(_ARMA_REQUIRED_VARS ARMADILLO_LIBRARY ARMADILLO_INCLUDE_DIR VERSION_VAR ARMADILLO_VERSION_STRING)
else()
# don't link to armadillo in this case
set(ARMADILLO_LIBRARY "")
if(_ARMA_USE_LAPACK)
if(ARMADILLO_FIND_QUIETLY OR NOT ARMADILLO_FIND_REQUIRED)
find_package(LAPACK QUIET)
else()
find_package(LAPCK REQUIRED)
endif()
if(LAPACK_FOUND)
set(_ARMA_SUPPORT_LIBRARIES "${_ARMA_SUPPORT_LIBRARIES}" "${LAPACK_LIBRARIES}")
endif()
endif()
if(_ARMA_USE_BLAS)
if(ARMADILLO_FIND_QUIETLY OR NOT ARMADILLO_FIND_REQUIRED)
find_package(BLAS QUIET)
else()
find_package(BLAS REQUIRED)
endif()
if(BLAS_FOUND)
set(_ARMA_SUPPORT_LIBRARIES "${_ARMA_SUPPORT_LIBRARIES}" "${BLAS_LIBRARIES}")
endif()
endif()
if(_ARMA_USE_ARPACK)
if(ARMADILLO_FIND_QUIETLY OR NOT ARMADILLO_FIND_REQUIRED)
find_package(ARPACK QUIET)
else()
find_package(ARPACK REQUIRED)
endif()
if(ARPACK_FOUND)
set(_ARMA_SUPPORT_LIBRARIES "${_ARMA_SUPPORT_LIBRARIES}" "${ARPACK_LIBRARIES}")
endif()
endif()
if(_ARMA_USE_HDF5)
find_package(HDF5 QUIET)
if(NOT HDF5_FOUND)
# On Debian systems, the HDF5 package has been split into multiple
# packages so that it is co-installable. But this may mean that the
# include files are hidden somewhere very odd that FindHDF5.cmake will
# not find. Thus, we'll also quickly check pkgconfig to see if there is
# information on what to use there.
message(WARNING "HDF5 required but not found; using PkgConfig")
find_package(PkgConfig)
if (PKG_CONFIG_FOUND)
pkg_check_modules(HDF5 REQUIRED hdf5)
link_directories("${HDF5_LIBRARY_DIRS}")
else()
message(FATAL_ERROR "PkgConfig (Used to help find HDF5) was not found")
endif()
endif()
set(_ARMA_SUPPORT_INCLUDE_DIRS "${HDF5_INCLUDE_DIRS}")
set(_ARMA_SUPPORT_LIBRARIES "${_ARMA_SUPPORT_LIBRARIES}" "${HDF5_LIBRARIES}")
endif()
set(ARMADILLO_FOUND true)
set(_ARMA_REQUIRED_VARS ARMADILLO_INCLUDE_DIR VERSION_VAR ARMADILLO_VERSION_STRING)
endif()
# Checks 'REQUIRED', 'QUIET' and versions.
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Armadillo
REQUIRED_VARS ARMADILLO_LIBRARY ARMADILLO_INCLUDE_DIR
VERSION_VAR ARMADILLO_VERSION_STRING)
# version_var fails with cmake < 2.8.4.
else ()
# Checks 'REQUIRED', 'QUIET' and versions.
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Armadillo
REQUIRED_VARS ARMADILLO_INCLUDE_DIR
VERSION_VAR ARMADILLO_VERSION_STRING)
endif ()
find_package_handle_standard_args(Armadillo REQUIRED_VARS ${_ARMA_REQUIRED_VARS})
if (ARMADILLO_FOUND)
# Also include support include directories.
set(ARMADILLO_INCLUDE_DIRS ${ARMADILLO_INCLUDE_DIR} ${SUPPORT_INCLUDE_DIRS})
# Also include support libraries to link against.
if (ARMA_NEED_LIBRARY)
set(ARMADILLO_LIBRARIES ${ARMADILLO_LIBRARY} ${SUPPORT_LIBRARIES})
else ()
set(ARMADILLO_LIBRARIES ${SUPPORT_LIBRARIES})
endif ()
message(STATUS "Armadillo libraries: ${ARMADILLO_LIBRARIES}")
set(ARMADILLO_INCLUDE_DIRS ${ARMADILLO_INCLUDE_DIR})
set(ARMADILLO_LIBRARIES ${ARMADILLO_LIBRARY} ${_ARMA_SUPPORT_LIBRARIES})
endif ()
# Clean up internal variables
unset(_ARMA_REQUIRED_VARS)
unset(_ARMA_SUPPORT_LIBRARIES)
unset(_ARMA_USE_WRAPPER)
unset(_ARMA_USE_LAPACK)
unset(_ARMA_USE_BLAS)
unset(_ARMA_USE_ARPACK)
unset(_ARMA_USE_HDF5)
unset(_ARMA_CONFIG_CONTENTS)
unset(_ARMA_HEADER_CONTENTS)
unset(__ARMA_SUPPORT_INCLUDE_DIRS)
# Hide internal variables
mark_as_advanced(
ARMADILLO_INCLUDE_DIR
ARMADILLO_LIBRARY)
#======================
+13 -57
View File
@@ -292,51 +292,6 @@ else()
endif ()
endif()
# On Windows, Armadillo should be using LAPACK and BLAS but we still need to
# link against it. We don't want to use the FindLAPACK or FindBLAS modules
# because then we are required to have a FORTRAN compiler (argh!) so we will try
# and find LAPACK and BLAS ourselves, using a slightly modified variant of the
# script Armadillo uses to find these.
if (WIN32)
find_library(LAPACK_LIBRARY
NAMES lapack liblapack lapack_win32_MT lapack_win32
PATHS "C:/Program Files/Armadillo"
PATH_SUFFIXES "examples/lib_win32/")
if (NOT LAPACK_LIBRARY)
message(FATAL_ERROR "Cannot find LAPACK library (.lib)!")
endif ()
find_library(BLAS_LIBRARY
NAMES blas libblas blas_win32_MT blas_win32
PATHS "C:/Program Files/Armadillo"
PATH_SUFFIXES "examples/lib_win32/")
if (NOT BLAS_LIBRARY)
message(FATAL_ERROR "Cannot find BLAS library (.lib)!")
endif ()
# Piggyback LAPACK and BLAS linking into Armadillo link.
set(ARMADILLO_LIBRARIES
${ARMADILLO_LIBRARIES} ${BLAS_LIBRARY} ${LAPACK_LIBRARY})
# Ensure that the libraries are added to the MSVC IDE runtime path.
get_filename_component(BLAS_DIR ${BLAS_LIBRARY} DIRECTORY)
get_filename_component(LAPACK_DIR ${LAPACK_LIBRARY} DIRECTORY)
# Sometimes, especially with an OpenBLAS install via nuget, the DLLs are
# actually in ../../bin/x64/. Automatically add these.
if (EXISTS "${BLAS_DIR}/../../bin/x64/")
get_filename_component(BLAS_DLL_DIR "${BLAS_DIR}/../../bin/x64" ABSOLUTE)
set(DLL_COPY_DIRS ${DLL_COPY_DIRS} "${BLAS_DLL_DIR}")
endif ()
if (EXISTS "${LAPACK_DIR}/../../bin/x64/")
get_filename_component(LAPACK_DLL_DIR "${LAPACK_DIR}/../../bin/x64" ABSOLUTE)
set(DLL_COPY_DIRS ${DLL_COPY_DIRS} "${BLAS_DLL_DIR}")
endif ()
endif ()
# Include directories for the previous dependencies.
set(MLPACK_INCLUDE_DIRS ${MLPACK_INCLUDE_DIRS} ${ARMADILLO_INCLUDE_DIRS})
set(MLPACK_LIBRARIES ${MLPACK_LIBRARIES} ${ARMADILLO_LIBRARIES})
@@ -373,6 +328,7 @@ if (NOT STB_IMAGE_FOUND)
install(FILES "${CMAKE_BINARY_DIR}/deps/${STB_DIR}/stb_image.h" DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}")
install(FILES "${CMAKE_BINARY_DIR}/deps/${STB_DIR}/stb_image_write.h" DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}")
add_definitions(-DHAS_STB)
set(STB_AVAILABLE "1")
else ()
message(WARNING
"stb/stb_image.h is not installed. Image utilities will not be available!")
@@ -393,6 +349,7 @@ else ()
# Already has STB installed.
add_definitions(-DHAS_STB)
set(MLPACK_INCLUDE_DIRS ${MLPACK_INCLUDE_DIRS} ${STB_IMAGE_INCLUDE_DIR})
set(STB_AVAILABLE "1")
endif ()
@@ -415,7 +372,12 @@ if (NOT ENSMALLEN_FOUND)
# Get the name of the directory.
file (GLOB ENS_DIRECTORIES RELATIVE "${CMAKE_BINARY_DIR}/deps/"
"${CMAKE_BINARY_DIR}/deps/ensmallen-[0-9]*.[0-9]*.[0-9]*")
list(FILTER ENS_DIRECTORIES EXCLUDE REGEX "ensmallen-.*\.tar\.gz")
# list(FILTER) is not available on 3.5 or older, but try to keep
# configuring without filtering the list anyway (it might work if only
# the file ensmallen-latest.tar.gz is present.
if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.6.0")
list(FILTER ENS_DIRECTORIES EXCLUDE REGEX "ensmallen-.*\.tar\.gz")
endif ()
list(LENGTH ENS_DIRECTORIES ENS_DIRECTORIES_LEN)
if (ENS_DIRECTORIES_LEN EQUAL 1)
list(GET ENS_DIRECTORIES 0 ENSMALLEN_INCLUDE_DIR)
@@ -453,6 +415,9 @@ endif ()
# Unfortunately this configuration variable is necessary and will need to be
# updated as time goes on and new versions are released.
set(Boost_ADDITIONAL_VERSIONS
"1.72.0" "1.72"
"1.71.0" "1.71"
"1.70.0" "1.70"
"1.69.0" "1.69"
"1.68.0" "1.68"
"1.67.0" "1.67"
@@ -464,23 +429,14 @@ set(Boost_ADDITIONAL_VERSIONS
"1.61.1" "1.61.0" "1.61"
"1.60.1" "1.60.0" "1.60"
"1.59.1" "1.59.0" "1.59"
"1.58.1" "1.58.0" "1.58"
"1.57.1" "1.57.0" "1.57"
"1.56.1" "1.56.0" "1.56"
"1.55.1" "1.55.0" "1.55"
"1.54.1" "1.54.0" "1.54"
"1.53.1" "1.53.0" "1.53"
"1.52.1" "1.52.0" "1.52"
"1.51.1" "1.51.0" "1.51"
"1.50.1" "1.50.0" "1.50"
"1.49.1" "1.49.0" "1.49")
"1.58.1" "1.58.0" "1.58")
# Disable forced config-mode CMake search for Boost, which only imports targets
# and does not set the variables that we need.
#
# TODO for the brave: transition all mlpack's CMake to 'target-based modern
# CMake'. Good luck! You'll need it.
set(Boost_NO_BOOST_CMAKE 1)
find_package(Boost 1.49
find_package(Boost 1.58
COMPONENTS
program_options
unit_test_framework
+46
View File
@@ -28,3 +28,49 @@ Members of the Contributors team are encouraged to review pull requests that
have already been reviewed, and pull request contributors are encouraged to seek
multiple reviews. Reviews from anyone not on the Contributors team are always
appreciated and encouraged!
## Reviewing Pull Requests
All mlpack contributors who choose to review and provide feedback on pull
requests have a responsibility to both the project and the individual making
the contribution.
Reviews and feedback should be
[helpful, insightful, and geared towards improving the contribution](
https://www.youtube.com/watch?v=NNXk_WJzyMI).
If there are reasons why you feel the PR should not be merged, explain
what those are. Be open to having your mind changed. Be open to
working with the contributor to make the pull request better.
Please don't leave dismissive or disrespectful reviews! It's not helpful for
anyone.
When reviewing a pull request, the primary goals are:
- For the codebase/project to improve
- For the person submitting the request to succeed
Even if a pull request does not get merged, the submitters should come away
from the experience feeling like their effort was not wasted or unappreciated.
Every pull request from a new contributor is an opportunity to grow the community.
When changes are necessary, request them, do not demand them, and do not assume
that the contributor already knows how to do that. Be there to lend a helping
hand in case of need.
Since there can sometimes be a lot more pull requests being opened than
reviewed, we highly encourage everyone to review each others pull request
keeping in mind all the above mentioned points.
Let's welcome new contributors with ❤️.
## Pull Request Waiting Time
mlpack is a community-driven project, so everyone only works on it in their
free time; this means it may take some time for them to review pull requests.
While gentle reminders are welcome, please be patient and avoid constantly
messaging contributors or tagging them on pull requests.
Typically small PRs will be reviewed within a handful of days; larger PRs might
take a few weeks for an initial review, and it may be a little bit longer in
times of high activity.
+3
View File
@@ -128,6 +128,9 @@ Copyright:
Copyright 2020, Sriram S K <sriramsk1999@gmail.com>
Copyright 2020, Manoranjan Kumar Bharti ( Nakul Bharti ) <knakul853@gmail.com>
Copyright 2020, Saraansh Tandon <saraanshtandon1999@gmail.com>
Copyright 2020, Gaurav Singh <gs8763076@gmail.com>
Copyright 2020, Lakshya Ojha <ojhalakshya@gmail.com>
Copyright 2020, Bisakh Mondal <bisakhmondal00@gmail.com>
License: BSD-3-clause
All rights reserved.
+34 -4
View File
@@ -1,10 +1,14 @@
### mlpack ?.?.?
###### ????-??-??
* Templated return type of `Forward function` of loss functions (#2339).
* Added `R2 Score` regression metric (#2323).
* Added `mean squared logarithmic error` loss function for neural networks
(#2210).
* Added `mean bias loss function` for neural networks (#2210).
* The DecisionStump class has been marked deprecated; use the `DecisionTree`
class with `NoRecursion=true` or use `ID3DecisionStump` instead (#2099).
@@ -25,12 +29,18 @@
* Add functions to access parameters of `Convolution` and `AtrousConvolution`
layers (#1985).
* Add Compute Error function in lars regression and changing Train function to
return computed error (#2139).
* Add Julia bindings (#1949). Build settings can be controlled with the
`BUILD_JULIA_BINDINGS=(ON/OFF)` and `JULIA_EXECUTABLE=/path/to/julia` CMake
parameters.
* CMake fix for finding STB include directory (#2145).
* Add bindings for loading and saving images (#2019); `mlpack_image_converter`
from the command-line, `mlpack.image_converter()` from Python.
* Add normalization support for CF binding (#2136).
* Add Mish activation function (#2158).
@@ -42,12 +52,32 @@
* Better error handling of eigendecompositions and Cholesky decompositions
(#2088, #1840).
* Add LiSHT activation function (#2182).
* Add Valid and Same Padding for Transposed Convolution layer (#2163).
* Add CELU activation function (#2191)
* Add Log-Hyperbolic-Cosine Loss function (#2207).
* Add Log-Hyperbolic-Cosine Loss function (#2207)
* Change neural network types to avoid unnecessary use of rvalue references
(#2259).
* Bump minimum Boost version to 1.58 (#2305).
* Refactor STB support so HAS_STB macro is not needed when compiling against
mlpack (#2312).
* Add Hard Shrink Activation Function (#2186).
* Add Soft Shrink Activation Function (#2174).
* Add Hinge Embedding Loss Function (#2229).
* Add Cosine Embedding Loss Function (#2209).
* Add Margin Ranking Loss Function (#2264).
### mlpack 3.2.2
###### 2019-11-26
+8 -5
View File
@@ -17,6 +17,7 @@ src="https://cdn.rawgit.com/mlpack/mlpack.org/e7d36ed8/mlpack-black.svg" style="
<a href="http://ci.mlpack.org/job/mlpack%20-%20git%20commit%20test/"><img src="https://img.shields.io/jenkins/build.svg?jobUrl=http%3A%2F%2Fci.mlpack.org%2Fjob%2Fmlpack%2520-%2520git%2520commit%2520test%2F&label=Linux%20build&style=flat-square" alt="Jenkins"></a>
<a href="https://coveralls.io/github/mlpack/mlpack?branch=master"><img src="https://img.shields.io/coveralls/mlpack/mlpack/master.svg?style=flat-square" alt="Coveralls"></a>
<a href="https://opensource.org/licenses/BSD-3-Clause"><img src="https://img.shields.io/badge/License-BSD%203--Clause-blue.svg?style=flat-square" alt="License"></a>
<a href="http://numfocus.org/donate-to-mlpack"><img src="https://img.shields.io/badge/sponsored%20by-NumFOCUS-orange.svg?style=flat-square&colorA=E1523D&colorB=007D8A" alt="NumFOCUS"></a>
</p>
<p align="center">
@@ -33,6 +34,8 @@ functions as a "swiss army knife" for machine learning researchers. In addition
to its powerful C++ interface, mlpack also provides command-line programs,
Python bindings, and Julia bindings.
[//]: # (numfocus-fiscal-sponsor-attribution)
mlpack uses an [open governance model](./GOVERNANCE.md) and is fiscally
sponsored by [NumFOCUS](https://numfocus.org/). Consider making a
[tax-deductible donation](https://numfocus.org/donate-to-mlpack) to help the
@@ -40,7 +43,7 @@ project pay for developer time, professional services, travel, workshops, and a
variety of other needs.
<div align="center">
<a href="https://numfocus.org/donate-to-mlpack">
<a href="https://numfocus.org/">
<img height="60px"
src="https://raw.githubusercontent.com/numfocus/templates/master/images/numfocus-logo.png"
align="center">
@@ -97,11 +100,11 @@ Citations are beneficial for the growth and improvement of mlpack.
mlpack has the following dependencies:
Armadillo >= 8.400.0
Armadillo >= 8.400.0
Boost (program_options, math_c99, unit_test_framework, serialization,
spirit)
CMake >= 3.3.2
ensmallen >= 2.10.0
spirit) >= 1.58.0
CMake >= 3.3.2
ensmallen >= 2.10.0
All of those should be available in your distribution's package manager. If
not, you will have to compile each of them by hand. See the documentation for
+1 -1
View File
@@ -79,7 +79,7 @@ system and have headers present:
- Armadillo >= 8.400.0 (with LAPACK support)
- Boost (math_c99, program_options, serialization, unit_test_framework, heap,
spirit) >= 1.49
spirit) >= 1.58
- ensmallen >= 2.10.0 (will be downloaded if not found)
In addition, mlpack has the following optional dependencies:
+1 -1
View File
@@ -118,7 +118,7 @@ compiler version, check if the Visual Studio compiler and Windows SDK are instal
- Run cmake:
@code
cmake -G "Visual Studio 16 2019" -A x64 -DBLAS_LIBRARY:FILEPATH="C:/mlpack/mlpack/packages/OpenBLAS.0.2.14.1/lib/native/lib/x64/libopenblas.dll.a" -DLAPACK_LIBRARY:FILEPATH="C:/mlpack/mlpack/packages/OpenBLAS.0.2.14.1/lib/native/lib/x64/libopenblas.dll.a" -DARMADILLO_INCLUDE_DIR="C:/mlpack/armadillo/include" -DARMADILLO_LIBRARY:FILEPATH="C:/mlpack/armadillo/build/Debug/armadillo.lib" -DBOOST_INCLUDEDIR:PATH="C:/boost/" -DBOOST_LIBRARYDIR:PATH="C:/boost/lib64-msvc-14.2" -DDEBUG=OFF -DPROFILE=OFF ..
cmake -G "Visual Studio 16 2019" -A x64 -DBLAS_LIBRARIES:FILEPATH="C:/mlpack/mlpack/packages/OpenBLAS.0.2.14.1/lib/native/lib/x64/libopenblas.dll.a" -DLAPACK_LIBRARIES:FILEPATH="C:/mlpack/mlpack/packages/OpenBLAS.0.2.14.1/lib/native/lib/x64/libopenblas.dll.a" -DARMADILLO_INCLUDE_DIR="C:/mlpack/armadillo/include" -DARMADILLO_LIBRARY:FILEPATH="C:/mlpack/armadillo/build/Debug/armadillo.lib" -DBOOST_INCLUDEDIR:PATH="C:/boost/" -DBOOST_LIBRARYDIR:PATH="C:/boost/lib64-msvc-14.2" -DDEBUG=OFF -DPROFILE=OFF ..
@endcode
@note cmake will attempt to automatically download the ensmallen dependency. If for some reason cmake can't download the dependency, you will need to manually download ensmallen from http://ensmallen.org/ and extract it to "C:\mlpack\mlpack\deps\". Then, specify the path to ensmallen using the flag: -DENSMALLEN_INCLUDE_DIR=C:/mlpack/mlpack/deps/ensmallen/include
+31 -25
View File
@@ -330,39 +330,46 @@ mlpack's image saving/loading functionality is based on [stb/](https://github.co
Image utilities supports loading and saving of images.
It supports filetypes "jpg", "png", "tga","bmp", "psd", "gif", "hdr", "pic", "pnm" for loading and "jpg", "png", "tga", "bmp", "hdr" for saving.
It supports filetypes "jpg", "png", "tga", "bmp", "psd", "gif", "hdr", "pic",
"pnm" for loading and "jpg", "png", "tga", "bmp", "hdr" for saving.
The datatype associated is unsigned char to support RGB values in the range 1-255. To feed data into the network typecast of `arma::Mat` may be required. Images are stored in matrix as (width * height * channels, NumberOfImages). Therefore imageMatrix.col(0) would be the first image if images are loaded in imageMatrix.
The datatype associated is unsigned char to support RGB values in the range
1-255. To feed data into the network typecast of `arma::Mat` may be required.
Images are stored in the matrix as (width * height * channels, NumberOfImages).
Therefore @c imageMatrix.col(0) would be the first image if images are loaded in
@c imageMatrix.
@section imageinfo_api_imagetut Accessing Metadata of Images: ImageInfo
ImageInfo class contains the metadata of the images.
@code
ImageInfo(const size_t width,
const size_t height,
const size_t channels);
const size_t height,
const size_t channels,
const size_t quality = 90);
@endcode
Other public memebers include:
- flipVertical Flip the image vertical upon loading.
- quality Compression of the image if saved as jpg (0-100).
The @c quality member denotes the compression of the image if it is saved as
`jpg`; it takes values from 0 to 100.
@section load_api_imagetut Loading Images in C++
Standalone loading of images.
@code
template<typename eT>
bool Load(const std::string& filename,
arma::Mat<eT>& matrix,
ImageInfo& info,
const bool fatal,
const bool transpose);
template<typename eT>
bool Load(const std::string& filename,
arma::Mat<eT>& matrix,
ImageInfo& info,
const bool fatal);
@endcode
Loading a test image. It also fills up the ImageInfo class object.
The example below loads a test image. It also fills up the ImageInfo class
object.
@code
data::ImageInfo info;
data::Load("test_image.png", matrix, info, false, true);
data::Load("test_image.png", matrix, info, false);
@endcode
ImageInfo requires height, width, number of channels of the image.
@@ -377,18 +384,17 @@ More than one image can be loaded into the same matrix.
Loading multiple images:
@code
template<typename eT>
bool Load(const std::vector<std::string>& files,
arma::Mat<eT>& matrix,
ImageInfo& info,
const bool fatal,
const bool transpose);
template<typename eT>
bool Load(const std::vector<std::string>& files,
arma::Mat<eT>& matrix,
ImageInfo& info,
const bool fatal);
@endcode
@code
data::ImageInfo info;
std::vector<std::string>> files{"test_image1.bmp","test_image2.bmp"};
data::load(files, matrix, info, false, true);
data::ImageInfo info;
std::vector<std::string>> files{"test_image1.bmp","test_image2.bmp"};
data::Load(files, matrix, info, false);
@endcode
@section save_api_imagetut Saving Images in C++
+61 -27
View File
@@ -204,17 +204,17 @@ using namespace mlpack::ann;
int main()
{
// Load the training set.
arma::mat dataset;
data::Load("thyroid_train.csv", dataset, true);
// Load the training set and testing set.
arma::mat trainData;
data::Load("thyroid_train.csv", trainData, true);
arma::mat testData;
data::Load("thyroid_test.csv", testData, true);
// Split the labels from the training set.
arma::mat trainData = dataset.submat(0, 0, dataset.n_rows - 4,
dataset.n_cols - 1);
// Split the data from the training set.
arma::mat trainLabels = dataset.submat(dataset.n_rows - 3, 0,
dataset.n_rows - 1, dataset.n_cols - 1);
// Split the labels from the training set and testing set respectively.
arma::mat trainLabels = trainData.row(trainData.n_rows - 1);
arma::mat testLabels = testData.row(testData.n_rows - 1);
trainData.shed_row(trainData.n_rows - 1);
testData.shed_row(testData.n_rows - 1);
// Initialize the network.
FFN<> model;
@@ -226,14 +226,48 @@ int main()
// Train the model.
model.Train(trainData, trainLabels);
// Use the Predict method to get the assignments.
arma::mat assignments;
model.Predict(trainData, assignments);
// Use the Predict method to get the predictions.
arma::mat predictionTemp;
model.Predict(testData, predictionTemp);
/*
Since the predictionsTemp is of dimensions (3 x number_of_data_points)
with continuous values, we first need to reduce it to a dimension of
(1 x number_of_data_points) with scalar values, to be able to compare with
testLabels.
The first step towards doing this is to create a matrix of zeros with the
desired dimensions (1 x number_of_data_points).
In predictionsTemp, the 3 dimensions for each data point correspond to the
probabilities of belonging to the three possible classes.
*/
arma::mat prediction = arma::zeros<arma::mat>(1, predictionTemp.n_cols);
// Find index of max prediction for each data point and store in "prediction"
for (size_t i = 0; i < predictionTemp.n_cols; ++i)
{
// we add 1 to the max index, so that it matches the actual test labels.
prediction(i) = arma::as_scalar(arma::find(
arma::max(predictionTemp.col(i)) == predictionTemp.col(i), 1)) + 1;
}
/*
Compute the error between predictions and testLabels,
now that we have the desired predictions.
*/
size_t correct = arma::accu(prediction == testLabels);
double classificationError = 1 - double(correct) / testData.n_cols;
// Print out the classification error for the testing dataset.
std::cout << "Classification Error for the Test set: " << classificationError << std::endl;
return 0;
}
@endcode
Now, the matrix assignments holds the classification of each point in the
dataset.
Now, the matrix prediction holds the classification of each point in the
dataset. Subsequently, we find the classification error by comparing it
with testLabels.
In the next example, we create simple noisy sine sequences, which are trained
later on, using the RNN class in the `RNNModel()` method.
@@ -328,7 +362,7 @@ implementation of a \c Forward() method. The interface looks like:
@code
template<typename eT>
void Forward(const arma::Mat<eT>&& input, arma::Mat<eT>&& output);
void Forward(const arma::Mat<eT>& input, arma::Mat<eT>& output);
@endcode
The method should calculate the output of the layer given the input matrix and
@@ -339,9 +373,9 @@ through f:
@code
template<typename eT>
void Backward(const arma::Mat<eT>&& input,
arma::Mat<eT>&& gy,
arma::Mat<eT>&& g);
void Backward(const arma::Mat<eT>& input,
const arma::Mat<eT>& gy,
arma::Mat<eT>& g);
@endcode
Finally, if the layer is differentiable, the layer must also implement
@@ -349,9 +383,9 @@ a Gradient() method:
@code
template<typename eT>
void Gradient(const arma::Mat<eT>&& input,
arma::Mat<eT>&& error,
arma::Mat<eT>&& gradient);
void Gradient(const arma::Mat<eT>& input,
const arma::Mat<eT>& error,
arma::Mat<eT>& gradient);
@endcode
The Gradient function should calculate the gradient with respect to the input
@@ -434,21 +468,21 @@ API, so we must implement some additional functions.
@code
template<typename InputType, typename OutputType>
void Forward(const InputType&& input, OutputType&& output)
void Forward(const InputType& input, OutputType& output)
{
output = arma::ones(input.n_rows, input.n_cols);
}
template<typename InputType, typename ErrorType, typename GradientType>
void Backward(const InputType&& input, ErrorType&& gy, GradientType&& g)
void Backward(const InputType& input, const ErrorType& gy, GradientType& g)
{
g = arma::zeros(gy.n_rows, gy.n_cols) + gy;
}
template<typename InputType, typename ErrorType, typename GradientType>
void Gradient(const InputType&& input,
ErrorType&& error,
GradientType&& gradient)
void Gradient(const InputType& input,
ErrorType& error,
GradientType& gradient)
{
gradient = arma::zeros(input.n_rows, input.n_cols) * error;
}
+188
View File
@@ -0,0 +1,188 @@
/*!
@file image.txt
@author Mehul Kumar Nirala
@brief Tutorial for how to load and save images in mlpack.
@page imagetutorial Image Utilities tutorial
@section intro_imagetut Introduction
Image datasets are becoming increasingly popular in deep learning.
mlpack's image saving/loading functionality is based on [stb/](https://github.com/nothings/stb).
@section toc_imagetut Table of Contents
This tutorial is split into the following sections:
- \ref intro_imagetut
- \ref toc_imagetut
- \ref model_api_imagetut
- \ref imageinfo_api_imagetut
- \ref load_api_imagetut
- \ref save_api_imagetut
@section model_api_imagetut Model API
Image utilities supports loading and saving of images.
It supports filetypes "jpg", "png", "tga","bmp", "psd", "gif", "hdr", "pic", "pnm" for loading and "jpg", "png", "tga", "bmp", "hdr" for saving.
The datatype associated is unsigned char to support RGB values in the range 1-255. To feed data into the network typecast of `arma::Mat` may be required. Images are stored in matrix as (width * height * channels, NumberOfImages). Therefore imageMatrix.col(0) would be the first image if images are loaded in imageMatrix.
@section imageinfo_api_imagetut ImageInfo
ImageInfo class contains the metadata of the images.
@code
/**
* Instantiate the ImageInfo object with the image width, height, channels.
*
* @param width Image width.
* @param height Image height.
* @param channels number of channels in the image.
*/
ImageInfo(const size_t width,
const size_t height,
const size_t channels);
@endcode
Other public memebers include:
- quality Compression of the image if saved as jpg (0-100).
@section load_api_imagetut Load
Standalone loading of images.
@code
/**
* Load the image file into the given matrix.
*
* @param filename Name of the image file.
* @param matrix Matrix to load the image into.
* @param info An object of ImageInfo class.
* @param fatal If an error should be reported as fatal (default false).
* @param transpose If true, flips the image, same as transposing the
* matrix after loading.
* @return Boolean value indicating success or failure of load.
*/
template<typename eT>
bool Load(const std::string& filename,
arma::Mat<eT>& matrix,
ImageInfo& info,
const bool fatal,
const bool transpose);
@endcode
Loading a test image. It also fills up the ImageInfo class object.
@code
data::ImageInfo info;
data::Load("test_image.png", matrix, info, false, true);
@endcode
ImageInfo requires height, width, number of channels of the image.
@code
size_t height = 64, width = 64, channels = 1;
data::ImageInfo info(width, height, channels);
@endcode
More than one image can be loaded into the same matrix.
Loading multiple images:
@code
/**
* Load the image file into the given matrix.
*
* @param files A vector consisting of filenames.
* @param matrix Matrix to save the image from.
* @param info An object of ImageInfo class.
* @param fatal If an error should be reported as fatal (default false).
* @param transpose If true, flips the image, same as transposing the
* matrix after loading.
* @return Boolean value indicating success or failure of load.
*/
template<typename eT>
bool Load(const std::vector<std::string>& files,
arma::Mat<eT>& matrix,
ImageInfo& info,
const bool fatal,
const bool transpose);
@endcode
@code
data::ImageInfo info;
std::vector<std::string>> files{"test_image1.bmp","test_image2.bmp"};
data::load(files, matrix, info, false, true);
@endcode
@section save_api_imagetut Save
Save images expects a matrix of type unsigned char in the form (width * height * channels, NumberOfImages).
Just like load it can be used to save one image or multiple images. Besides image data it also expects the shape of the image as input (width, height, channels).
Saving one image:
@code
/**
* Save the image file from the given matrix.
*
* @param filename Name of the image file.
* @param matrix Matrix to save the image from.
* @param info An object of ImageInfo class.
* @param fatal If an error should be reported as fatal (default false).
* @param transpose If true, flips the image, same as transposing the
* matrix after loading.
* @return Boolean value indicating success or failure of load.
*/
template<typename eT>
bool Save(const std::string& filename,
arma::Mat<eT>& matrix,
ImageInfo& info,
const bool fatal,
const bool transpose);
@endcode
@code
data::ImageInfo info;
info.width = info.height = 25;
info.channels = 3;
info.quality = 90;
data::Save("test_image.bmp", matrix, info, false, true);
@endcode
If the matrix contains more than one image, only the first one is saved.
Saving multiple images:
@code
/**
* Save the image file from the given matrix.
*
* @param files A vector consisting of filenames.
* @param matrix Matrix to save the image from.
* @param info An object of ImageInfo class.
* @param fatal If an error should be reported as fatal (default false).
* @param transpose If true, Flips the image, same as transposing the
* matrix after loading.
* @return Boolean value indicating success or failure of load.
*/
template<typename eT>
bool Save(const std::vector<std::string>& files,
arma::Mat<eT>& matrix,
ImageInfo& info,
const bool fatal,
const bool transpose);
@endcode
@code
data::ImageInfo info;
info.width = info.height = 25;
info.channels = 3;
info.quality = 90;
std::vector<std::string>> files{"test_image1.bmp", "test_image2.bmp"};
data::Save(files, matrix, info, false, true);
@endcode
Multiple images are saved according to the vector of filenames specified.
*/
@@ -0,0 +1,399 @@
/*!
@file rl.txt
@author Sriram S K
@author Joel Joseph
@brief Tutorial for how to use the Reinforcement Learning module in mlpack.
@page rltutorial Reinforcement Learning Tutorial
@section intro_rltut Introduction
Reinforcement Learning is one of the hottest topics right now, with
interest surging after DeepMind published their article on training
deep neural networks to play Atari games to great success. mlpack
implements a complete end-to-end framework for Reinforcement Learning,
featuring multiple environments, policies and methods. Of course,
custom environments and policies can be used and plugged into the
existing framework with no runtime overhead.
mlpack implements typical benchmark environments (Acrobot, Mountain car etc.),
commonly used policies, replay methods and supports asynchronous
learning as well. In addition, it can [communicate](https://github.com/zoq/gym_tcp_api)
with the OpenAI Gym toolkit for more environments.
@section toc_rltut Table of Contents
This tutorial is split into the following sections:
- \ref intro_rltut
- \ref toc_rltut
- \ref environment_rltut
- \ref agent_components_rltut
- \ref q_learning_rltut
- \ref async_learning_rltut
- \ref further_rltut
@section environment_rltut Reinforcement Learning Environments
mlpack implements a number of the most popular environments used for testing
RL agents and algorithms. These include the Cart Pole, Acrobot, Mountain Car
and their variations. Of course, as mentioned above, you can communicate with
OpenAI Gym for other environments, like the Atari video games.
A key component of mlpack is its extensibility. It is a simple process to create
your own custom environments, specific to your needs, and use it with mlpack's
RL framework. All the environments implement a few specific methods and classes
which are used by the agents while learning.
- \c State: The State class is a representation of the environment. For the CartPole,
this would involve storing the position, velocity, angle and angular velocity.
- \c Action: It is an enum naming all the possible actions the agent can take in the
environment. Continuing with the CartPole example, the Action enum would simply
contain the two possible actions, backward and forward.
- \c Sample: This method is perhaps the heart of the environment, providing rewards to
the agent depending on the state and the action taken, and updates the state based on
the action taken as well.
Of course, your custom environment will most likely make use of a number of helper methods, depending
on your application, such as the \c Dsdt method in the \c Acrobot environment, used in the \c RK4
iterative method (also another helper method) to estimate the next state.
@section agent_components_rltut Components of an RL Agent
A Reinforcement Learning agent, in general, takes actions in an environment in order
to maximize a cumulative reward. To that end, it requires a way to choose actions (\b policy)
and a way to sample previous experiences (\b replay).
An example of a simple policy would be an epsilon-greedy policy. Using such a policy, the agent
will choose actions greedily with some probability epsilon. This probability is slowly decreased
over time, balancing the line between exploration and exploitation.
Similarly, an example of a simple replay would be a random replay. At each time step, the
interactions between the agent and the environment are saved to a memory buffer and previous
experiences are sampled from the buffer to train the agent.
Instantiating the components of an agent can be easily done by passing the Environment as
a templated argument and the parameters of the policy/replay to the constructor.
To create a Greedy Policy and Prioritized Replay for the CartPole environment, we would do the
following:
@code
GreedyPolicy<CartPole> policy(1.0, 1000, 0.1);
PrioritizedReplay<CartPole> replayMethod(10, 10000, 0.6);
@endcode
The arguments to `policy` are the initial epsilon values, the interval of decrease in its value
and the value at which epsilon bottoms out and won't be reduced further. The arguments to
`replayMethod` are size of the batch returned, the number of examples stored in memory, and the
degree of prioritization.
In addition to the above components, an RL agent requires many hyperparameters to be tuned during
it's training period. These parameters include everything from the discount rate of the future
reward to whether Double Q-learning should be used or not. The `TrainingConfig` class can be
instantiated and configured as follows:
@code
TrainingConfig config;
config.StepSize() = 0.01;
config.Discount() = 0.9;
config.TargetNetworkSyncInterval() = 100;
config.ExplorationSteps() = 100;
config.DoubleQLearning() = false;
config.StepLimit() = 200;
@endcode
The object `config` describes an RL agent, using a step size of 0.01 for the optimization process,
a discount factor of 0.9, sync interval of 200 episodes. This agent only starts learning after storing
100 exploration steps, has a step limit of 200, and does not utilize double q-learning.
In this way, we can easily configure an RL agent with the desired hyperparameters.
@section q_learning_rltut Q-Learning in mlpack
Here, we demonstrate Q-Learning in mlpack through the use of a simple example, the training of a Q-Learning
agent on the CartPole environment. The code has been broken into chunks for easy understanding.
@code
#include <mlpack/core.hpp>
#include <mlpack/methods/ann/ffn.hpp>
#include <mlpack/methods/ann/init_rules/gaussian_init.hpp>
#include <mlpack/methods/ann/layer/layer.hpp>
#include <mlpack/methods/ann/loss_functions/mean_squared_error.hpp>
#include <mlpack/methods/reinforcement_learning/q_learning.hpp>
#include <mlpack/methods/reinforcement_learning/environment/cart_pole.hpp>
#include <mlpack/methods/reinforcement_learning/policy/greedy_policy.hpp>
#include <mlpack/methods/reinforcement_learning/training_config.hpp>
#include <ensmallen.hpp>
using namespace mlpack;
using namespace mlpack::ann;
using namespace ens;
using namespace mlpack::rl;
@endcode
We include all the necessary components of our toy example and declare namespaces for convenience.
@code
int main()
{
// Set up the network.
FFN<MeanSquaredError<>, GaussianInitialization> model(MeanSquaredError<>(),
GaussianInitialization(0, 0.001));
model.Add<Linear<>>(4, 128);
model.Add<ReLULayer<>>();
model.Add<Linear<>>(128, 128);
model.Add<ReLULayer<>>();
model.Add<Linear<>>(128, 2);
@endcode
The first step in setting our Q-learning agent is to setup the network for it to use. Here,
we use mlpack's ann module to setup a simple FFN network, consisting of a single hidden layer.
@note
The network constructed here has an input shape of 4 and output shape of 2. This corresponds to
the structure of the CartPole environment, where each state is represented as a column vector with
4 data members (position, velocity, angle, angular velocity). Similarly, the output shape is represented
by the number of possible actions, which in this case, is only 2 (foward and backward).
The next step would be to setup the other components of the Q-learning agent, namely its policy, replay
method and hyperparameters.
@code
// Set up the policy and replay method.
GreedyPolicy<CartPole> policy(1.0, 1000, 0.1, 0.99);
RandomReplay<CartPole> replayMethod(10, 10000);
TrainingConfig config;
config.StepSize() = 0.01;
config.Discount() = 0.9;
config.TargetNetworkSyncInterval() = 100;
config.ExplorationSteps() = 100;
config.DoubleQLearning() = false;
config.StepLimit() = 200;
@endcode
And now, we get to the heart of the program, declaring a Q-Learning agent.
@code
QLearning<CartPole, decltype(model), AdamUpdate, decltype(policy)>
agent(std::move(config), std::move(model), std::move(policy),
std::move(replayMethod));
@endcode
Here, we call the `QLearning` constructor, passing in the type of environment,
network, updater, policy and replay. We use `decltype(var)` as a shorthand for
the variable, saving us the trouble of copying the lengthy templated type.
Similarly, `std::move` is called for convenience, moving the components instead of
duplicating them and copying them over.
We have our Q-Learning agent `agent` ready to be trained on the Cart Pole environment.
@code
arma::running_stat<double> averageReturn;
size_t episodes = 0;
bool converged = true;
while (true)
{
double episodeReturn = agent.Episode();
averageReturn(episodeReturn);
episodes += 1;
if (episodes > 1000)
{
std::cout << "Cart Pole with DQN failed." << std::endl;
converged = false;
break;
}
/**
* Reaching running average return 35 is enough to show it works.
*/
std::cout << "Average return: " << averageReturn.mean()
<< " Episode return: " << episodeReturn << std::endl;
if (averageReturn.mean() > 35)
break;
}
if (converged)
std::cout << "Hooray! Q-Learning agent successfully trained" << std::endl;
return 0;
}
@endcode
We set up a loop to train the agent. The exit condition is determined by the average
reward which can be computed with `arma::running_stat`. It is used for storing running
statistics of scalars, which in this case is the reward signal. The agent can be said
to have converged when the average return reaches a predetermined value (i.e. > 35).
Conversely, if the average return does not go beyond that amount even after a thousand
episodes, we can conclude that the agent will not converge and exit the training loop.
@section async_learning_rltut
In 2016, Researchers at Deepmind and University of Montreal published their paper
"Asynchronous Methods for Deep Reinforcement Learning". In it they described asynchronous
variants of four standard reinforcement learning algorithms:
- One-Step SARSA
- One-Step Q-Learning
- N-Step Q-Learning
- Advantage Actor-Critic(A3C)
Online RL algorithms and Deep Neural Networks make an unstable combination because of the
non-stationary and correlated nature of online updates. Although this is solved by Experience Replay,
it has several drawbacks: it uses more memory and computation per real interaction; and it requires
off-policy learning algorithms.
Asynchronous methods, instead of experience replay, asynchronously executes multiple agents
in parallel, on multiple instances of the environment, which solves all the above problems.
Here, we demonstrate Asynchronous Learning methods in mlpack through the training of an async
agent. Asynchronous learning involves training several agents simultaneously. Here, each of the
agents are referred to as "workers". Currently mlpack has One-Step Q-Learning worker, N-Step
Q-Learning worker and One-Step SARSA worker.
Let's examine the sample code in chunks.
Apart from the includes used for the q-learning example, two more have to be included:
@code
#include <mlpack/methods/reinforcement_learning/async_learning.hpp>
#include <mlpack/methods/reinforcement_learning/policy/aggregated_policy.hpp>
@endcode
Here we don't use experience replay, and instead of a single policy, we use three different
policies, each corresponding to its worker. Number of workers created, depends on the number of
policies given in the Aggregated Policy. The column vector contains the probability distribution
for each child policy. We should make sure its size is same as the number of policies and the sum
of its elements is equal to 1.
@code
AggregatedPolicy<GreedyPolicy<CartPole>> policy({GreedyPolicy<CartPole>(0.7, 5000, 0.1),
GreedyPolicy<CartPole>(0.7, 5000, 0.01),
GreedyPolicy<CartPole>(0.7, 5000, 0.5)},
arma::colvec("0.4 0.3 0.3"));
@endcode
Now, we will create the "OneStepQLearning" agent. We could have used "NStepQLearning" or "OneStepSarsa"
here according to our requirement.
@code
OneStepQLearning<CartPole, decltype(model), ens::AdamUpdate, decltype(policy)>
agent(std::move(config), std::move(model), std::move(policy));
@endcode
Here, unlike the Q-Learning example, instead of the entire while loop, we use the Train method of the Asynchronous
Learning class inside a for loop. 100 training episodes will take around 50 seconds.
@code
for (int i = 0; i < 100; i++)
{
agent.Train(measure);
}
@endcode
What is "measure" here? It is a lambda function which returns a boolean value (indicating the end of training)
and accepts the episode return (total reward of a deterministic test episode) as parameter.
So, let's create that.
@code
arma::vec returns(20, arma::fill::zeros);
size_t position = 0;
size_t episode = 0;
auto measure = [&returns, &position, &episode](double episodeReturn)
{
if(episode > 10000) return true;
returns[position++] = episodeReturn;
position = position % returns.n_elem;
episode++;
std::cout << "Episode No.: " << episode
<< "; Episode Return: " << episodeReturn
<< "; Average Return: " << arma::mean(returns) << endl;
};
@endcode
This will train three different agents on three CPU threads asynchronously and use this data to update the
action value estimate.
Voila, thats all there is to it.
Here is the full code to try this right away:
@code
#include <mlpack/core.hpp>
#include <mlpack/methods/ann/ffn.hpp>
#include <mlpack/methods/ann/init_rules/gaussian_init.hpp>
#include <mlpack/methods/ann/layer/layer.hpp>
#include <mlpack/methods/ann/loss_functions/mean_squared_error.hpp>
#include <mlpack/methods/reinforcement_learning/async_learning.hpp>
#include <mlpack/methods/reinforcement_learning/environment/cart_pole.hpp>
#include <mlpack/methods/reinforcement_learning/policy/greedy_policy.hpp>
#include <mlpack/methods/reinforcement_learning/policy/aggregated_policy.hpp>
#include <mlpack/methods/reinforcement_learning/training_config.hpp>
#include <ensmallen.hpp>
using namespace mlpack;
using namespace mlpack::ann;
using namespace mlpack::rl;
int main()
{
// Set up the network.
FFN<MeanSquaredError<>, GaussianInitialization> model(MeanSquaredError<>(), GaussianInitialization(0, 0.001));
model.Add<Linear<>>(4, 128);
model.Add<ReLULayer<>>();
model.Add<Linear<>>(128, 128);
model.Add<ReLULayer<>>();
model.Add<Linear<>>(128, 2);
AggregatedPolicy<GreedyPolicy<CartPole>> policy({GreedyPolicy<CartPole>(0.7, 5000, 0.1),
GreedyPolicy<CartPole>(0.7, 5000, 0.01),
GreedyPolicy<CartPole>(0.7, 5000, 0.5)},
arma::colvec("0.4 0.3 0.3"));
TrainingConfig config;
config.StepSize() = 0.01;
config.Discount() = 0.9;
config.TargetNetworkSyncInterval() = 100;
config.ExplorationSteps() = 100;
config.DoubleQLearning() = false;
config.StepLimit() = 200;
OneStepQLearning<CartPole, decltype(model), ens::VanillaUpdate, decltype(policy)>
agent(std::move(config), std::move(model), std::move(policy));
arma::vec returns(20, arma::fill::zeros);
size_t position = 0;
size_t episode = 0;
auto measure = [&returns, &position, &episode](double episodeReturn)
{
if(episode > 10000) return true;
returns[position++] = episodeReturn;
position = position % returns.n_elem;
episode++;
std::cout << "Episode No.: " << episode
<< "; Episode Return: " << episodeReturn
<< "; Average Return: " << arma::mean(returns) << endl;
};
for (int i = 0; i < 100; i++)
{
agent.Train(measure);
}
}
@endcode
@section further_rltut Further documentation
For further documentation on the rl classes, consult the \ref mlpack::rl
"complete API documentation".
*/
+12 -12
View File
@@ -18,10 +18,6 @@ if (BUILD_JULIA_BINDINGS)
add_custom_command(TARGET julia PRE_BUILD
COMMAND ${CMAKE_COMMAND} -E make_directory
${CMAKE_BINARY_DIR}/src/mlpack/bindings/julia/mlpack/src/)
add_custom_command(TARGET julia PRE_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
${CMAKE_CURRENT_SOURCE_DIR}/mlpack/REQUIRE
${CMAKE_BINARY_DIR}/src/mlpack/bindings/julia/mlpack/REQUIRE)
add_library(mlpack_julia_util
julia_util.h
@@ -52,12 +48,16 @@ if (BUILD_JULIA_BINDINGS)
configure_file(${CMAKE_SOURCE_DIR}/src/mlpack/bindings/julia/mlpack/cli.jl.in
${CMAKE_BINARY_DIR}/src/mlpack/bindings/julia/mlpack/src/cli.jl)
# Create the empty mlpack.jl file that we will fill with includes.
file(WRITE
"${CMAKE_BINARY_DIR}/src/mlpack/bindings/julia/mlpack/src/mlpack.jl"
"module mlpack\n\n"
"module util\n\n"
"include(\"cli.jl\")\n")
# Create the empty mlpack.jl file that we will fill with includes using the
# exsiting template. Unfortunately COPY doesn't let us change the extension
# so we need a follow-up RENAME command.
file(COPY
"${CMAKE_CURRENT_SOURCE_DIR}/mlpack/mlpack.jl.in"
DESTINATION
"${CMAKE_BINARY_DIR}/src/mlpack/bindings/julia/mlpack/src/")
file(RENAME
"${CMAKE_BINARY_DIR}/src/mlpack/bindings/julia/mlpack/src/mlpack.jl.in"
"${CMAKE_BINARY_DIR}/src/mlpack/bindings/julia/mlpack/src/mlpack.jl")
file(WRITE
"${CMAKE_BINARY_DIR}/src/mlpack/bindings/julia/mlpack/src/functions.jl"
@@ -150,10 +150,10 @@ if (BUILD_JULIA_BINDINGS)
# Append the code to define the function in the module.
file(APPEND
"${CMAKE_BINARY_DIR}/src/mlpack/bindings/julia/mlpack/src/functions.jl"
"${name} = util.${name}\n")
"${name} = _Internal.${name}\n")
endif ()
endmacro ()
if (BUILD_TESTS)
if (BUILD_TESTS AND BUILD_JULIA_BINDINGS)
add_subdirectory(tests)
endif ()
@@ -116,11 +116,11 @@ std::string DefaultParamImpl(
else if (std::is_same<T, arma::Col<size_t>>::value ||
std::is_same<T, arma::Row<size_t>>::value)
{
return "Int64[]";
return "Int[]";
}
else if (std::is_same<T, arma::Mat<size_t>>::value)
{
return "zeros(Int64, 0, 0)";
return "zeros(Int, 0, 0)";
}
else
{
+2 -2
View File
@@ -101,9 +101,9 @@ inline std::string GetJuliaType(
const typename std::enable_if<arma::is_arma_type<T>::value>::type* = 0)
{
// size_t matrices are special: we want to represent them in Julia as
// Array{Int64, X} not UInt64 because Julia displays UInt64s strangely.
// Array{Int, X} not UInt because Julia displays UInts strangely.
if (std::is_same<typename T::elem_type, size_t>::value)
return std::string("Array{Int64, ") + (T::is_col || T::is_row ? "1" : "2")
return std::string("Array{Int, ") + (T::is_col || T::is_row ? "1" : "2")
+ "}";
else
return "Array{" + GetJuliaType<typename T::elem_type>() + ", "
@@ -47,7 +47,7 @@ std::string GetPrintableType(
const typename std::enable_if<util::IsStdVector<T>::value>::type*)
{
if (std::is_same<T, std::vector<int>>::value)
return "Array{Int64, 1}";
return "Array{Int, 1}";
else if (std::is_same<T, std::vector<std::string>>::value)
return "Array{String, 1}";
else
@@ -65,15 +65,15 @@ std::string GetPrintableType(
if (std::is_same<T, arma::mat>::value)
return "Float64 matrix-like";
else if (std::is_same<T, arma::Mat<size_t>>::value)
return "Int64 matrix-like";
return "Int matrix-like";
else if (std::is_same<T, arma::rowvec>::value)
return "Float64 vector-like";
else if (std::is_same<T, arma::Row<size_t>>::value)
return "Int64 vector-like";
return "Int vector-like";
else if (std::is_same<T, arma::vec>::value)
return "Float64 vector-like";
else if (std::is_same<T, arma::Col<size_t>>::value)
return "Int64 vector-like";
return "Int vector-like";
else
throw std::invalid_argument("unknown Armadillo type " + data.cppType);
}
+28 -20
View File
@@ -7,6 +7,7 @@
#include <mlpack/bindings/julia/julia_util.h>
#include <mlpack/prereqs.hpp>
#include <mlpack/core/util/cli.hpp>
#include <stdint.h>
using namespace mlpack;
@@ -82,13 +83,14 @@ void CLI_SetParamVectorStrStr(const char* paramName,
* Call CLI::SetParam<std::vector<int>>().
*/
void CLI_SetParamVectorInt(const char* paramName,
uint64_t* ints,
int* ints,
const size_t length)
{
// Create a std::vector<int> object; unfortunately this requires copying the
// vector elements.
std::vector<int> vec(length);
for (size_t i = 0; i < (size_t) length; ++i)
std::vector<int> vec;
vec.resize(length);
for (size_t i = 0; i < length; ++i)
vec[i] = ints[i];
CLI::GetParam<std::vector<int>>(paramName) = std::move(vec);
@@ -105,7 +107,7 @@ void CLI_SetParamMat(const char* paramName,
const bool pointsAsRows)
{
// Create the matrix as an alias.
arma::mat m(memptr, rows, cols, false, true);
arma::mat m(memptr, arma::uword(rows), arma::uword(cols), false, true);
CLI::GetParam<arma::mat>(paramName) = pointsAsRows ? m.t() : std::move(m);
CLI::SetPassed(paramName);
}
@@ -120,7 +122,8 @@ void CLI_SetParamUMat(const char* paramName,
const bool pointsAsRows)
{
// Create the matrix as an alias.
arma::Mat<size_t> m(memptr, rows, cols, false, true);
arma::Mat<size_t> m(memptr, arma::uword(rows), arma::uword(cols), false,
true);
CLI::GetParam<arma::Mat<size_t>>(paramName) = pointsAsRows ? m.t() :
std::move(m);
CLI::SetPassed(paramName);
@@ -133,7 +136,7 @@ void CLI_SetParamRow(const char* paramName,
double* memptr,
const size_t cols)
{
arma::rowvec m(memptr, cols, false, true);
arma::rowvec m(memptr, arma::uword(cols), false, true);
CLI::GetParam<arma::rowvec>(paramName) = std::move(m);
CLI::SetPassed(paramName);
}
@@ -145,7 +148,7 @@ void CLI_SetParamURow(const char* paramName,
size_t* memptr,
const size_t cols)
{
arma::Row<size_t> m(memptr, cols, false, true);
arma::Row<size_t> m(memptr, arma::uword(cols), false, true);
CLI::GetParam<arma::Row<size_t>>(paramName) = std::move(m);
CLI::SetPassed(paramName);
}
@@ -157,7 +160,7 @@ void CLI_SetParamCol(const char* paramName,
double* memptr,
const size_t rows)
{
arma::vec m(memptr, rows, false, true);
arma::vec m(memptr, arma::uword(rows), false, true);
CLI::GetParam<arma::vec>(paramName) = std::move(m);
CLI::SetPassed(paramName);
}
@@ -166,10 +169,10 @@ void CLI_SetParamCol(const char* paramName,
* Call CLI::SetParam<arma::Row<size_t>>().
*/
void CLI_SetParamUCol(const char* paramName,
size_t* memptr,
const size_t rows)
size_t* memptr,
const size_t rows)
{
arma::Col<size_t> m(memptr, rows, false, true);
arma::Col<size_t> m(memptr, arma::uword(rows), false, true);
CLI::GetParam<arma::Col<size_t>>(paramName) = std::move(m);
CLI::SetPassed(paramName);
}
@@ -191,7 +194,7 @@ void CLI_SetParamMatWithInfo(const char* paramName,
data::Datatype::numeric;
}
arma::mat m(memptr, rows, cols, false, true);
arma::mat m(memptr, arma::uword(rows), arma::uword(cols), false, true);
std::get<0>(CLI::GetParam<std::tuple<data::DatasetInfo, arma::mat>>(
paramName)) = std::move(d);
std::get<1>(CLI::GetParam<std::tuple<data::DatasetInfo, arma::mat>>(
@@ -243,7 +246,7 @@ size_t CLI_GetParamVectorStrLen(const char* paramName)
/**
* Call CLI::GetParam<std::vector<std::string>>() and get the i'th string.
*/
const char* CLI_GetParamVectorStrStr(const char* paramName, const int i)
const char* CLI_GetParamVectorStrStr(const char* paramName, const size_t i)
{
return CLI::GetParam<std::vector<std::string>>(paramName)[i].c_str();
}
@@ -261,10 +264,10 @@ size_t CLI_GetParamVectorIntLen(const char* paramName)
* The vector will be created in-place and it is expected that the calling
* function will take ownership.
*/
uint64_t* CLI_GetParamVectorIntPtr(const char* paramName)
int* CLI_GetParamVectorIntPtr(const char* paramName)
{
const size_t size = CLI::GetParam<std::vector<int>>(paramName).size();
uint64_t* ints = new uint64_t[size];
int* ints = new int[size];
for (size_t i = 0; i < size; ++i)
ints[i] = CLI::GetParam<std::vector<int>>(paramName)[i];
@@ -335,15 +338,17 @@ size_t CLI_GetParamUMatCols(const char* paramName)
*/
size_t* CLI_GetParamUMat(const char* paramName)
{
arma::Mat<size_t>& mat = CLI::GetParam<arma::Mat<size_t>>(paramName);
// Are we using preallocated memory? If so we have to handle this more
// carefully.
arma::Mat<size_t>& mat = CLI::GetParam<arma::Mat<size_t>>(paramName);
if (mat.n_elem <= arma::arma_config::mat_prealloc)
{
// Copy the memory to something that we can give back to Julia.
size_t* newMem = new size_t[mat.n_elem];
arma::arrayops::copy(newMem, mat.mem, mat.n_elem);
return newMem; // We believe Julia will free it. Hopefully we are right.
// We believe Julia will free it. Hopefully we are right.
return newMem;
}
else
{
@@ -399,15 +404,17 @@ size_t CLI_GetParamUColRows(const char* paramName)
*/
size_t* CLI_GetParamUCol(const char* paramName)
{
arma::Col<size_t>& vec = CLI::GetParam<arma::Col<size_t>>(paramName);
// Are we using preallocated memory? If so we have to handle this more
// carefully.
arma::Col<size_t>& vec = CLI::GetParam<arma::Col<size_t>>(paramName);
if (vec.n_elem <= arma::arma_config::mat_prealloc)
{
// Copy the memory to something we can give back to Julia.
size_t* newMem = new size_t[vec.n_elem];
arma::arrayops::copy(newMem, vec.mem, vec.n_elem);
return newMem; // We believe Julia will free it. Hopefully we are right.
// We believe Julia will free it. Hopefully we are right.
return newMem;
}
else
{
@@ -463,9 +470,10 @@ size_t CLI_GetParamURowCols(const char* paramName)
*/
size_t* CLI_GetParamURow(const char* paramName)
{
arma::Row<size_t>& vec = CLI::GetParam<arma::Row<size_t>>(paramName);
// Are we using preallocated memory? If so we have to handle this more
// carefully.
arma::Row<size_t>& vec = CLI::GetParam<arma::Row<size_t>>(paramName);
if (vec.n_elem <= arma::arma_config::mat_prealloc)
{
// Copy the memory to something we can give back to Julia.
+3 -3
View File
@@ -61,7 +61,7 @@ void CLI_SetParamVectorStrStr(const char* paramName,
* Call CLI::SetParam<std::vector<int>>().
*/
void CLI_SetParamVectorInt(const char* paramName,
uint64_t* ints,
int* ints,
const size_t length);
/**
@@ -149,7 +149,7 @@ size_t CLI_GetParamVectorStrLen(const char* paramName);
/**
* Call CLI::GetParam<std::vector<std::string>>() and get the i'th string.
*/
const char* CLI_GetParamVectorStrStr(const char* paramName, const int i);
const char* CLI_GetParamVectorStrStr(const char* paramName, const size_t i);
/**
* Call CLI::GetParam<std::vector<int>>() and get the length of the vector.
@@ -161,7 +161,7 @@ size_t CLI_GetParamVectorIntLen(const char* paramName);
* The vector will be created in-place and it is expected that the calling
* function will take ownership.
*/
uint64_t* CLI_GetParamVectorIntPtr(const char* paramName);
int* CLI_GetParamVectorIntPtr(const char* paramName);
/**
* Get the number of rows in a matrix parameter.
-1
View File
@@ -1 +0,0 @@
julia 0.7.0
+65 -63
View File
@@ -66,8 +66,8 @@ function CLIRestoreSettings(programName::String)
end
function CLISetParam(paramName::String, paramValue::Int)
ccall((:CLI_SetParamInt, library), Nothing, (Cstring, Int), paramName,
paramValue);
ccall((:CLI_SetParamInt, library), Nothing, (Cstring, Cint), paramName,
Cint(paramValue));
end
function CLISetParam(paramName::String, paramValue::Float64)
@@ -89,15 +89,15 @@ function CLISetParamMat(paramName::String,
paramValue,
pointsAsRows::Bool)
paramMat = to_matrix(paramValue, Float64)
ccall((:CLI_SetParamMat, library), Nothing, (Cstring, Ptr{Float64}, UInt64,
UInt64, Bool), paramName, Base.pointer(paramMat), size(paramMat, 1),
ccall((:CLI_SetParamMat, library), Nothing, (Cstring, Ptr{Float64}, Csize_t,
Csize_t, Bool), paramName, Base.pointer(paramMat), size(paramMat, 1),
size(paramMat, 2), pointsAsRows);
end
function CLISetParamUMat(paramName::String,
paramValue,
pointsAsRows::Bool)
paramMat = to_matrix(paramValue, Int64)
paramMat = to_matrix(paramValue, Int)
# Sanity check.
if minimum(paramMat) <= 0
@@ -105,9 +105,9 @@ function CLISetParamUMat(paramName::String,
"Must be 1 or greater."))
end
m = convert(Array{UInt64, 2}, paramMat .- 1)
ccall((:CLI_SetParamUMat, library), Nothing, (Cstring, Ptr{UInt64}, UInt64,
UInt64, Bool), paramName, Base.pointer(m), size(paramValue, 1),
m = convert(Array{Csize_t, 2}, paramMat .- 1)
ccall((:CLI_SetParamUMat, library), Nothing, (Cstring, Ptr{Csize_t}, Csize_t,
Csize_t, Bool), paramName, Base.pointer(m), size(paramValue, 1),
size(paramValue, 2), pointsAsRows);
end
@@ -117,25 +117,26 @@ function CLISetParam(paramName::String,
# sequentially. I am not sure if this is fully necessary but I have some
# reservations about Julia's support for passing arrays of strings correctly
# as a const char**.
ccall((:CLI_SetParamVectorStrLen, library), Nothing, (Cstring, UInt64),
ccall((:CLI_SetParamVectorStrLen, library), Nothing, (Cstring, Csize_t),
paramName, size(vector, 1));
for i in 1:size(vector, 1)
ccall((:CLI_SetParamVectorStrStr, library), Nothing, (Cstring, Cstring,
UInt64), paramName, vector[i], i .- 1);
Csize_t), paramName, vector[i], i .- 1);
end
end
function CLISetParam(paramName::String,
vector::Vector{Int64})
ccall((:CLI_SetParamVectorInt, library), Nothing, (Cstring, Ptr{Int64},
Int64), paramName, Base.pointer(vector), size(vector, 1));
vector::Vector{Int})
cint_vec = convert(Vector{Cint}, vector)
ccall((:CLI_SetParamVectorInt, library), Nothing, (Cstring, Ptr{Cint},
Csize_t), paramName, Base.pointer(cint_vec), size(cint_vec, 1));
end
function CLISetParam(paramName::String,
matWithInfo::Tuple{Array{Bool, 1}, Array{Float64, 2}},
pointsAsRows::Bool)
ccall((:CLI_SetParamMatWithInfo, library), Nothing, (Cstring, Ptr{Bool},
Ptr{Float64}, Int64, Int64, Bool), paramName,
Ptr{Float64}, Int, Int, Bool), paramName,
Base.pointer(matWithInfo[1]), Base.pointer(matWithInfo[2]),
size(matWithInfo[2], 1), size(matWithInfo[2], 2), pointsAsRows);
end
@@ -143,44 +144,44 @@ end
function CLISetParamRow(paramName::String,
paramValue)
paramVec = to_vector(paramValue, Float64)
ccall((:CLI_SetParamRow, library), Nothing, (Cstring, Ptr{Float64}, UInt64),
ccall((:CLI_SetParamRow, library), Nothing, (Cstring, Ptr{Float64}, Csize_t),
paramName, Base.pointer(paramVec), size(paramVec, 1));
end
function CLISetParamCol(paramName::String,
paramValue)
paramVec = to_vector(paramValue, Float64)
ccall((:CLI_SetParamCol, library), Nothing, (Cstring, Ptr{Float64}, UInt64),
ccall((:CLI_SetParamCol, library), Nothing, (Cstring, Ptr{Float64}, Csize_t),
paramName, Base.pointer(paramVec), size(paramVec, 1));
end
function CLISetParamURow(paramName::String,
paramValue)
paramVec = to_vector(paramValue, Int64)
paramVec = to_vector(paramValue, Int)
# Sanity check.
if minimum(paramVec) <= 0
throw(DomainError("Input $(paramName) cannot have 0 or negative values! " *
"Must be 1 or greater."))
end
m = convert(Array{UInt64, 1}, paramVec .- 1)
m = convert(Array{Csize_t, 1}, paramVec .- 1)
ccall((:CLI_SetParamURow, library), Nothing, (Cstring, Ptr{UInt64}, UInt64),
ccall((:CLI_SetParamURow, library), Nothing, (Cstring, Ptr{Csize_t}, Csize_t),
paramName, Base.pointer(m), size(paramValue, 1));
end
function CLISetParamUCol(paramName::String,
paramValue)
paramVec = to_vector(paramValue, Int64)
paramVec = to_vector(paramValue, Int)
# Sanity check.
if minimum(paramVec) <= 0
throw(DomainError("Input $(paramName) cannot have 0 or negative values! " *
"Must be 1 or greater."))
end
m = convert(Array{UInt64, 1}, paramValue .- 1)
m = convert(Array{Csize_t, 1}, paramValue .- 1)
ccall((:CLI_SetParamUCol, library), Nothing, (Cstring, Ptr{UInt64}, UInt64),
ccall((:CLI_SetParamUCol, library), Nothing, (Cstring, Ptr{Csize_t}, Csize_t),
paramName, Base.pointer(m), size(paramValue, 1));
end
@@ -189,7 +190,7 @@ function CLIGetParamBool(paramName::String)
end
function CLIGetParamInt(paramName::String)
return ccall((:CLI_GetParamInt, library), Int64, (Cstring,), paramName)
return Int(ccall((:CLI_GetParamInt, library), Cint, (Cstring,), paramName))
end
function CLIGetParamDouble(paramName::String)
@@ -201,15 +202,15 @@ function CLIGetParamString(paramName::String)
end
function CLIGetParamVectorStr(paramName::String)
local size::UInt64
local size::Csize_t
local ptr::Ptr{String}
# Get the size of the vector, then each element.
size = ccall((:CLI_GetParamVectorStrLen, library), UInt64, (Cstring,),
size = ccall((:CLI_GetParamVectorStrLen, library), Csize_t, (Cstring,),
paramName);
out = Array{String, 1}()
for i = 1:size
s = ccall((:CLI_GetParamVectorStrStr, library), Cstring, (Cstring, UInt64),
s = ccall((:CLI_GetParamVectorStrStr, library), Cstring, (Cstring, Csize_t),
paramName, i .- 1)
push!(out, Base.unsafe_string(s))
end
@@ -218,28 +219,29 @@ function CLIGetParamVectorStr(paramName::String)
end
function CLIGetParamVectorInt(paramName::String)
local size::UInt64
local ptr::Ptr{Int64}
local size::Csize_t
local ptr::Ptr{Cint}
# Get the size of the vector, then the pointer to it. We will own the
# pointer.
size = ccall((:CLI_GetParamVectorIntLen, library), UInt64, (Cstring,),
size = ccall((:CLI_GetParamVectorIntLen, library), Csize_t, (Cstring,),
paramName);
ptr = ccall((:CLI_GetParamVectorIntPtr, library), Ptr{Int64}, (Cstring,),
ptr = ccall((:CLI_GetParamVectorIntPtr, library), Ptr{Cint}, (Cstring,),
paramName);
return Base.unsafe_wrap(Array{Int64, 1}, ptr, (size), own=true)
return convert(Array{Int, 1}, Base.unsafe_wrap(Array{Cint, 1}, ptr, (size),
own=true))
end
function CLIGetParamMat(paramName::String, pointsAsRows::Bool)
# Can we return different return types? For now let's restrict to a matrix to
# make it easy...
local ptr::Ptr{Float64}
local rows::UInt64, cols::UInt64;
local rows::Csize_t, cols::Csize_t;
# I suppose it would be possible to do this all in one call, but this seems
# easy enough.
rows = ccall((:CLI_GetParamMatRows, library), UInt64, (Cstring,), paramName);
cols = ccall((:CLI_GetParamMatCols, library), UInt64, (Cstring,), paramName);
rows = ccall((:CLI_GetParamMatRows, library), Csize_t, (Cstring,), paramName);
cols = ccall((:CLI_GetParamMatCols, library), Csize_t, (Cstring,), paramName);
ptr = ccall((:CLI_GetParamMat, library), Ptr{Float64}, (Cstring,), paramName);
if pointsAsRows
@@ -255,30 +257,30 @@ end
function CLIGetParamUMat(paramName::String, pointsAsRows::Bool)
# Can we return different return types? For now let's restrict to a matrix to
# make it easy...
local ptr::Ptr{UInt64}
local rows::UInt64, cols::UInt64;
local ptr::Ptr{Csize_t}
local rows::Csize_t, cols::Csize_t;
# I suppose it would be possible to do this all in one call, but this seems
# easy enough.
rows = ccall((:CLI_GetParamUMatRows, library), UInt64, (Cstring,), paramName);
cols = ccall((:CLI_GetParamUMatCols, library), UInt64, (Cstring,), paramName);
ptr = ccall((:CLI_GetParamUMat, library), Ptr{UInt64}, (Cstring,), paramName);
rows = ccall((:CLI_GetParamUMatRows, library), Csize_t, (Cstring,), paramName);
cols = ccall((:CLI_GetParamUMatCols, library), Csize_t, (Cstring,), paramName);
ptr = ccall((:CLI_GetParamUMat, library), Ptr{Csize_t}, (Cstring,), paramName);
if pointsAsRows
# In this case we have to transpose, unfortunately.
m = Base.unsafe_wrap(Array{UInt64, 2}, ptr, (rows, cols), own=true);
return convert(Array{Int64, 2}, m' .+ 1) # Add 1 because these are indexes.
m = Base.unsafe_wrap(Array{Csize_t, 2}, ptr, (rows, cols), own=true);
return convert(Array{Int, 2}, m' .+ 1) # Add 1 because these are indexes.
else
# Here no transpose is necessary.
m = Base.unsafe_wrap(Array{UInt64, 2}, ptr, (rows, cols), own=true);
return convert(Array{Int64, 2}, m .+ 1)
m = Base.unsafe_wrap(Array{Csize_t, 2}, ptr, (rows, cols), own=true);
return convert(Array{Int, 2}, m .+ 1)
end
end
function CLIGetParamCol(paramName::String)
local ptr::Ptr{Float64};
local rows::UInt64;
local rows::Csize_t;
rows = ccall((:CLI_GetParamColRows, library), UInt64, (Cstring,), paramName);
rows = ccall((:CLI_GetParamColRows, library), Csize_t, (Cstring,), paramName);
ptr = ccall((:CLI_GetParamCol, library), Ptr{Float64}, (Cstring,), paramName);
return Base.unsafe_wrap(Array{Float64, 1}, ptr, rows, own=true);
@@ -286,45 +288,45 @@ end
function CLIGetParamRow(paramName::String)
local ptr::Ptr{Float64};
local cols::UInt64;
local cols::Csize_t;
cols = ccall((:CLI_GetParamRowCols, library), UInt64, (Cstring,), paramName);
cols = ccall((:CLI_GetParamRowCols, library), Csize_t, (Cstring,), paramName);
ptr = ccall((:CLI_GetParamRow, library), Ptr{Float64}, (Cstring,), paramName);
return Base.unsafe_wrap(Array{Float64, 1}, ptr, cols, own=true);
end
function CLIGetParamUCol(paramName::String)
local ptr::Ptr{UInt64};
local rows::UInt64;
local ptr::Ptr{Csize_t};
local rows::Csize_t;
rows = ccall((:CLI_GetParamUColRows, library), UInt64, (Cstring,), paramName);
ptr = ccall((:CLI_GetParamUCol, library), Ptr{UInt64}, (Cstring,), paramName);
rows = ccall((:CLI_GetParamUColRows, library), Csize_t, (Cstring,), paramName);
ptr = ccall((:CLI_GetParamUCol, library), Ptr{Csize_t}, (Cstring,), paramName);
m = Base.unsafe_wrap(Array{UInt64, 1}, ptr, rows, own=true);
return convert(Array{Int64, 1}, m .+ 1)
m = Base.unsafe_wrap(Array{Csize_t, 1}, ptr, rows, own=true);
return convert(Array{Int, 1}, m .+ 1)
end
function CLIGetParamURow(paramName::String)
local ptr::Ptr{UInt64};
local cols::UInt64;
local ptr::Ptr{Csize_t};
local cols::Csize_t;
cols = ccall((:CLI_GetParamURowCols, library), UInt64, (Cstring,), paramName);
ptr = ccall((:CLI_GetParamURow, library), Ptr{UInt64}, (Cstring,), paramName);
cols = ccall((:CLI_GetParamURowCols, library), Csize_t, (Cstring,), paramName);
ptr = ccall((:CLI_GetParamURow, library), Ptr{Csize_t}, (Cstring,), paramName);
m = Base.unsafe_wrap(Array{UInt64, 1}, ptr, cols, own=true);
return convert(Array{Int64, 1}, m .+ 1)
m = Base.unsafe_wrap(Array{Csize_t, 1}, ptr, cols, own=true);
return convert(Array{Int, 1}, m .+ 1)
end
function CLIGetParamMatWithInfo(paramName::String, pointsAsRows::Bool)
local ptrBool::Ptr{Bool};
local ptrData::Ptr{Float64};
local rows::UInt64;
local cols::UInt64;
local rows::Csize_t;
local cols::Csize_t;
rows = ccall((:CLI_GetParamMatWithInfoRows, library), UInt64, (Cstring,),
rows = ccall((:CLI_GetParamMatWithInfoRows, library), Csize_t, (Cstring,),
paramName);
cols = ccall((:CLI_GetParamMatWithInfoCols, library), UInt64, (Cstring,),
cols = ccall((:CLI_GetParamMatWithInfoCols, library), Csize_t, (Cstring,),
paramName);
ptrBool = ccall((:CLI_GetParamMatWithInfoBoolPtr, library), Ptr{Bool},
(Cstring,), paramName);
@@ -0,0 +1,30 @@
"""
mlpack
mlpack is a fast, flexible machine learning library, written in C++, that aims
to provide fast, extensible implementations of cutting-edge machine learning
algorithms. This module provides those implementations as Julia functions.
Each function inside the module performs a specific machine learning task.
For complete documentation of these functions, including example usage, see the
mlpack website's documentation for the Julia bindings:
https://www.mlpack.org/doc/stable/julia_documentation.html
Each function also contains an equivalent docstring; the Julia REPL's help
functionality can be used to access the documentation that way.
"""
module mlpack
"""
mlpack._Internal
This module contains internal implementations details of mlpack. There
shouldn't be any need to go digging around in here if you're just using mlpack.
(But don't let this comment discourage you if you're just curious and poking
around!)
"""
module _Internal
include("cli.jl")
@@ -124,7 +124,7 @@ inline std::string CreateInputArguments(const std::string& paramName,
d.cppType == "arma::Col<size_t>")
{
oss << "julia> " << value << " = CSV.read(\"" << value
<< ".csv\"; type=Int64)" << std::endl;
<< ".csv\"; type=Int)" << std::endl;
}
}
@@ -375,6 +375,9 @@ inline std::string ProgramCall(const std::string& programName, Args... args)
{
std::ostringstream oss;
// The code should appear in a Markdown code block.
oss << "```julia" << std::endl;
// Print any input argument definitions. The only input argument definitions
// will be the definitions of matrices, which use the CSV.jl package, so we
// should also include a `using CSV` in there too.
@@ -401,6 +404,9 @@ inline std::string ProgramCall(const std::string& programName, Args... args)
// Since `julia> ` is 8 characters, let's indent 12 otherwise it looks weird.
oss << util::HyphenateString(ossCall.str(), 12);
// Close the Markdown code block.
oss << std::endl << "```";
return oss.str();
}
+1 -1
View File
@@ -62,7 +62,7 @@ void PrintJL(const util::ProgramDoc& programInfo,
cout << endl;
// We need to include utility functions.
cout << "using mlpack.util.cli" << endl;
cout << "using mlpack._Internal.cli" << endl;
cout << endl;
// Make sure the libraries we need are accessible.
@@ -109,15 +109,15 @@ std::string PrintTypeDoc(
if (T::is_col || T::is_row)
{
return "A 1-d vector-like containing `Int` data (elements should be "
"greater than or equal to 0). Could be an `Array{Int64, 1}`, an "
"`Array{Int64, 2}` with one dimension of size 1, or anything "
"convertible to `Array{Int64, 1}`.";
"greater than or equal to 0). Could be an `Array{Int, 1}`, an "
"`Array{Int, 2}` with one dimension of size 1, or anything "
"convertible to `Array{Int, 1}`.";
}
else
{
return "A 2-d matrix-like containing `Int` data (elements should be "
"greater than or equal to 0). Could be an `Array{Int64, 2}` or a "
"`DataFrame` or anything convertible to an `Array{Int64, 2}`. It is "
"greater than or equal to 0). Could be an `Array{Int, 2}` or a "
"`DataFrame` or anything convertible to an `Array{Int, 2}`. It is "
"expected that each row of the matrix corresponds to a data point, "
"unless `points_are_rows` is set to `false` when calling mlpack "
"bindings.";
+8 -8
View File
@@ -129,7 +129,7 @@ end
# Same as TestMatrix but with an unsigned matrix.
@testset "TestUMatrix" begin
# Generate a random matrix of integers.
x = convert(Array{Int64, 2}, rand(1:500, (100, 5)))
x = convert(Array{Int, 2}, rand(1:500, (100, 5)))
_, _, _, _, _, _, _, _, _, _, _, umatOut, _, _ =
test_julia_binding(4.0, 12, "hello",
@@ -138,7 +138,7 @@ end
@test size(umatOut, 1) == 100
@test size(umatOut, 2) == 4
@test typeof(umatOut[1, 1]) == Int64
@test typeof(umatOut[1, 1]) == Int
for i in [0, 1, 3]
for j in 1:100
@test umatOut[j, i + 1] == x[j, i + 1]
@@ -155,7 +155,7 @@ end
# Same as TestMatrix but with an unsigned column major matrix.
@testset "TestUMatrixColMajor" begin
# Generate a random matrix of integers.
x = convert(Array{Int64, 2}, rand(1:500, (5, 100)))
x = convert(Array{Int, 2}, rand(1:500, (5, 100)))
_, _, _, _, _, _, _, _, _, _, _, umatOut, _, _ =
test_julia_binding(4.0, 12, "hello",
@@ -164,7 +164,7 @@ end
@test size(umatOut, 1) == 4
@test size(umatOut, 2) == 100
@test typeof(umatOut[1, 1]) == Int64
@test typeof(umatOut[1, 1]) == Int
for i in 1:100
for j in [0, 1, 3]
@test umatOut[j + 1, i] == x[j + 1, i]
@@ -196,14 +196,14 @@ end
# Test an unsigned column vector input parameter.
@testset "TestUCol" begin
x = convert(Array{Int64, 1}, rand(1:500, 100))
x = convert(Array{Int, 1}, rand(1:500, 100))
_, _, _, _, _, _, _, _, _, _, ucolOut, _, _, _ =
test_julia_binding(4.0, 12, "hello",
ucol_in=x)
@test size(ucolOut, 1) == 100
@test typeof(ucolOut) == Array{Int64, 1}
@test typeof(ucolOut) == Array{Int, 1}
for i in 1:100
# Since we subtract one when we convert to C++, and then add one when we
# convert back, we get a slightly different result here.
@@ -228,14 +228,14 @@ end
# Test an unsigned row vector input parameter.
@testset "TestURow" begin
x = convert(Array{Int64, 1}, rand(1:500, 100))
x = convert(Array{Int, 1}, rand(1:500, 100))
_, _, _, _, _, _, _, _, _, _, _, _, urowOut, _ =
test_julia_binding(4.0, 12, "hello",
urow_in=x)
@test size(urowOut, 1) == 100
@test typeof(urowOut) == Array{Int64, 1}
@test typeof(urowOut) == Array{Int, 1}
for i in 1:100
# Since we subtract one when we convert to C++, and then add one when we
# convert back, we get a slightly different result here.
@@ -451,20 +451,21 @@ inline std::string PrintModel(const std::string& model)
template<typename... Args>
std::string ProgramCall(const std::string& programName, Args... args)
{
std::string s = "```";
std::string s;
if (BindingInfo::Language() == "cli")
{
s += "bash\n";
s += "```bash\n";
s += cli::ProgramCall(programName, args...);
}
else if (BindingInfo::Language() == "python")
{
s += "python\n";
s += "```python\n";
s += python::ProgramCall(programName, args...);
}
else if (BindingInfo::Language() == "julia")
{
s += "julia\n";
// Julia's ProgramCall() with a set of arguments will automatically enclose
// the text in Markdown code, so we don't need to.
s += julia::ProgramCall(programName, args...);
}
else
@@ -472,7 +473,10 @@ std::string ProgramCall(const std::string& programName, Args... args)
throw std::invalid_argument("ProgramCall(): unknown "
"BindingInfo::Language(): " + BindingInfo::Language() + "!");
}
s += "\n```";
// Close the Markdown code block, but only if we opened one.
if (BindingInfo::Language() != "julia")
s += "\n```";
return s;
}
+5 -2
View File
@@ -126,7 +126,8 @@ void PrintDocs(const std::string& bindingName,
cout << "| ";
cout << ParamString(it->second.name) << " | ";
cout << ParamType(it->second) << " | ";
cout << it->second.desc; // just a string
string desc = boost::replace_all_copy(it->second.desc, "|", "\\|");
cout << desc; // just a string
// Print whether or not it's a "special" language-only parameter.
if (it->second.name == "copy_all_inputs" || it->second.name == "help" ||
it->second.name == "info" || it->second.name == "version")
@@ -180,7 +181,9 @@ void PrintDocs(const std::string& bindingName,
cout << "{: #" << languages[i] << "_" << bindingName
<< "_detailed-documentation }" << endl;
cout << endl;
cout << programDoc.documentation() << endl;
string doc = boost::replace_all_copy(programDoc.documentation(),
"|", "\\|");
cout << doc << endl;
cout << endl;
cout << "### See also" << endl;
@@ -19,6 +19,9 @@ void Cube<eT>::serialize(Archive& ar, const unsigned int /* version */)
// mem_state will always be 0 on load, so we don't need to save it.
if (Archive::is_loading::value)
{
// Clean any mat pointers.
delete_mat();
// Don't free if local memory is being used.
if (mem_state == 0 && mem != NULL && old_n_elem > arma_config::mat_prealloc)
{
@@ -36,6 +36,12 @@
#endif
#endif
// Force definition of old HDF5 API. Thanks to Mike Roberts for helping find
// this workaround.
#if !defined(H5_USE_110_API)
#define H5_USE_110_API
#endif
// Include everything we'll need for serialize().
#include <boost/serialization/serialization.hpp>
#include <boost/serialization/nvp.hpp>
@@ -2,18 +2,14 @@
# Anything not in this list will not be compiled into mlpack.
set(SOURCES
bernoulli.hpp
boost_backport_math.hpp
boost_backport_serialization.hpp
detail/bernoulli_details.hpp
detail/polygamma.hpp
detail/unchecked_bernoulli.hpp
math_fwd.hpp
policy.hpp
polygamma.hpp
trigamma.hpp
unordered_collections_load_imp.hpp
unordered_collections_save_imp.hpp
unordered_map.hpp
vector.hpp
string_view.hpp
string_view_fwd.hpp
@@ -1,29 +0,0 @@
/**
* @file boost_backport.hpp
* @author Yannis Mentekidis
*
* Centralized control of what boost files to include. We have backported the
* following boost functionality here:
*
* * trigamma and polygamma function evaluation (added in boost 1.58.0)
*
* For versions 1.56, 1.57 we include the backported polygamma and trigamma
* functions. Anything newer, we include from Boost.
*/
#ifndef MLPACK_CORE_BOOST_BACKPORT_MATH_HPP
#define MLPACK_CORE_BOOST_BACKPORT_MATH_HPP
#include <boost/version.hpp>
#if BOOST_VERSION < 105800
// Backported trigamma and polygamma.
#include "mlpack/core/boost_backport/trigamma.hpp"
#include "mlpack/core/boost_backport/polygamma.hpp"
#else
// Boost's version.
#include <boost/math/special_functions/trigamma.hpp>
#include <boost/math/special_functions/polygamma.hpp>
#endif
#endif // MLPACK_CORE_BOOST_BACKPORT_HPP
@@ -16,14 +16,7 @@
#define MLPACK_CORE_BOOST_BACKPORT_SERIALIZATION_HPP
#include <boost/version.hpp>
#if BOOST_VERSION < 105600
// Backported unordered_map.
#include "mlpack/core/boost_backport/unordered_map.hpp"
#else
// Boost's version.
#include <boost/serialization/unordered_map.hpp>
#endif
#include <boost/serialization/unordered_map.hpp>
#if BOOST_VERSION == 105800
/**
@@ -1,94 +0,0 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright 2013 Nikhar Agrawal
// Copyright 2013 Christopher Kormanyos
// Copyright 2014 John Maddock
// Copyright 2013 Paul Bristow
// Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef _BOOST_POLYGAMMA_2013_07_30_HPP_
#define _BOOST_POLYGAMMA_2013_07_30_HPP_
#include "detail/polygamma.hpp"
#include "trigamma.hpp"
#include <boost/math/special_functions/factorials.hpp>
// Forward declarations
namespace boost { namespace math {
template <class T, class Policy>
inline typename tools::promote_args<T>::type
trigamma(T x, const Policy&);
template <class T>
inline typename tools::promote_args<T>::type
trigamma(T x);
}}
namespace boost { namespace math {
template<class T, class Policy>
inline typename tools::promote_args<T>::type polygamma(const int n, T x, const Policy& pol)
{
//
// Filter off special cases right at the start:
//
if(n == 0)
return boost::math::digamma(x, pol);
if(n == 1)
return boost::math::trigamma(x, pol);
//
// We've found some standard library functions to misbehave if any FPU exception flags
// are set prior to their call, this code will clear those flags, then reset them
// on exit:
//
BOOST_FPU_EXCEPTION_GUARD
//
// The type of the result - the common type of T and U after
// any integer types have been promoted to double:
//
typedef typename tools::promote_args<T>::type result_type;
//
// The type used for the calculation. This may be a wider type than
// the result in order to ensure full precision:
//
typedef typename policies::evaluation<result_type, Policy>::type value_type;
//
// The type of the policy to forward to the actual implementation.
// We disable promotion of float and double as that's [possibly]
// happened already in the line above. Also reset to the default
// any policies we don't use (reduces code bloat if we're called
// multiple times with differing policies we don't actually use).
// Also normalise the type, again to reduce code bloat in case we're
// called multiple times with functionally identical policies that happen
// to be different types.
//
typedef typename policies::normalise<
Policy,
policies::promote_float<false>,
policies::promote_double<false>,
policies::discrete_quantile<>,
policies::assert_undefined<> >::type forwarding_policy;
//
// Whew. Now we can make the actual call to the implementation.
// Arguments are explicitly cast to the evaluation type, and the result
// passed through checked_narrowing_cast which handles things like overflow
// according to the policy passed:
//
return policies::checked_narrowing_cast<result_type, forwarding_policy>(
detail::polygamma_imp(n, static_cast<value_type>(x), forwarding_policy()),
"boost::math::polygamma<%1%>(int, %1%)");
}
template<class T>
inline typename tools::promote_args<T>::type polygamma(const int n, T x)
{
return boost::math::polygamma(n, x, policies::policy<>());
}
} } // namespace boost::math
#endif // _BOOST_BERNOULLI_2013_05_30_HPP_
-469
View File
@@ -1,469 +0,0 @@
// (C) Copyright John Maddock 2006.
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_MATH_SF_TRIGAMMA_HPP
#define BOOST_MATH_SF_TRIGAMMA_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include "math_fwd.hpp"
#include "polygamma.hpp"
#include <boost/math/tools/rational.hpp>
#include <boost/math/tools/series.hpp>
#include <boost/math/tools/promotion.hpp>
#include <boost/math/policies/error_handling.hpp>
#include <boost/math/constants/constants.hpp>
#include <boost/mpl/comparison.hpp>
#include <boost/math/tools/big_constant.hpp>
namespace boost{
namespace math{
namespace detail{
template<class T, class Policy>
T polygamma_imp(const int n, T x, const Policy &pol);
template <class T, class Policy>
T trigamma_prec(T x, const mpl::int_<53>*, const Policy&)
{
// Max error in interpolated form: 3.736e-017
static const T offset = BOOST_MATH_BIG_CONSTANT(T, 53, 2.1093254089355469);
static const T P_1_2[] = {
BOOST_MATH_BIG_CONSTANT(T, 53, -1.1093280605946045),
BOOST_MATH_BIG_CONSTANT(T, 53, -3.8310674472619321),
BOOST_MATH_BIG_CONSTANT(T, 53, -3.3703848401898283),
BOOST_MATH_BIG_CONSTANT(T, 53, 0.28080574467981213),
BOOST_MATH_BIG_CONSTANT(T, 53, 1.6638069578676164),
BOOST_MATH_BIG_CONSTANT(T, 53, 0.64468386819102836),
};
static const T Q_1_2[] = {
BOOST_MATH_BIG_CONSTANT(T, 53, 1.0),
BOOST_MATH_BIG_CONSTANT(T, 53, 3.4535389668541151),
BOOST_MATH_BIG_CONSTANT(T, 53, 4.5208926987851437),
BOOST_MATH_BIG_CONSTANT(T, 53, 2.7012734178351534),
BOOST_MATH_BIG_CONSTANT(T, 53, 0.64468798399785611),
BOOST_MATH_BIG_CONSTANT(T, 53, -0.20314516859987728e-6),
};
// Max error in interpolated form: 1.159e-017
static const T P_2_4[] = {
BOOST_MATH_BIG_CONSTANT(T, 53, -0.13803835004508849e-7),
BOOST_MATH_BIG_CONSTANT(T, 53, 0.50000049158540261),
BOOST_MATH_BIG_CONSTANT(T, 53, 1.6077979838469348),
BOOST_MATH_BIG_CONSTANT(T, 53, 2.5645435828098254),
BOOST_MATH_BIG_CONSTANT(T, 53, 2.0534873203680393),
BOOST_MATH_BIG_CONSTANT(T, 53, 0.74566981111565923),
};
static const T Q_2_4[] = {
BOOST_MATH_BIG_CONSTANT(T, 53, 1.0),
BOOST_MATH_BIG_CONSTANT(T, 53, 2.8822787662376169),
BOOST_MATH_BIG_CONSTANT(T, 53, 4.1681660554090917),
BOOST_MATH_BIG_CONSTANT(T, 53, 2.7853527819234466),
BOOST_MATH_BIG_CONSTANT(T, 53, 0.74967671848044792),
BOOST_MATH_BIG_CONSTANT(T, 53, -0.00057069112416246805),
};
// Maximum Deviation Found: 6.896e-018
// Expected Error Term : -6.895e-018
// Maximum Relative Change in Control Points : 8.497e-004
static const T P_4_inf[] = {
static_cast<T>(0.68947581948701249e-17L),
static_cast<T>(0.49999999999998975L),
static_cast<T>(1.0177274392923795L),
static_cast<T>(2.498208511343429L),
static_cast<T>(2.1921221359427595L),
static_cast<T>(1.5897035272532764L),
static_cast<T>(0.40154388356961734L),
};
static const T Q_4_inf[] = {
static_cast<T>(1.0L),
static_cast<T>(1.7021215452463932L),
static_cast<T>(4.4290431747556469L),
static_cast<T>(2.9745631894384922L),
static_cast<T>(2.3013614809773616L),
static_cast<T>(0.28360399799075752L),
static_cast<T>(0.022892987908906897L),
};
if(x <= 2)
{
return (offset + boost::math::tools::evaluate_polynomial(P_1_2, x) / tools::evaluate_polynomial(Q_1_2, x)) / (x * x);
}
else if(x <= 4)
{
T y = 1 / x;
return (1 + tools::evaluate_polynomial(P_2_4, y) / tools::evaluate_polynomial(Q_2_4, y)) / x;
}
T y = 1 / x;
return (1 + tools::evaluate_polynomial(P_4_inf, y) / tools::evaluate_polynomial(Q_4_inf, y)) / x;
}
template <class T, class Policy>
T trigamma_prec(T x, const mpl::int_<64>*, const Policy&)
{
// Max error in interpolated form: 1.178e-020
static const T offset_1_2 = BOOST_MATH_BIG_CONSTANT(T, 64, 2.109325408935546875);
static const T P_1_2[] = {
BOOST_MATH_BIG_CONSTANT(T, 64, -1.10932535608960258341),
BOOST_MATH_BIG_CONSTANT(T, 64, -4.18793841543017129052),
BOOST_MATH_BIG_CONSTANT(T, 64, -4.63865531898487734531),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.919832884430500908047),
BOOST_MATH_BIG_CONSTANT(T, 64, 1.68074038333180423012),
BOOST_MATH_BIG_CONSTANT(T, 64, 1.21172611429185622377),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.259635673503366427284),
};
static const T Q_1_2[] = {
BOOST_MATH_BIG_CONSTANT(T, 64, 1.0),
BOOST_MATH_BIG_CONSTANT(T, 64, 3.77521119359546982995),
BOOST_MATH_BIG_CONSTANT(T, 64, 5.664338024578956321),
BOOST_MATH_BIG_CONSTANT(T, 64, 4.25995134879278028361),
BOOST_MATH_BIG_CONSTANT(T, 64, 1.62956638448940402182),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.259635512844691089868),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.629642219810618032207e-8),
};
// Max error in interpolated form: 3.912e-020
static const T P_2_8[] = {
BOOST_MATH_BIG_CONSTANT(T, 64, -0.387540035162952880976e-11),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.500000000276430504),
BOOST_MATH_BIG_CONSTANT(T, 64, 3.21926880986360957306),
BOOST_MATH_BIG_CONSTANT(T, 64, 10.2550347708483445775),
BOOST_MATH_BIG_CONSTANT(T, 64, 18.9002075150709144043),
BOOST_MATH_BIG_CONSTANT(T, 64, 21.0357215832399705625),
BOOST_MATH_BIG_CONSTANT(T, 64, 13.4346512182925923978),
BOOST_MATH_BIG_CONSTANT(T, 64, 3.98656291026448279118),
};
static const T Q_2_8[] = {
BOOST_MATH_BIG_CONSTANT(T, 64, 1.0),
BOOST_MATH_BIG_CONSTANT(T, 64, 6.10520430478613667724),
BOOST_MATH_BIG_CONSTANT(T, 64, 18.475001060603645512),
BOOST_MATH_BIG_CONSTANT(T, 64, 31.7087534567758405638),
BOOST_MATH_BIG_CONSTANT(T, 64, 31.908814523890465398),
BOOST_MATH_BIG_CONSTANT(T, 64, 17.4175479039227084798),
BOOST_MATH_BIG_CONSTANT(T, 64, 3.98749106958394941276),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.000115917322224411128566),
};
// Maximum Deviation Found: 2.635e-020
// Expected Error Term : 2.635e-020
// Maximum Relative Change in Control Points : 1.791e-003
static const T P_8_inf[] = {
BOOST_MATH_BIG_CONSTANT(T, 64, -0.263527875092466899848e-19),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.500000000000000058145),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.0730121433777364138677),
BOOST_MATH_BIG_CONSTANT(T, 64, 1.94505878379957149534),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.0517092358874932620529),
BOOST_MATH_BIG_CONSTANT(T, 64, 1.07995383547483921121),
};
static const T Q_8_inf[] = {
BOOST_MATH_BIG_CONSTANT(T, 64, 1.0),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.187309046577818095504),
BOOST_MATH_BIG_CONSTANT(T, 64, 3.95255391645238842975),
BOOST_MATH_BIG_CONSTANT(T, 64, -1.14743283327078949087),
BOOST_MATH_BIG_CONSTANT(T, 64, 2.52989799376344914499),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.627414303172402506396),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.141554248216425512536),
};
if(x <= 2)
{
return (offset_1_2 + boost::math::tools::evaluate_polynomial(P_1_2, x) / tools::evaluate_polynomial(Q_1_2, x)) / (x * x);
}
else if(x <= 8)
{
T y = 1 / x;
return (1 + tools::evaluate_polynomial(P_2_8, y) / tools::evaluate_polynomial(Q_2_8, y)) / x;
}
T y = 1 / x;
return (1 + tools::evaluate_polynomial(P_8_inf, y) / tools::evaluate_polynomial(Q_8_inf, y)) / x;
}
template <class T, class Policy>
T trigamma_prec(T x, const mpl::int_<113>*, const Policy&)
{
// Max error in interpolated form: 1.916e-035
static const T P_1_2[] = {
BOOST_MATH_BIG_CONSTANT(T, 113, -0.999999999999999082554457936871832533),
BOOST_MATH_BIG_CONSTANT(T, 113, -4.71237311120865266379041700054847734),
BOOST_MATH_BIG_CONSTANT(T, 113, -7.94125711970499027763789342500817316),
BOOST_MATH_BIG_CONSTANT(T, 113, -5.74657746697664735258222071695644535),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.404213349456398905981223965160595687),
BOOST_MATH_BIG_CONSTANT(T, 113, 2.47877781178642876561595890095758896),
BOOST_MATH_BIG_CONSTANT(T, 113, 2.07714151702455125992166949812126433),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.858877899162360138844032265418028567),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.20499222604410032375789018837922397),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.0272103140348194747360175268778415049),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.0015764849020876949848954081173520686),
};
static const T Q_1_2[] = {
BOOST_MATH_BIG_CONSTANT(T, 113, 1.0),
BOOST_MATH_BIG_CONSTANT(T, 113, 4.71237311120863419878375031457715223),
BOOST_MATH_BIG_CONSTANT(T, 113, 9.58619118655339853449127952145877467),
BOOST_MATH_BIG_CONSTANT(T, 113, 11.0940067269829372437561421279054968),
BOOST_MATH_BIG_CONSTANT(T, 113, 8.09075424749327792073276309969037885),
BOOST_MATH_BIG_CONSTANT(T, 113, 3.87705890159891405185343806884451286),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.22758678701914477836330837816976782),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.249092040606385004109672077814668716),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.0295750413900655597027079600025569048),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.00157648490200498142247694709728858139),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.161264050344059471721062360645432809e-14),
};
// Max error in interpolated form: 8.958e-035
static const T P_2_4[] = {
BOOST_MATH_BIG_CONSTANT(T, 113, -2.55843734739907925764326773972215085),
BOOST_MATH_BIG_CONSTANT(T, 113, -12.2830208240542011967952466273455887),
BOOST_MATH_BIG_CONSTANT(T, 113, -23.9195022162767993526575786066414403),
BOOST_MATH_BIG_CONSTANT(T, 113, -24.9256431504823483094158828285470862),
BOOST_MATH_BIG_CONSTANT(T, 113, -14.7979122765478779075108064826412285),
BOOST_MATH_BIG_CONSTANT(T, 113, -4.46654453928610666393276765059122272),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.0191439033405649675717082465687845002),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.515412052554351265708917209749037352),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.195378348786064304378247325360320038),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.0334761282624174313035014426794245393),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.002373665205942206348500250056602687),
};
static const T Q_2_4[] = {
BOOST_MATH_BIG_CONSTANT(T, 113, 1.0),
BOOST_MATH_BIG_CONSTANT(T, 113, 4.80098558454419907830670928248659245),
BOOST_MATH_BIG_CONSTANT(T, 113, 9.99220727843170133895059300223445265),
BOOST_MATH_BIG_CONSTANT(T, 113, 11.8896146167631330735386697123464976),
BOOST_MATH_BIG_CONSTANT(T, 113, 8.96613256683809091593793565879092581),
BOOST_MATH_BIG_CONSTANT(T, 113, 4.47254136149624110878909334574485751),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.48600982028196527372434773913633152),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.319570735766764237068541501137990078),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.0407358345787680953107374215319322066),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.00237366520593271641375755486420859837),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.239554887903526152679337256236302116e-15),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.294749244740618656265237072002026314e-17),
};
static const T y_offset_2_4 = BOOST_MATH_BIG_CONSTANT(T, 113, 3.558437347412109375);
// Max error in interpolated form: 4.319e-035
static const T P_4_8[] = {
BOOST_MATH_BIG_CONSTANT(T, 113, 0.166626112697021464248967707021688845e-16),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.499999999999997739552090249208808197),
BOOST_MATH_BIG_CONSTANT(T, 113, 6.40270945019053817915772473771553187),
BOOST_MATH_BIG_CONSTANT(T, 113, 41.3833374155000608013677627389343329),
BOOST_MATH_BIG_CONSTANT(T, 113, 166.803341854562809335667241074035245),
BOOST_MATH_BIG_CONSTANT(T, 113, 453.39964786925369319960722793414521),
BOOST_MATH_BIG_CONSTANT(T, 113, 851.153712317697055375935433362983944),
BOOST_MATH_BIG_CONSTANT(T, 113, 1097.70657567285059133109286478004458),
BOOST_MATH_BIG_CONSTANT(T, 113, 938.431232478455316020076349367632922),
BOOST_MATH_BIG_CONSTANT(T, 113, 487.268001604651932322080970189930074),
BOOST_MATH_BIG_CONSTANT(T, 113, 119.953445242335730062471193124820659),
};
static const T Q_4_8[] = {
BOOST_MATH_BIG_CONSTANT(T, 113, 1.0),
BOOST_MATH_BIG_CONSTANT(T, 113, 12.4720855670474488978638945855932398),
BOOST_MATH_BIG_CONSTANT(T, 113, 78.6093129753298570701376952709727391),
BOOST_MATH_BIG_CONSTANT(T, 113, 307.470246050318322489781182863190127),
BOOST_MATH_BIG_CONSTANT(T, 113, 805.140686101151538537565264188630079),
BOOST_MATH_BIG_CONSTANT(T, 113, 1439.12019760292146454787601409644413),
BOOST_MATH_BIG_CONSTANT(T, 113, 1735.6105285756048831268586001383127),
BOOST_MATH_BIG_CONSTANT(T, 113, 1348.32500712856328019355198611280536),
BOOST_MATH_BIG_CONSTANT(T, 113, 607.225985860570846699704222144650563),
BOOST_MATH_BIG_CONSTANT(T, 113, 119.952317857277045332558673164517227),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.000140165918355036060868680809129436084),
};
// Maximum Deviation Found: 2.867e-035
// Expected Error Term : 2.866e-035
// Maximum Relative Change in Control Points : 2.662e-004
static const T P_8_16[] = {
BOOST_MATH_BIG_CONSTANT(T, 113, -0.184828315274146610610872315609837439e-19),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.500000000000000004122475157735807738),
BOOST_MATH_BIG_CONSTANT(T, 113, 3.02533865247313349284875558880415875),
BOOST_MATH_BIG_CONSTANT(T, 113, 13.5995927517457371243039532492642734),
BOOST_MATH_BIG_CONSTANT(T, 113, 35.3132224283087906757037999452941588),
BOOST_MATH_BIG_CONSTANT(T, 113, 67.1639424550714159157603179911505619),
BOOST_MATH_BIG_CONSTANT(T, 113, 83.5767733658513967581959839367419891),
BOOST_MATH_BIG_CONSTANT(T, 113, 71.073491212235705900866411319363501),
BOOST_MATH_BIG_CONSTANT(T, 113, 35.8621515614725564575893663483998663),
BOOST_MATH_BIG_CONSTANT(T, 113, 8.72152231639983491987779743154333318),
};
static const T Q_8_16[] = {
BOOST_MATH_BIG_CONSTANT(T, 113, 1.0),
BOOST_MATH_BIG_CONSTANT(T, 113, 5.71734397161293452310624822415866372),
BOOST_MATH_BIG_CONSTANT(T, 113, 25.293404179620438179337103263274815),
BOOST_MATH_BIG_CONSTANT(T, 113, 62.2619767967468199111077640625328469),
BOOST_MATH_BIG_CONSTANT(T, 113, 113.955048909238993473389714972250235),
BOOST_MATH_BIG_CONSTANT(T, 113, 130.807138328938966981862203944329408),
BOOST_MATH_BIG_CONSTANT(T, 113, 102.423146902337654110717764213057753),
BOOST_MATH_BIG_CONSTANT(T, 113, 44.0424772805245202514468199602123565),
BOOST_MATH_BIG_CONSTANT(T, 113, 8.89898032477904072082994913461386099),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.0296627336872039988632793863671456398),
};
// Maximum Deviation Found: 1.079e-035
// Expected Error Term : -1.079e-035
// Maximum Relative Change in Control Points : 7.884e-003
static const T P_16_inf[] = {
BOOST_MATH_BIG_CONSTANT(T, 113, 0.0),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.500000000000000000000000000000087317),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.345625669885456215194494735902663968),
BOOST_MATH_BIG_CONSTANT(T, 113, 9.62895499360842232127552650044647769),
BOOST_MATH_BIG_CONSTANT(T, 113, 3.5936085382439026269301003761320812),
BOOST_MATH_BIG_CONSTANT(T, 113, 49.459599118438883265036646019410669),
BOOST_MATH_BIG_CONSTANT(T, 113, 7.77519237321893917784735690560496607),
BOOST_MATH_BIG_CONSTANT(T, 113, 74.4536074488178075948642351179304121),
BOOST_MATH_BIG_CONSTANT(T, 113, 2.75209340397069050436806159297952699),
BOOST_MATH_BIG_CONSTANT(T, 113, 23.9292359711471667884504840186561598),
};
static const T Q_16_inf[] = {
BOOST_MATH_BIG_CONSTANT(T, 113, 1.0),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.357918006437579097055656138920742037),
BOOST_MATH_BIG_CONSTANT(T, 113, 19.1386039850709849435325005484512944),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.874349081464143606016221431763364517),
BOOST_MATH_BIG_CONSTANT(T, 113, 98.6516097434855572678195488061432509),
BOOST_MATH_BIG_CONSTANT(T, 113, -16.1051972833382893468655223662534306),
BOOST_MATH_BIG_CONSTANT(T, 113, 154.316860216253720989145047141653727),
BOOST_MATH_BIG_CONSTANT(T, 113, -40.2026880424378986053105969312264534),
BOOST_MATH_BIG_CONSTANT(T, 113, 60.1679136674264778074736441126810223),
BOOST_MATH_BIG_CONSTANT(T, 113, -13.3414844622256422644504472438320114),
BOOST_MATH_BIG_CONSTANT(T, 113, 2.53795636200649908779512969030363442),
};
if(x <= 2)
{
return (2 + boost::math::tools::evaluate_polynomial(P_1_2, x) / tools::evaluate_polynomial(Q_1_2, x)) / (x * x);
}
else if(x <= 4)
{
return (y_offset_2_4 + boost::math::tools::evaluate_polynomial(P_2_4, x) / tools::evaluate_polynomial(Q_2_4, x)) / (x * x);
}
else if(x <= 8)
{
T y = 1 / x;
return (1 + tools::evaluate_polynomial(P_4_8, y) / tools::evaluate_polynomial(Q_4_8, y)) / x;
}
else if(x <= 16)
{
T y = 1 / x;
return (1 + tools::evaluate_polynomial(P_8_16, y) / tools::evaluate_polynomial(Q_8_16, y)) / x;
}
T y = 1 / x;
return (1 + tools::evaluate_polynomial(P_16_inf, y) / tools::evaluate_polynomial(Q_16_inf, y)) / x;
}
template <class T, class Tag, class Policy>
T trigamma_imp(T x, const Tag* t, const Policy& pol)
{
//
// This handles reflection of negative arguments, and all our
// error handling, then forwards to the T-specific approximation.
//
BOOST_MATH_STD_USING // ADL of std functions.
T result = 0;
//
// Check for negative arguments and use reflection:
//
if(x <= 0)
{
// Reflect:
T z = 1 - x;
// Argument reduction for tan:
if(floor(x) == x)
{
return policies::raise_pole_error<T>("boost::math::trigamma<%1%>(%1%)", 0, (1-x), pol);
}
T s = fabs(x) < fabs(z) ? boost::math::sin_pi(x, pol) : boost::math::sin_pi(z, pol);
return -trigamma_imp(z, t, pol) + boost::math::pow<2>(constants::pi<T>()) / (s * s);
}
if(x < 1)
{
result = 1 / (x * x);
x += 1;
}
return result + trigamma_prec(x, t, pol);
}
template <class T, class Policy>
T trigamma_imp(T x, const mpl::int_<0>*, const Policy& pol)
{
return polygamma_imp(1, x, pol);
}
//
// Initializer: ensure all our constants are initialized prior to the first call of main:
//
template <class T, class Policy>
struct trigamma_initializer
{
struct init
{
init()
{
typedef typename policies::precision<T, Policy>::type precision_type;
do_init(mpl::bool_<precision_type::value && (precision_type::value <= 113)>());
}
void do_init(const mpl::true_&)
{
boost::math::trigamma(T(2.5), Policy());
}
void do_init(const mpl::false_&){}
void force_instantiate()const{}
};
static const init initializer;
static void force_instantiate()
{
initializer.force_instantiate();
}
};
template <class T, class Policy>
const typename trigamma_initializer<T, Policy>::init trigamma_initializer<T, Policy>::initializer;
} // namespace detail
template <class T, class Policy>
inline typename tools::promote_args<T>::type
trigamma(T x, const Policy&)
{
typedef typename tools::promote_args<T>::type result_type;
typedef typename policies::evaluation<result_type, Policy>::type value_type;
typedef typename policies::precision<T, Policy>::type precision_type;
typedef typename mpl::if_<
mpl::or_<
mpl::less_equal<precision_type, mpl::int_<0> >,
mpl::greater<precision_type, mpl::int_<114> >
>,
mpl::int_<0>,
typename mpl::if_<
mpl::less<precision_type, mpl::int_<54> >,
mpl::int_<53>,
typename mpl::if_<
mpl::less<precision_type, mpl::int_<65> >,
mpl::int_<64>,
mpl::int_<113>
>::type
>::type
>::type tag_type;
typedef typename policies::normalise<
Policy,
policies::promote_float<false>,
policies::promote_double<false>,
policies::discrete_quantile<>,
policies::assert_undefined<> >::type forwarding_policy;
// Force initialization of constants:
detail::trigamma_initializer<value_type, forwarding_policy>::force_instantiate();
return policies::checked_narrowing_cast<result_type, Policy>(detail::trigamma_imp(
static_cast<value_type>(x),
static_cast<const tag_type*>(0), forwarding_policy()), "boost::math::trigamma<%1%>(%1%)");
}
template <class T>
inline typename tools::promote_args<T>::type
trigamma(T x)
{
return trigamma(x, policies::policy<>());
}
} // namespace math
} // namespace boost
#endif
@@ -1,234 +0,0 @@
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_SERIALIZATION_UNORDERED_MAP_HPP
#define BOOST_SERIALIZATION_UNORDERED_MAP_HPP
// MS compatible compilers support #pragma once
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
# pragma once
#endif
/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
// serialization/unordered_map.hpp:
// serialization for stl unordered_map templates
// (C) Copyright 2002 Robert Ramey - http://www.rrsd.com .
// (C) Copyright 2014 Jim Bell
// Use, modification and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
// See http://www.boost.org for updates, documentation, and revision history.
#include <boost/config.hpp>
#include <unordered_map>
#include <boost/serialization/utility.hpp>
#include "unordered_collections_save_imp.hpp"
#include "unordered_collections_load_imp.hpp"
#include <boost/serialization/split_free.hpp>
namespace boost {
namespace serialization {
namespace stl {
// map input
template<class Archive, class Container>
struct archive_input_unordered_map
{
inline void operator()(
Archive &ar,
Container &s,
const unsigned int v
){
typedef typename Container::value_type type;
detail::stack_construct<Archive, type> t(ar, v);
// borland fails silently w/o full namespace
ar >> boost::serialization::make_nvp("item", t.reference());
std::pair<typename Container::const_iterator, bool> result =
s.insert(t.reference());
// note: the following presumes that the map::value_type was NOT tracked
// in the archive. This is the usual case, but here there is no way
// to determine that.
if(result.second){
ar.reset_object_address(
& (result.first->second),
& t.reference().second
);
}
}
};
// multimap input
template<class Archive, class Container>
struct archive_input_unordered_multimap
{
inline void operator()(
Archive &ar,
Container &s,
const unsigned int v
){
typedef typename Container::value_type type;
detail::stack_construct<Archive, type> t(ar, v);
// borland fails silently w/o full namespace
ar >> boost::serialization::make_nvp("item", t.reference());
typename Container::const_iterator result
= s.insert(t.reference());
// note: the following presumes that the map::value_type was NOT tracked
// in the archive. This is the usual case, but here there is no way
// to determine that.
ar.reset_object_address(
& result->second,
& t.reference()
);
}
};
} // stl
template<
class Archive,
class Key,
class HashFcn,
class EqualKey,
class Allocator
>
inline void save(
Archive & ar,
const std::unordered_map<
Key, HashFcn, EqualKey, Allocator
> &t,
const unsigned int /*file_version*/
){
boost::serialization::stl::save_unordered_collection<
Archive,
std::unordered_map<
Key, HashFcn, EqualKey, Allocator
>
>(ar, t);
}
template<
class Archive,
class Key,
class HashFcn,
class EqualKey,
class Allocator
>
inline void load(
Archive & ar,
std::unordered_map<
Key, HashFcn, EqualKey, Allocator
> &t,
const unsigned int /*file_version*/
){
boost::serialization::stl::load_unordered_collection<
Archive,
std::unordered_map<
Key, HashFcn, EqualKey, Allocator
>,
boost::serialization::stl::archive_input_unordered_map<
Archive,
std::unordered_map<
Key, HashFcn, EqualKey, Allocator
>
>
>(ar, t);
}
// split non-intrusive serialization function member into separate
// non intrusive save/load member functions
template<
class Archive,
class Key,
class HashFcn,
class EqualKey,
class Allocator
>
inline void serialize(
Archive & ar,
std::unordered_map<
Key, HashFcn, EqualKey, Allocator
> &t,
const unsigned int file_version
){
boost::serialization::split_free(ar, t, file_version);
}
// unordered_multimap
template<
class Archive,
class Key,
class HashFcn,
class EqualKey,
class Allocator
>
inline void save(
Archive & ar,
const std::unordered_multimap<
Key, HashFcn, EqualKey, Allocator
> &t,
const unsigned int /*file_version*/
){
boost::serialization::stl::save_unordered_collection<
Archive,
std::unordered_multimap<
Key, HashFcn, EqualKey, Allocator
>
>(ar, t);
}
template<
class Archive,
class Key,
class HashFcn,
class EqualKey,
class Allocator
>
inline void load(
Archive & ar,
std::unordered_multimap<
Key, HashFcn, EqualKey, Allocator
> &t,
const unsigned int /*file_version*/
){
boost::serialization::stl::load_unordered_collection<
Archive,
std::unordered_multimap<
Key, HashFcn, EqualKey, Allocator
>,
boost::serialization::stl::archive_input_unordered_multimap<
Archive,
std::unordered_multimap<
Key, HashFcn, EqualKey, Allocator
>
>
>(ar, t);
}
// split non-intrusive serialization function member into separate
// non intrusive save/load member functions
template<
class Archive,
class Key,
class HashFcn,
class EqualKey,
class Allocator
>
inline void serialize(
Archive & ar,
std::unordered_multimap<
Key, HashFcn, EqualKey, Allocator
> &t,
const unsigned int file_version
){
boost::serialization::split_free(ar, t, file_version);
}
} // namespace serialization
} // namespace boost
#endif // BOOST_SERIALIZATION_UNORDERED_MAP_HPP
@@ -13,6 +13,8 @@ set(SOURCES
precision_impl.hpp
recall.hpp
recall_impl.hpp
r2_score.hpp
r2_score_impl.hpp
)
# Add directory name to sources.
+76
View File
@@ -0,0 +1,76 @@
/**
* @file r2_score.hpp
* @author Bisakh Mondal
*
* The R^2 (Coefficient of determination) regression metric.
*
* 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_CV_METRICS_R2SCORE_HPP
#define MLPACK_CORE_CV_METRICS_R2SCORE_HPP
#include <mlpack/core.hpp>
namespace mlpack {
namespace cv {
/**
* The R2 Score is a metric of performance for regression algorithms
* that represents the proportion of variance (here y) that has been
* explained by the independent variables in the model. It provides
* an indication of goodness of fit and therefore a measure of how
* well unseen samples are likely to be predicted by the model,
* through the proportion of explained variance.
* As R2 Score is dataset dependent it can have wide range of values. The
* best possible score is @f$R^2 =1.0@f$. Values of R2 outside the range
* 0 to 1 can occur when the model fits the data worse than a horizontal
* hyperplane. This would occur when the wrong model was chosen, or
* nonsensical constraints were applied by mistake. A model which
* predicts exactly the expected value of y, disregarding the input
* features, gets a R2 Score equals to 0.0.
* If a model predicts @f$ \hat{y}_i $@f of the @f$ i $@f-th sample for a true
* @f$ y_i $@f for total n samples, the R2 Score is calculated by
* @f{eqnarray*}{
* R^{2} \left( y, \hat{y} \right) &=& 1-\frac{\sum_{i=1}^{n}
* \left( y_i - \hat{y_i} \right)^2 }
* {\sum_{i=1}^{n} \left( y_i - \bar{y}\right)^2}\\
* @f}
*
* where @f$ \bar{y} = frac{1}{y}\sum_{i=1}^{n} y_i $@f.
* For example, a model having R2Score = 0.85, explains 85 \% variability of
* the response data around its mean.
*/
class R2Score
{
public:
/**
* Run prediction and calculate the R squared error.
*
* @param model A regression model.
* @param data Column-major data containing test items.
* @param responses Ground truth (correct) target values for the test items,
* should be either a row vector or a column-major matrix.
* @return calculated R2 Score.
*/
template<typename MLAlgorithm, typename DataType, typename ResponsesType>
static double Evaluate(MLAlgorithm& model,
const DataType& data,
const ResponsesType& responses);
/**
* Information for hyper-parameter tuning code. It indicates that we want
* to maximize the measurement.
*/
static const bool NeedsMinimization = false;
};
} // namespace cv
} // namespace mlpack
// Include implementation.
#include "r2_score_impl.hpp"
#endif
@@ -0,0 +1,55 @@
/**
* @file r2_score_impl.hpp
* @author Bisakh Mondal
*
* The implementation of the class R2Score.
*
* 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_CV_METRICS_R2SCORE_IMPL_HPP
#define MLPACK_CORE_CV_METRICS_R2SCORE_IMPL_HPP
namespace mlpack {
namespace cv {
template<typename MLAlgorithm, typename DataType, typename ResponsesType>
double R2Score::Evaluate(MLAlgorithm& model,
const DataType& data,
const ResponsesType& responses)
{
if (data.n_cols != responses.n_cols)
{
std::ostringstream oss;
oss << "R2Score::Evaluate(): number of points (" << data.n_cols << ") "
<< "does not match number of responses (" << responses.n_cols << ")!"
<< std::endl;
throw std::invalid_argument(oss.str());
}
ResponsesType predictedResponses;
// Taking Predicted Output from the model.
model.Predict(data, predictedResponses);
// Mean value of response.
double meanResponses = arma::mean(responses);
// Calculate the numerator i.e. residual sum of squares.
double residualSumSquared = arma::accu(arma::square(responses -
predictedResponses));
// Calculate the denominator i.e.total sum of squares.
double totalSumSquared = arma::accu(arma::square(responses - meanResponses));
// Handling undefined R2 Score when both denominator and numerator is 0.0.
if (residualSumSquared == 0.0)
return totalSumSquared ? 1.0 : DBL_MIN;
return 1 - residualSumSquared / totalSumSquared;
}
} // namespace cv
} // namespace mlpack
#endif
+2
View File
@@ -11,6 +11,7 @@ set(SOURCES
load_csv.cpp
load.hpp
load_image_impl.hpp
load_image.cpp
load_model_impl.hpp
load_vec_impl.hpp
load_impl.hpp
@@ -21,6 +22,7 @@ set(SOURCES
normalize_labels_impl.hpp
save.hpp
save_impl.hpp
save_image.cpp
serialization_template_version.hpp
split_data.hpp
imputer.hpp
+9 -18
View File
@@ -13,28 +13,12 @@
#ifndef MLPACK_CORE_DATA_IMAGE_INFO_HPP
#define MLPACK_CORE_DATA_IMAGE_INFO_HPP
#include <mlpack/prereqs.hpp>
#include "extension.hpp"
#ifdef HAS_STB // Compile this only if stb is present.
#define STB_IMAGE_STATIC
#define STB_IMAGE_IMPLEMENTATION
#include <stb_image.h>
#define STB_IMAGE_WRITE_STATIC
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include <stb_image_write.h>
#endif
namespace mlpack {
namespace data {
#ifdef HAS_STB // Compile this only if stb is present.
/**
* Checks if the given image filename is supported.
*
@@ -44,8 +28,6 @@ namespace data {
inline bool ImageFormatSupported(const std::string& fileName,
const bool save = false);
#endif
/**
* Implements meta-data of images required by data::Load and
* data::Save for loading and saving images into arma::Mat.
@@ -87,6 +69,15 @@ class ImageInfo
//! Modify the image quality.
size_t& Quality() { return quality; }
template<typename Archive>
void serialize(Archive& ar, const unsigned int /* version */)
{
ar & BOOST_SERIALIZATION_NVP(width);
ar & BOOST_SERIALIZATION_NVP(channels);
ar & BOOST_SERIALIZATION_NVP(height);
ar & BOOST_SERIALIZATION_NVP(quality);
}
private:
// To store the image width.
size_t width;
+7 -7
View File
@@ -291,7 +291,6 @@ bool Load(const std::string& filename,
/**
* Image load/save interfaces.
*/
#ifdef HAS_STB
/**
* Load the image file into the given matrix.
@@ -300,15 +299,13 @@ bool Load(const std::string& filename,
* @param matrix Matrix to load the image into.
* @param info An object of ImageInfo class.
* @param fatal If an error should be reported as fatal (default false).
* @param transpose If true, transpose the matrix after loading.
* @return Boolean value indicating success or failure of load.
*/
template<typename eT>
bool Load(const std::string& filename,
arma::Mat<eT>& matrix,
ImageInfo& info,
const bool fatal = false,
const bool transpose = true);
const bool fatal = false);
/**
* Load the image file into the given matrix.
@@ -324,10 +321,13 @@ template<typename eT>
bool Load(const std::vector<std::string>& files,
arma::Mat<eT>& matrix,
ImageInfo& info,
const bool fatal = false,
const bool transpose = true);
const bool fatal = false);
#endif // HAS_STB.
// Implementation found in load_image.cpp.
bool LoadImage(const std::string& filename,
arma::Mat<unsigned char>& matrix,
ImageInfo& info,
const bool fatal = false);
} // namespace data
} // namespace mlpack
+125
View File
@@ -0,0 +1,125 @@
/**
* @file load_image.cpp
* @author Mehul Kumar Nirala
*
* Implementation of image loading functionality via STB.
*/
#include "load.hpp"
#include "image_info.hpp"
#ifdef HAS_STB
#define STB_IMAGE_STATIC
#define STB_IMAGE_IMPLEMENTATION
#include <stb_image.h>
#define STB_IMAGE_WRITE_STATIC
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include <stb_image_write.h>
namespace mlpack {
namespace data {
bool LoadImage(const std::string& filename,
arma::Mat<unsigned char>& matrix,
ImageInfo& info,
const bool fatal)
{
unsigned char* image;
if (!ImageFormatSupported(filename))
{
std::ostringstream oss;
oss << "Load(): file type " << Extension(filename) << " not supported. ";
oss << "Currently it supports: ";
for (auto extension : loadFileTypes)
oss << " " << extension;
oss << "." << std::endl;
if (fatal)
{
Log::Fatal << oss.str();
}
else
{
Log::Warn << oss.str();
}
return false;
}
// Temporary variables needed as stb_image.h supports int parameters.
int tempWidth, tempHeight, tempChannels;
// For grayscale images.
if (info.Channels() == 1)
{
image = stbi_load(filename.c_str(), &tempWidth, &tempHeight, &tempChannels,
STBI_grey);
}
else
{
image = stbi_load(filename.c_str(), &tempWidth, &tempHeight, &tempChannels,
STBI_rgb);
}
if (!image)
{
if (fatal)
{
Log::Fatal << "Load(): failed to load image '" << filename << "': "
<< stbi_failure_reason() << std::endl;
}
else
{
Log::Warn << "Load(): failed to load image '" << filename << "': "
<< stbi_failure_reason() << std::endl;
}
return false;
}
info.Width() = tempWidth;
info.Height() = tempHeight;
info.Channels() = tempChannels;
// Copy image into armadillo Mat.
matrix = arma::Mat<unsigned char>(image, info.Width() * info.Height() *
info.Channels(), 1, true, true);
// Free the image pointer.
free(image);
return true;
}
} // namespace data
} // namespace mlpack
#else
namespace mlpack {
namespace data {
bool LoadImage(const std::string& /* filename */,
arma::Mat<unsigned char>& /* matrix */,
ImageInfo& /* info */,
const bool fatal)
{
if (fatal)
{
Log::Fatal << "Load(): mlpack was not compiled with STB support, so images "
<< "cannot be loaded!" << std::endl;
}
else
{
Log::Warn << "Load(): mlpack was not compiled with STB support, so images "
<< "cannot be loaded!" << std::endl;
}
return false;
}
} // namespace data
} // namespace mlpack
#endif
+31 -83
View File
@@ -19,68 +19,28 @@
namespace mlpack {
namespace data {
#ifdef HAS_STB // Compile this only if stb is present.
// Image loading API.
template<typename eT>
bool Load(const std::string& filename,
arma::Mat<eT>& matrix,
ImageInfo& info,
const bool /* fatal */,
const bool transpose)
const bool fatal)
{
Timer::Start("loading_image");
unsigned char* image;
if (!ImageFormatSupported(filename))
// STB loads into unsigned char matrices, so we may have to convert once
// loaded.
arma::Mat<unsigned char> tempMatrix;
const bool result = LoadImage(filename, tempMatrix, info, fatal);
// If fatal is true, then the program will have already thrown an exception.
if (!result)
{
std::ostringstream oss;
oss << "File type " << Extension(filename) << " not supported.\n";
oss << "Currently it supports ";
for (auto extension : loadFileTypes)
oss << " " << extension;
oss << std::endl;
throw std::runtime_error(oss.str());
Timer::Stop("loading_image");
return false;
}
stbi_set_flip_vertically_on_load(transpose);
// Temporary variables needed as stb_image.h supports int parameters.
int tempWidth, tempHeight, tempChannels;
// For grayscale images.
if (info.Channels() == 1)
{
image = stbi_load(filename.c_str(), &tempWidth, &tempHeight, &tempChannels,
STBI_grey);
}
else
{
image = stbi_load(filename.c_str(), &tempWidth, &tempHeight, &tempChannels,
STBI_rgb);
}
if (tempWidth <= 0 || tempHeight <= 0)
{
std::ostringstream oss;
oss << "Image '" << filename << "' not found." << std::endl;
free(image);
throw std::runtime_error(oss.str());
return false;
}
info.Width() = tempWidth;
info.Height() = tempHeight;
info.Channels() = tempChannels;
// Copy image into armadillo Mat.
matrix = arma::Mat<unsigned char>(image, info.Width() * info.Height() *
info.Channels(), 1, true, true);
// Free the image pointer.
free(image);
matrix = arma::conv_to<arma::Mat<eT>>::from(tempMatrix);
Timer::Stop("loading_image");
return true;
}
@@ -90,58 +50,46 @@ template<typename eT>
bool Load(const std::vector<std::string>& files,
arma::Mat<eT>& matrix,
ImageInfo& info,
const bool fatal,
const bool transpose)
const bool fatal)
{
if (files.size() == 0)
{
std::ostringstream oss;
oss << "Files vector is empty." << std::endl;
oss << "Load(): vector of image files is empty." << std::endl;
if (fatal)
Log::Fatal << oss.str();
else
Log::Warn << oss.str();
throw std::runtime_error(oss.str());
return false;
}
arma::Mat<unsigned char> img;
bool status = Load(files[0], img, info, fatal, transpose);
bool status = LoadImage(files[0], img, info, fatal);
if (!status)
return false;
// Decide matrix dimension using the image height and width.
matrix.set_size(info.Width() * info.Height() * info.Channels(), files.size());
matrix.col(0) = img;
arma::Mat<unsigned char> tmpMatrix(
info.Width() * info.Height() * info.Channels(), files.size());
tmpMatrix.col(0) = img;
for (size_t i = 1; i < files.size() ; i++)
{
arma::Mat<unsigned char> colImg(matrix.colptr(i), matrix.n_rows, 1,
arma::Mat<unsigned char> colImg(tmpMatrix.colptr(i), tmpMatrix.n_rows, 1,
false, true);
status &= Load(files[i], colImg, info, fatal, transpose);
status = LoadImage(files[i], colImg, info, fatal);
if (!status)
return false;
}
return status;
}
#else // No STB.
template<typename eT>
bool Load(const std::string& filename,
arma::Mat<eT>& matrix,
ImageInfo& info,
const bool fatal = false,
const bool transpose = true)
{
throw std::runtime_error("Load(): HAS_STB is not defined, "
"so STB is not available and images cannot be loaded!");
matrix = arma::conv_to<arma::Mat<eT>>::from(tmpMatrix);
return true;
}
template<typename eT>
bool Load(const std::vector<std::string>& files,
arma::Mat<eT>& matrix,
ImageInfo& info,
const bool fatal = false,
const bool transpose = true)
{
throw std::runtime_error("Load(): HAS_STB is not defined, "
"so STB is not available and images cannot be loaded!");
}
#endif // HAS_STB.
} // namespace data
} // namespace mlpack
+9 -7
View File
@@ -91,8 +91,6 @@ bool Save(const std::string& filename,
const bool fatal = false,
format f = format::autodetect);
#ifdef HAS_STB
/**
* Save the image file from the given matrix.
*
@@ -107,8 +105,7 @@ template<typename eT>
bool Save(const std::string& filename,
arma::Mat<eT>& matrix,
ImageInfo& info,
const bool fatal = false,
const bool transpose = true);
const bool fatal = false);
/**
* Save the image file from the given matrix.
@@ -124,10 +121,15 @@ template<typename eT>
bool Save(const std::vector<std::string>& files,
arma::Mat<eT>& matrix,
ImageInfo& info,
const bool fatal = false,
const bool transpose = true);
const bool fatal = false);
#endif // HAS_STB.
/**
* Helper function to save files. Implementation in save_image.cpp.
*/
bool SaveImage(const std::string& filename,
arma::Mat<unsigned char>& image,
ImageInfo& info,
const bool fatal = false);
} // namespace data
} // namespace mlpack
+141
View File
@@ -0,0 +1,141 @@
/**
* @file save_image.cpp
* @author Mehul Kumar Nirala
*
* Implementation of image saving functionality via STB.
*/
#include "save.hpp"
#ifdef HAS_STB
#define STB_IMAGE_STATIC
#define STB_IMAGE_IMPLEMENTATION
#include <stb_image.h>
#define STB_IMAGE_WRITE_STATIC
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include <stb_image_write.h>
namespace mlpack {
namespace data {
bool SaveImage(const std::string& filename,
arma::Mat<unsigned char>& image,
ImageInfo& info,
const bool fatal)
{
// Check to see if the file type is supported.
if (!ImageFormatSupported(filename, true))
{
std::ostringstream oss;
oss << "Save(): file type " << Extension(filename) << " not supported.\n";
oss << "Currently image saving supports ";
for (auto extension : saveFileTypes)
oss << ", " << extension;
oss << "." << std::endl;
if (fatal)
{
Log::Fatal << oss.str();
}
else
{
Log::Warn << oss.str();
}
return false;
}
// Ensure the shape of the matrix is correct.
if (image.n_cols > 1)
{
Log::Warn << "Save(): given input image matrix contains more than 1 image."
<< std::endl;
Log::Warn << "Only the first image will be saved!" << std::endl;
}
if (info.Width() * info.Height() * info.Channels() != image.n_elem)
{
Log::Fatal << "data::Save(): The given image dimensions do not match the "
<< "dimensions of the matrix to be saved!" << std::endl;
}
bool status = false;
unsigned char* imageMem = image.memptr();
if ("png" == Extension(filename))
{
status = stbi_write_png(filename.c_str(), info.Width(), info.Height(),
info.Channels(), imageMem, info.Width() * info.Channels());
}
else if ("bmp" == Extension(filename))
{
status = stbi_write_bmp(filename.c_str(), info.Width(), info.Height(),
info.Channels(), imageMem);
}
else if ("tga" == Extension(filename))
{
status = stbi_write_tga(filename.c_str(), info.Width(), info.Height(),
info.Channels(), imageMem);
}
else if ("hdr" == Extension(filename))
{
// We'll have to convert to float...
arma::fmat tmpImage = arma::conv_to<arma::fmat>::from(image);
status = stbi_write_hdr(filename.c_str(), info.Width(), info.Height(),
info.Channels(), tmpImage.memptr());
}
else if ("jpg" == Extension(filename))
{
status = stbi_write_jpg(filename.c_str(), info.Width(), info.Height(),
info.Channels(), imageMem, info.Quality());
}
if (!status)
{
if (fatal)
{
Log::Fatal << "Save(): error saving image to '" << filename << "'."
<< std::endl;
}
else
{
Log::Warn << "Save(): error saving image to '" << filename << "'."
<< std::endl;
}
}
return status;
}
} // namespace data
} // namespace mlpack
#else
namespace mlpack {
namespace data {
bool SaveImage(const std::string& /* filename */,
arma::Mat<unsigned char>& /* image */,
ImageInfo& /* info */,
const bool fatal)
{
if (fatal)
{
Log::Fatal << "Save(): mlpack was not compiled with STB support, so images "
<< "cannot be saved!" << std::endl;
}
else
{
Log::Warn << "Save(): mlpack was not compiled with STB support, so images "
<< "cannot be saved!" << std::endl;
}
return false;
}
} // namespace data
} // namespace mlpack
#endif
+29 -113
View File
@@ -283,86 +283,25 @@ bool Save(const std::string& filename,
}
}
#ifdef HAS_STB
// Image saving API.
/**
* Save the given image to the given filename.
*
* @param filename Filename to save to.
* @param matrix Matrix containing image to be saved.
* @param info Information about the image (width/height/channels/etc.).
* @param fatal Whether an exception should be thrown on save failure.
*/
template<typename eT>
bool Save(const std::string& filename,
arma::Mat<eT>& matrix,
ImageInfo& info,
const bool fatal,
const bool transpose)
const bool fatal)
{
Timer::Start("saving_image");
// We transpose by default. So, un-transpose if necessary.
if (!transpose)
matrix = arma::trans(matrix);
arma::Mat<unsigned char> tmpMatrix =
arma::conv_to<arma::Mat<unsigned char>>::from(matrix);
int tempWidth, tempHeight, tempChannels, tempQuality;
tempWidth = info.Width();
tempHeight = info.Height();
tempChannels = info.Channels();
tempQuality = info.Quality();
if (!ImageFormatSupported(filename, true))
{
std::ostringstream oss;
oss << "File type " << Extension(filename) << " not supported.\n";
oss << "Currently it supports ";
for (auto extension : saveFileTypes)
oss << ", " << extension;
oss << std::endl;
throw std::runtime_error(oss.str());
return false;
}
if (matrix.n_cols > 1)
{
std::cout << "Input Matrix contains more than 1 image." << std::endl;
std::cout << "Only the firstimage will be saved!" << std::endl;
}
stbi_flip_vertically_on_write(transpose);
bool status = false;
try
{
unsigned char* image = matrix.memptr();
if ("png" == Extension(filename))
{
status = stbi_write_png(filename.c_str(), tempWidth, tempHeight,
tempChannels, image, tempWidth * tempChannels);
}
else if ("bmp" == Extension(filename))
{
status = stbi_write_bmp(filename.c_str(), tempWidth, tempHeight,
tempChannels, image);
}
else if ("tga" == Extension(filename))
{
status = stbi_write_tga(filename.c_str(), tempWidth, tempHeight,
tempChannels, image);
}
else if ("hdr" == Extension(filename))
{
status = stbi_write_hdr(filename.c_str(), tempWidth, tempHeight,
tempChannels, reinterpret_cast<float*>(image));
}
else if ("jpg" == Extension(filename))
{
status = stbi_write_jpg(filename.c_str(), tempWidth, tempHeight,
tempChannels, image, tempQuality);
}
}
catch (std::exception& e)
{
Timer::Stop("saving_image");
if (fatal)
Log::Fatal << e.what() << std::endl;
Log::Warn << e.what() << std::endl;
return false;
}
Timer::Stop("saving_image");
return status;
// Call out to .cpp implementation.
return SaveImage(filename, tmpMatrix, info, fatal);
}
// Image saving API for multiple files.
@@ -370,59 +309,36 @@ template<typename eT>
bool Save(const std::vector<std::string>& files,
arma::Mat<eT>& matrix,
ImageInfo& info,
const bool fatal,
const bool transpose)
const bool fatal)
{
if (files.size() == 0)
{
std::ostringstream oss;
oss << "Files vector is empty." << std::endl;
if (fatal)
{
Log::Fatal << "Save(): vector of image files is empty; nothing to save."
<< std::endl;
}
else
{
Log::Warn << "Save(): vector of image files is empty; nothing to save."
<< std::endl;
}
throw std::runtime_error(oss.str());
return false;
}
// We transpose by default. So, un-transpose if necessary.
if (!transpose)
matrix = arma::trans(matrix);
arma::Mat<unsigned char> img;
bool status = Save(files[0], img, info, fatal, transpose);
bool status = true;
// Decide matrix dimension using the image height and width.
matrix.set_size(info.Width() * info.Height() * info.Channels(), files.size());
matrix.col(0) = img;
for (size_t i = 1; i < files.size() ; i++)
for (size_t i = 0; i < files.size() ; i++)
{
arma::Mat<unsigned char> colImg(matrix.colptr(i), matrix.n_rows, 1,
arma::Mat<eT> colImg(matrix.colptr(i), matrix.n_rows, 1,
false, true);
status &= Save(files[i], colImg, info, fatal, transpose);
status &= Save(files[i], colImg, info, fatal);
}
return status;
}
#else
template<typename eT>
bool Save(const std::string& filename,
arma::Mat<eT>& matrix,
ImageInfo& info,
const bool fatal = false,
const bool transpose = true)
{
throw std::runtime_error("Save(): HAS_STB is not defined, "
"so STB is not available and images cannot be saved!");
}
template<typename eT>
bool Save(const std::vector<std::string>& files,
arma::Mat<eT>& matrix,
ImageInfo& info,
const bool fatal = false,
const bool transpose = true)
{
throw std::runtime_error("Save(): HAS_STB is not defined, "
"so STB is not available and images cannot be saved!");
}
#endif // HAS_STB.
} // namespace data
} // namespace mlpack
@@ -52,10 +52,7 @@ class ZCAWhitening
*
* @param eps Regularization parameter.
*/
ZCAWhitening(double eps = 0.00005)
{
pca = new data::PCAWhitening(eps);
}
ZCAWhitening(double eps = 0.00005) : pca(eps) { }
/**
* Function to fit features, to find out the min max and scale.
@@ -65,7 +62,7 @@ class ZCAWhitening
template<typename MatType>
void Fit(const MatType& input)
{
pca->Fit(input);
pca.Fit(input);
}
/**
@@ -77,8 +74,8 @@ class ZCAWhitening
template<typename MatType>
void Transform(const MatType& input, MatType& output)
{
pca->Transform(input, output);
output = pca->EigenVectors() * output;
pca.Transform(input, output);
output = pca.EigenVectors() * output;
}
/**
@@ -90,19 +87,19 @@ class ZCAWhitening
template<typename MatType>
void InverseTransform(const MatType& input, MatType& output)
{
output = inv(pca->EigenVectors()) * arma::diagmat(arma::sqrt(
pca->EigenValues())) * inv(pca->EigenVectors().t()) * input;
output = (output.each_col() + pca->ItemMean());
output = inv(pca.EigenVectors()) * arma::diagmat(arma::sqrt(
pca.EigenValues())) * inv(pca.EigenVectors().t()) * input;
output = (output.each_col() + pca.ItemMean());
}
//! Get the mean row vector.
const arma::vec& ItemMean() const { return pca->ItemMean(); }
const arma::vec& ItemMean() const { return pca.ItemMean(); }
//! Get the eigenvalues vector.
const arma::vec& EigenValues() const { return pca->EigenValues(); }
const arma::vec& EigenValues() const { return pca.EigenValues(); }
//! Get the eigenvector.
const arma::mat& EigenVectors() const { return pca->EigenVectors(); }
const arma::mat& EigenVectors() const { return pca.EigenVectors(); }
//! Get the regularization parameter.
double Epsilon() const { return pca->Epsilon(); }
double Epsilon() const { return pca.Epsilon(); }
template<typename Archive>
void serialize(Archive& ar, const unsigned int /* version */)
@@ -112,7 +109,7 @@ class ZCAWhitening
private:
// A pointer to PcaWhitening Class.
PCAWhitening* pca;
PCAWhitening pca;
}; // class ZCAWhitening
} // namespace data
+23 -11
View File
@@ -24,7 +24,8 @@ namespace data {
/**
* The class translates a set of strings into numbers using various encoding
* algorithms.
* algorithms. The encoder writes data either in the column-major order or
* in the row-major order depending on the output data type.
*
* @tparam EncodingPolicyType Type of the encoding algorithm itself.
* @tparam DictionaryType Type of the dictionary.
@@ -90,11 +91,17 @@ class StringEncoding
void Clear();
/**
* Encode the given text and write the result to the given output.
* Encode the given text and write the result to the given output. The encoder
* writes data in the column-major order or in the row-major order depending
* on the output data type.
*
* If the output type is either arma::mat or arma::sp_mat then the function
* writes it in the column-major order. If the output type is 2D std::vector
* then the function writes it in the row major order.
*
* @tparam OutputType Type of the output container. The function supports
* the following types: arma::mat, arma::sp_mat,
* std::vector<std::vector<size_t>>.
* std::vector<std::vector<>>.
* @tparam TokenizerType Type of the tokenizer.
*
* @param input Corpus of text to encode.
@@ -132,11 +139,16 @@ class StringEncoding
private:
/**
* A helper function to encode the given text and write the result to
* the given output.
* the given output. The encoder writes data in the column-major order or
* in the row-major order depending on the output data type.
*
* If the output type is either arma::mat or arma::sp_mat then the function
* writes it in the column-major order. If the output type is 2D std::vector
* then the function writes it in the row major order.
*
* @tparam OutputType Type of the output container. The function supports
* the following types: arma::mat, arma::sp_mat,
* std::vector<std::vector<size_t>>.
* std::vector<std::vector<>>.
* @tparam TokenizerType Type of the tokenizer.
* @tparam PolicyType The type of the encoding policy. It has to be
* equal to EncodingPolicyType.
@@ -153,9 +165,7 @@ class StringEncoding
* 2. IsTokenEmpty() that accepts a token and returns true if the given
* token is empty.
*/
template<typename OutputType,
typename TokenizerType,
typename PolicyType>
template<typename OutputType, typename TokenizerType, typename PolicyType>
void EncodeHelper(const std::vector<std::string>& input,
OutputType& output,
const TokenizerType& tokenizer,
@@ -164,11 +174,13 @@ class StringEncoding
/**
* A helper function to encode the given text and write the result to
* the given output. This is an optimized overload for policies that support
* the one pass encoding algorithm.
* the one pass encoding algorithm. The encoder writes data in the row-major
* order.
*
* @tparam TokenizerType Type of the tokenizer.
* @tparam PolicyType The type of the encoding policy. It has to be
* equal to EncodingPolicyType.
* @tparam ElemType Type of the output values.
*
* @param input Corpus of text to encode.
* @param output Output container to store the result.
@@ -182,9 +194,9 @@ class StringEncoding
* 2. IsTokenEmpty() that accepts a token and returns true if the given
* token is empty.
*/
template<typename TokenizerType, typename PolicyType>
template<typename TokenizerType, typename PolicyType, typename ElemType>
void EncodeHelper(const std::vector<std::string>& input,
std::vector<std::vector<size_t>>& output,
std::vector<std::vector<ElemType>>& output,
const TokenizerType& tokenizer,
PolicyType& policy,
typename std::enable_if<StringEncodingPolicyTraits<
+11 -4
View File
@@ -107,10 +107,12 @@ EncodeHelper(const std::vector<std::string>& input,
{
size_t numColumns = 0;
policy.Reset();
// The first pass adds the extracted tokens to the dictionary.
for (const std::string& line : input)
for (size_t i = 0; i < input.size(); i++)
{
boost::string_view strView(line);
boost::string_view strView(input[i]);
auto token = tokenizer(strView);
static_assert(
@@ -127,9 +129,12 @@ EncodeHelper(const std::vector<std::string>& input,
if (!dictionary.HasToken(token))
dictionary.AddToken(std::move(token));
policy.PreprocessToken(i, numTokens, dictionary.Value(token));
token = tokenizer(strView);
numTokens++;
}
numColumns = std::max(numColumns, numTokens);
}
@@ -152,15 +157,17 @@ EncodeHelper(const std::vector<std::string>& input,
}
template<typename EncodingPolicyType, typename DictionaryType>
template<typename TokenizerType, typename PolicyType>
template<typename TokenizerType, typename PolicyType, typename ElemType>
void StringEncoding<EncodingPolicyType, DictionaryType>::
EncodeHelper(const std::vector<std::string>& input,
std::vector<std::vector<size_t>>& output,
std::vector<std::vector<ElemType>>& output,
const TokenizerType& tokenizer,
PolicyType& policy,
typename std::enable_if<StringEncodingPolicyTraits<
PolicyType>::onePassEncoding>::type*)
{
policy.Reset();
// The loop below extracts the tokens and writes the encoded values
// at once.
for (size_t i = 0; i < input.size(); i++)
@@ -1,8 +1,10 @@
# Define the files that we need to compile.
# Anything not in this list will not be compiled into mlpack.
set(SOURCES
bag_of_words_encoding_policy.hpp
dictionary_encoding_policy.hpp
policy_traits.hpp
tf_idf_encoding_policy.hpp
)
# add directory name to sources
@@ -0,0 +1,171 @@
/**
* @file bag_of_words_encoding_policy.hpp
* @author Jeffin Sam
* @author Mikhail Lozhnikov
*
* Definition of the BagOfWordsEncodingPolicy class.
*
* mlpack is free software; you may redistribute it and/or modify it under the
* terms of the 3-clause BSD license. You should have received a copy of the
* 3-clause BSD license along with mlpack. If not, see
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
*/
#ifndef MLPACK_CORE_DATA_STR_ENCODING_POLICIES_BAG_OF_WORDS_ENCODING_POLICY_HPP
#define MLPACK_CORE_DATA_STR_ENCODING_POLICIES_BAG_OF_WORDS_ENCODING_POLICY_HPP
#include <mlpack/prereqs.hpp>
#include <mlpack/core/data/string_encoding_policies/policy_traits.hpp>
#include <mlpack/core/data/string_encoding.hpp>
namespace mlpack {
namespace data {
/**
* Definition of the BagOfWordsEncodingPolicy class.
*
* BagOfWords is used as a helper class for StringEncoding. The encoder maps
* each dataset item to a vector of size N, where N is equal to the total unique
* number of tokens. The i-th coordinate of the output vector is equal to
* the number of times when the i-th token occurs in the corresponding dataset
* item. The order in which the tokens are labeled is defined by the dictionary
* used by the StringEncoding class. The encoder writes data either in the
* column-major order or in the row-major order depending on the output data
* type.
*/
class BagOfWordsEncodingPolicy
{
public:
/**
* Clear the necessary internal variables.
*/
static void Reset()
{
// Nothing to do.
}
/**
* The function initializes the output matrix. The encoder writes data
* in the column-major order.
*
* @tparam MatType The output matrix type.
*
* @param output Output matrix to store the encoded results (sp_mat or mat).
* @param datasetSize The number of strings in the input dataset.
* @param maxNumTokens The maximum number of tokens in the strings of the
* input dataset (not used).
* @param dictionarySize The size of the dictionary.
*/
template<typename MatType>
static void InitMatrix(MatType& output,
const size_t datasetSize,
const size_t /* maxNumTokens */,
const size_t dictionarySize)
{
output.zeros(dictionarySize, datasetSize);
}
/**
* The function initializes the output matrix. The encoder writes data
* in the row-major order.
*
* Overloaded function to save the result in vector<vector<ElemType>>.
*
* @tparam ElemType Type of the output values.
*
* @param output Output matrix to store the encoded results.
* @param datasetSize The number of strings in the input dataset.
* @param maxNumTokens The maximum number of tokens in the strings of the
* input dataset (not used).
* @param dictionarySize The size of the dictionary.
*/
template<typename ElemType>
static void InitMatrix(std::vector<std::vector<ElemType>>& output,
const size_t datasetSize,
const size_t /* maxNumTokens */,
const size_t dictionarySize)
{
output.resize(datasetSize, std::vector<ElemType>(dictionarySize));
}
/**
* The function performs the bag of words encoding algorithm i.e. it writes
* the encoded token to the output. The encoder writes data in the
* column-major order.
*
* @tparam MatType The output matrix type.
*
* @param output Output matrix to store the encoded results (sp_mat or mat).
* @param value The encoded token.
* @param line The line number at which the encoding is performed.
* @param index The token index in the line.
*/
template<typename MatType>
static void Encode(MatType& output,
const size_t value,
const size_t line,
const size_t /* index */)
{
// The labels are assigned sequentially starting from one.
output(value - 1, line) += 1;
}
/**
* The function performs the bag of words encoding algorithm i.e. it writes
* the encoded token to the output. The encoder writes data in the
* row-major order.
*
* Overloaded function to accept vector<vector<ElemType>> as the output
* type.
*
* @tparam ElemType Type of the output values.
*
* @param output Output matrix to store the encoded results.
* @param value The encoded token.
* @param line The line number at which the encoding is performed.
* @param index The line token number at which the encoding is performed.
*/
template<typename ElemType>
static void Encode(std::vector<std::vector<ElemType>>& output,
const size_t value,
const size_t line,
const size_t /* index */)
{
// The labels are assigned sequentially starting from one.
output[line][value - 1] += 1;
}
/**
* The function is not used by the bag of words encoding policy.
*
* @param line The line number at which the encoding is performed.
* @param index The token sequence number in the line.
* @param value The encoded token.
*/
static void PreprocessToken(size_t /* line */,
size_t /* index */,
size_t /* value */)
{ }
/**
* Serialize the class to the given archive.
*/
template<typename Archive>
void serialize(Archive& /* ar */, const unsigned int /* version */)
{
// Nothing to serialize.
}
};
/**
* A convenient alias for the StringEncoding class with BagOfWordsEncodingPolicy
* and the default dictionary for the given token type.
*
* @tparam TokenType Type of the tokens.
*/
template<typename TokenType>
using BagOfWordsEncoding = StringEncoding<BagOfWordsEncodingPolicy,
StringEncodingDictionary<TokenType>>;
} // namespace data
} // namespace mlpack
#endif
@@ -25,65 +25,92 @@ namespace data {
* The encoder assigns a positive integer number to each unique token and treats
* the dataset as categorical. The numbers are assigned sequentially starting
* from one. The order in which the tokens are labeled is defined by
* the dictionary used by the StringEncoding class.
* the dictionary used by the StringEncoding class. The encoder writes data
* either in the column-major order or in the row-major order depending on
* the output data type.
*/
class DictionaryEncodingPolicy
{
public:
/**
* The function initializes the output matrix.
*
* @tparam MatType The output matrix type.
*
* @param output Output matrix to store the encoded results (sp_mat or mat).
* @param datasetSize The number of strings in the input dataset.
* @param maxNumTokens The maximum number of tokens in the strings of the
input dataset.
* @param dictionarySize The size of the dictionary (not used).
*/
* Clear the necessary internal variables.
*/
static void Reset()
{
// Nothing to do.
}
/**
* The function initializes the output matrix. The encoder writes data
* in the column-major order.
*
* @tparam MatType The output matrix type.
*
* @param output Output matrix to store the encoded results (sp_mat or mat).
* @param datasetSize The number of strings in the input dataset.
* @param maxNumTokens The maximum number of tokens in the strings of the
* input dataset.
* @param dictionarySize The size of the dictionary (not used).
*/
template<typename MatType>
static void InitMatrix(MatType& output,
const size_t datasetSize,
const size_t maxNumTokens,
const size_t /*dictionarySize*/)
const size_t /* dictionarySize */)
{
output.zeros(datasetSize, maxNumTokens);
output.zeros(maxNumTokens, datasetSize);
}
/**
* The function performs the dictionary encoding algorithm i.e. it writes
* the encoded token to the ouput.
*
* @tparam MatType The output matrix type.
*
* @param output Output matrix to store the encoded results (sp_mat or mat).
* @param value The encoded token.
* @param row The row number at which the encoding is performed.
* @param col The token index in the row.
*/
/**
* The function performs the dictionary encoding algorithm i.e. it writes
* the encoded token to the output. The encoder writes data in the
* column-major order.
*
* @tparam MatType The output matrix type.
*
* @param output Output matrix to store the encoded results (sp_mat or mat).
* @param value The encoded token.
* @param line The line number at which the encoding is performed.
* @param index The token index in the line.
*/
template<typename MatType>
static void Encode(MatType& output,
const size_t value,
const size_t row,
const size_t col)
const size_t line,
const size_t index)
{
output(row, col) = value;
output(index, line) = value;
}
/**
/**
* The function performs the dictionary encoding algorithm i.e. it writes
* the encoded token to the ouput. This is an overload function which saves
* the result into the given vector to avoid padding.
* the encoded token to the output. This is an overloaded function which saves
* the result into the given vector to avoid padding. The encoder writes data
* in the row-major order.
*
* @param output Output vector to store the encoded results.
* @tparam ElemType Type of the output values.
*
* @param output Output vector to store the encoded line.
* @param value The encoded token.
*/
static void Encode(std::vector<size_t>& output,
const size_t value)
template<typename ElemType>
static void Encode(std::vector<ElemType>& output, size_t value)
{
output.push_back(value);
}
/**
* The function is not used by the dictionary encoding policy.
*
* @param line The line number at which the encoding is performed.
* @param index The token sequence number in the line.
* @param value The encoded token.
*/
static void PreprocessToken(const size_t /* line */,
const size_t /* index */,
const size_t /* value */)
{ }
/**
* Serialize the class to the given archive.
*/
@@ -0,0 +1,349 @@
/**
* @file tf_idf_encoding_policy.hpp
* @author Jeffin Sam
* @author Mikhail Lozhnikov
*
* Definition of the TfIdfEncodingPolicy class.
*
* mlpack is free software; you may redistribute it and/or modify it under the
* terms of the 3-clause BSD license. You should have received a copy of the
* 3-clause BSD license along with mlpack. If not, see
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
*/
#ifndef MLPACK_CORE_DATA_STRING_ENCODING_POLICIES_TF_IDF_ENCODING_POLICY_HPP
#define MLPACK_CORE_DATA_STRING_ENCODING_POLICIES_TF_IDF_ENCODING_POLICY_HPP
#include <mlpack/prereqs.hpp>
#include <mlpack/core/data/string_encoding_policies/policy_traits.hpp>
#include <mlpack/core/data/string_encoding.hpp>
namespace mlpack {
namespace data {
/**
* Definition of the TfIdfEncodingPolicy class. TfIdfEncodingPolicy is used
* as a helper class for StringEncoding.
*
* Tf-idf is a weighting scheme that takes into account the importance of
* encoded tokens. The tf-idf statistics is equal to term frequency (tf)
* multiplied by inverse document frequency (idf).
* The encoder assigns the corresponding tf-idf value to each token. The order
* in which the tokens are labeled is defined by the dictionary used by the
* StringEncoding class. The encoder writes data either in the column-major
* order or in the row-major order depending on the output data type.
*/
class TfIdfEncodingPolicy
{
public:
/**
* Enum class used to identify the type of the term frequency statistics.
*
* The present implementation supports the following types:
* BINARY Term frequency equals 1 if the row contains the encoded
* token and 0 otherwise.
* RAW_COUNT Term frequency equals the number of times when the encoded
* token occurs in the row.
* TERM_FREQUENCY Term frequency equals the number of times when the encoded
* token occurs in the row divided by the total number of
* tokens in the row.
* SUBLINEAR_TF Term frequency equals \f$ 1 + log(rawCount), \f$ where
* rawCount is equal to the number of times when the encoded
* token occurs in the row.
*/
enum class TfTypes
{
BINARY,
RAW_COUNT,
TERM_FREQUENCY,
SUBLINEAR_TF,
};
/**
* Construct this using the term frequency type and the inverse document
* frequency type.
*
* @param tfType Type of the term frequency statistics.
* @param smoothIdf Used to indicate whether to use smooth idf or not.
* If idf is smooth it's calculated by the following formula:
* \f$ idf(T) = \log \frac{1 + N}{1 + df(T)} + 1, \f$ where
* \f$ N \f$ is the total number of strings in the document,
* \f$ T \f$ is the current encoded token, \f$ df(T) \f$
* equals the number of strings which contain the token.
* If idf isn't smooth then the following rule applies:
* \f$ idf(T) = \log \frac{N}{df(T)} + 1. \f$
*/
TfIdfEncodingPolicy(const TfTypes tfType = TfTypes::RAW_COUNT,
const bool smoothIdf = true) :
tfType(tfType),
smoothIdf(smoothIdf)
{ }
/**
* Clear the necessary internal variables.
*/
void Reset()
{
tokensFrequences.clear();
numContainingStrings.clear();
linesSizes.clear();
}
/**
* The function initializes the output matrix. The encoder writes data
* in the row-major order.
*
* @tparam MatType The output matrix type.
*
* @param output Output matrix to store the encoded results (sp_mat or mat).
* @param datasetSize The number of strings in the input dataset.
* @param maxNumTokens The maximum number of tokens in the strings of the
* input dataset (not used).
* @param dictionarySize The size of the dictionary.
*/
template<typename MatType>
static void InitMatrix(MatType& output,
const size_t datasetSize,
const size_t /* maxNumTokens */,
const size_t dictionarySize)
{
output.zeros(dictionarySize, datasetSize);
}
/**
* The function initializes the output matrix. The encoder writes data
* in the row-major order.
*
* Overloaded function to save the result in vector<vector<ElemType>>.
*
* @tparam ElemType Type of the output values.
*
* @param output Output matrix to store the encoded results.
* @param datasetSize The number of strings in the input dataset.
* @param maxNumTokens The maximum number of tokens in the strings of the
* input dataset (not used).
* @param dictionarySize The size of the dictionary.
*/
template<typename ElemType>
static void InitMatrix(std::vector<std::vector<ElemType>>& output,
const size_t datasetSize,
const size_t /* maxNumTokens */,
const size_t dictionarySize)
{
output.resize(datasetSize, std::vector<ElemType>(dictionarySize));
}
/**
* The function performs the TfIdf encoding algorithm i.e. it writes
* the encoded token to the output. The encoder writes data in the
* column-major order.
*
* @tparam MatType The output matrix type.
*
* @param output Output matrix to store the encoded results (sp_mat or mat).
* @param value The encoded token.
* @param line The line number at which the encoding is performed.
* @param index The token index in the line.
*/
template<typename MatType>
void Encode(MatType& output,
const size_t value,
const size_t line,
const size_t /* index */)
{
const typename MatType::elem_type tf =
TermFrequency<typename MatType::elem_type>(
tokensFrequences[line][value], linesSizes[line]);
const typename MatType::elem_type idf =
InverseDocumentFrequency<typename MatType::elem_type>(
output.n_cols, numContainingStrings[value]);
output(value - 1, line) = tf * idf;
}
/**
* The function performs the TfIdf encoding algorithm i.e. it writes
* the encoded token to the output. The encoder writes data in the
* row-major order.
*
* Overloaded function to accept vector<vector<ElemType>> as the output
* type.
*
* @tparam ElemType Type of the output values.
*
* @param output Output matrix to store the encoded results.
* @param value The encoded token.
* @param line The line number at which the encoding is performed.
* @param index The token index in the line.
*/
template<typename ElemType>
void Encode(std::vector<std::vector<ElemType>>& output,
const size_t value,
const size_t line,
const size_t /* index */)
{
const ElemType tf = TermFrequency<ElemType>(
tokensFrequences[line][value], linesSizes[line]);
const ElemType idf = InverseDocumentFrequency<ElemType>(
output.size(), numContainingStrings[value]);
output[line][value - 1] = tf * idf;
}
/*
* The function calculates the necessary statistics for the purpose
* of the tf-idf algorithm during the first pass through the dataset.
*
* @param line The line number at which the encoding is performed.
* @param index The token sequence number in the line.
* @param value The encoded token.
*/
void PreprocessToken(const size_t line,
const size_t /* index */,
const size_t value)
{
if (line >= tokensFrequences.size())
{
linesSizes.resize(line + 1);
tokensFrequences.resize(line + 1);
}
tokensFrequences[line][value]++;
if (tokensFrequences[line][value] == 1)
numContainingStrings[value]++;
linesSizes[line]++;
}
//! Return token frequencies.
const std::vector<std::unordered_map<size_t, size_t>>&
TokensFrequences() const { return tokensFrequences; }
//! Modify token frequencies.
std::vector<std::unordered_map<size_t, size_t>>& TokensFrequences()
{
return tokensFrequences;
}
//! Get the number of containing strings depending on the given token.
const std::unordered_map<size_t, size_t>& NumContainingStrings() const
{
return numContainingStrings;
}
//! Modify the number of containing strings depending on the given token.
std::unordered_map<size_t, size_t>& NumContainingStrings()
{
return numContainingStrings;
}
//! Return the lines sizes.
const std::vector<size_t>& LinesSizes() const { return linesSizes; }
//! Modify the lines sizes.
std::vector<size_t>& LinesSizes() { return linesSizes; }
//! Return the term frequency type.
TfTypes TfType() const { return tfType; }
//! Modify the term frequency type.
TfTypes& TfType() { return tfType; }
//! Determine the idf algorithm type (whether it's smooth or not).
bool SmoothIdf() const { return smoothIdf; }
//! Modify the idf algorithm type (whether it's smooth or not).
bool& SmoothIdf() { return smoothIdf; }
/**
* Serialize the class to the given archive.
*/
template<typename Archive>
void serialize(Archive& ar, const unsigned int /* version */)
{
ar & BOOST_SERIALIZATION_NVP(tfType);
ar & BOOST_SERIALIZATION_NVP(smoothIdf);
}
private:
/**
* The function calculates the term frequency statistics.
*
* @tparam ValueType Type of the returned value.
*
* @param numOccurrences The number of the given token occurrences in
* the line.
* @param numTokens The total number of tokens in the line.
*/
template<typename ValueType>
ValueType TermFrequency(const size_t numOccurrences,
const size_t numTokens)
{
switch (tfType)
{
case TfTypes::BINARY:
return numOccurrences > 0;
case TfTypes::RAW_COUNT:
return numOccurrences;
case TfTypes::TERM_FREQUENCY:
return static_cast<ValueType>(numOccurrences) / numTokens;
case TfTypes::SUBLINEAR_TF:
return std::log(static_cast<ValueType>(numOccurrences)) + 1;
default:
Log::Fatal << "Incorrect term frequency type!";
return 0;
}
}
/**
* The function calculates the inverse document frequency statistics.
*
* @tparam ValueType Type of the returned value.
*
* @param totalNumLines The total number of strings in the input dataset.
* @param numOccurrences The number of strings in the input dataset
* which contain the current token.
*/
template<typename ValueType>
ValueType InverseDocumentFrequency(const size_t totalNumLines,
const size_t numOccurrences)
{
if (smoothIdf)
{
return std::log(static_cast<ValueType>(totalNumLines + 1) /
(1 + numOccurrences)) + 1.0;
}
else
{
return std::log(static_cast<ValueType>(totalNumLines) /
numOccurrences) + 1.0;
}
}
private:
//! Used to store the total number of tokens for each line.
std::vector<std::unordered_map<size_t, size_t>> tokensFrequences;
/**
* Used to store the number of strings which contain a token depending
* on the given token.
*/
std::unordered_map<size_t, size_t> numContainingStrings;
//! Used to store the number of tokens in each line.
std::vector<size_t> linesSizes;
//! Type of the term frequency scheme.
TfTypes tfType;
//! Indicates whether the idf scheme is smooth or not.
bool smoothIdf;
};
/**
* A convenient alias for the StringEncoding class with TfIdfEncodingPolicy
* and the default dictionary for the given token type.
*
* @tparam TokenType Type of the tokens.
*/
template<typename TokenType>
using TfIdfEncoding = StringEncoding<TfIdfEncodingPolicy,
StringEncodingDictionary<TokenType>>;
} // namespace data
} // namespace mlpack
#endif
+2 -2
View File
@@ -11,8 +11,8 @@
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
*/
#include "gamma_distribution.hpp"
// This will include digamma and trigamma.
#include <mlpack/core/boost_backport/boost_backport_math.hpp>
#include <boost/math/special_functions/trigamma.hpp>
#include <boost/math/special_functions/polygamma.hpp>
using namespace mlpack;
using namespace mlpack::distribution;
+5 -1
View File
@@ -49,7 +49,7 @@ IPMetric<KernelType>::~IPMetric()
template<typename KernelType>
IPMetric<KernelType>::IPMetric(const IPMetric& other) :
kernel(other.kernel),
kernel(!other.kernelOwner ? other.kernel : new KernelType(*other.kernel)),
kernelOwner(other.kernelOwner)
{
// Nothing to do.
@@ -90,7 +90,11 @@ void IPMetric<KernelType>::serialize(Archive& ar,
// If we're loading, we need to allocate space for the kernel, and we will own
// the kernel.
if (Archive::is_loading::value)
{
if (kernelOwner)
delete kernel;
kernelOwner = true;
}
ar & BOOST_SERIALIZATION_NVP(kernel);
}
+1 -1
View File
@@ -63,7 +63,7 @@ template<int TPower, bool TTakeRoot = true>
class LMetric
{
public:
/***
/**
* Default constructor does nothing, but is required to satisfy the Metric
* policy.
*/
@@ -1,4 +1,4 @@
/***
/**
* @file mahalanobis_distance.hpp
* @author Ryan Curtin
*
@@ -1,4 +1,4 @@
/***
/**
* @file mahalanobis_distance_impl.hpp
* @author Ryan Curtin
*
@@ -80,6 +80,9 @@ template<typename TMetricType, typename ElemType>
HollowBallBound<TMetricType, ElemType>& HollowBallBound<TMetricType, ElemType>::
operator=(const HollowBallBound& other)
{
if (ownsMetric)
delete metric;
radii = other.radii;
center = other.center;
hollowCenter = other.hollowCenter;
+2 -2
View File
@@ -124,7 +124,7 @@ class PrefixedOutStream
private:
/**
* Conducts the base logic required in all the operator << overloads. Mostly
* just a good idea to reduce copy-pasta.
* just a good idea to reduce copy-paste.
*
* This overload is for non-Armadillo objects, which need special handling
* during printing.
@@ -138,7 +138,7 @@ class PrefixedOutStream
/**
* Conducts the base logic required in all the operator << overloads. Mostly
* just a good idea to reduce copy-pasta.
* just a good idea to reduce copy-paste.
*
* This overload is for Armadillo objects, which need special handling during
* printing.
+34 -2
View File
@@ -24,6 +24,7 @@
#include "init_rules/network_init.hpp"
#include <mlpack/methods/ann/layer/layer_types.hpp>
#include <mlpack/methods/ann/layer/layer.hpp>
#include <mlpack/methods/ann/layer/layer_traits.hpp>
#include <mlpack/methods/ann/init_rules/random_init.hpp>
#include <ensmallen.hpp>
@@ -72,10 +73,41 @@ class BRNN
BRNN(const size_t rho,
const bool single = false,
OutputLayerType outputLayer = OutputLayerType(),
MergeLayerType mergeLayer = MergeLayerType(),
MergeOutputType mergeOutput = MergeOutputType(),
MergeLayerType* mergeLayer = new MergeLayerType(),
MergeOutputType* mergeOutput = new MergeOutputType(),
InitializationRuleType initializeRule = InitializationRuleType());
~BRNN();
/**
* Check if the optimizer has MaxIterations() parameter, if it does
* then check if it's value is less than the number of datapoints
* in the dataset.
*
* @tparam OptimizerType Type of optimizer to use to train the model.
* @param optimizer optimizer used in the training process.
* @param samples Number of datapoints in the dataset.
*/
template<typename OptimizerType>
typename std::enable_if<
HasMaxIterations<OptimizerType, size_t&(OptimizerType::*)()>
::value, void>::type
WarnMessageMaxIterations(OptimizerType& optimizer, size_t samples) const;
/**
* Check if the optimizer has MaxIterations() parameter, if it
* doesn't then simply return from the function.
*
* @tparam OptimizerType Type of optimizer to use to train the model.
* @param optimizer optimizer used in the training process.
* @param samples Number of datapoints in the dataset.
*/
template<typename OptimizerType>
typename std::enable_if<
!HasMaxIterations<OptimizerType, size_t&(OptimizerType::*)()>
::value, void>::type
WarnMessageMaxIterations(OptimizerType& optimizer, size_t samples) const;
/**
* Train the bidirectional recurrent neural network on the given input data
* using the given optimizer.
+154 -91
View File
@@ -39,13 +39,13 @@ BRNN<OutputLayerType, MergeLayerType, MergeOutputType,
const size_t rho,
const bool single,
OutputLayerType outputLayer,
MergeLayerType mergeLayer,
MergeOutputType mergeOutput,
MergeLayerType* mergeLayer,
MergeOutputType* mergeOutput,
InitializationRuleType initializeRule) :
rho(rho),
outputLayer(std::move(outputLayer)),
mergeLayer(new MergeLayerType(mergeLayer)),
mergeOutput(new MergeOutputType(mergeOutput)),
mergeLayer(mergeLayer),
mergeOutput(mergeOutput),
initializeRule(std::move(initializeRule)),
inputSize(0),
outputSize(0),
@@ -60,6 +60,61 @@ BRNN<OutputLayerType, MergeLayerType, MergeOutputType,
/* Nothing to do here. */
}
template<typename OutputLayerType, typename MergeLayerType,
typename MergeOutputType, typename InitializationRuleType,
typename... CustomLayers>
BRNN<OutputLayerType, MergeLayerType, MergeOutputType,
InitializationRuleType, CustomLayers...>::~BRNN()
{
// Remove the last layers from the forward and backward RNNs, as they are held
// in mergeLayer. So, when we use DeleteVisitor with mergeLayer, those two
// layers will be properly (and not doubly) freed.
forwardRNN.network.pop_back();
backwardRNN.network.pop_back();
// Clean up layers that we allocated.
boost::apply_visitor(DeleteVisitor(), mergeLayer);
boost::apply_visitor(DeleteVisitor(), mergeOutput);
}
template<typename OutputLayerType, typename MergeLayerType,
typename MergeOutputType, typename InitializationRuleType,
typename... CustomLayers>
template<typename OptimizerType>
typename std::enable_if<
HasMaxIterations<OptimizerType, size_t&(OptimizerType::*)()>
::value, void>::type
BRNN<OutputLayerType, MergeLayerType, MergeOutputType,
InitializationRuleType, CustomLayers...>::WarnMessageMaxIterations
(OptimizerType& optimizer, size_t samples) const
{
if (optimizer.MaxIterations() < samples &&
optimizer.MaxIterations() != 0)
{
Log::Warn << "The optimizer's maximum number of iterations "
<< "is less than the size of the dataset; the "
<< "optimizer will not pass over the entire "
<< "dataset. To fix this, modify the maximum "
<< "number of iterations to be at least equal "
<< "to the number of points of your dataset "
<< "(" << samples << ")." << std::endl;
}
}
template<typename OutputLayerType, typename MergeLayerType,
typename MergeOutputType, typename InitializationRuleType,
typename... CustomLayers>
template<typename OptimizerType>
typename std::enable_if<
!HasMaxIterations<OptimizerType, size_t&(OptimizerType::*)()>
::value, void>::type
BRNN<OutputLayerType, MergeLayerType, MergeOutputType,
InitializationRuleType, CustomLayers...>::WarnMessageMaxIterations
(OptimizerType& optimizer, size_t samples) const
{
return;
}
template<typename OutputLayerType, typename MergeLayerType,
typename MergeOutputType, typename InitializationRuleType,
typename... CustomLayers>
@@ -83,6 +138,8 @@ double BRNN<OutputLayerType, MergeLayerType, MergeOutputType,
ResetParameters();
}
WarnMessageMaxIterations<OptimizerType>(optimizer, this->predictors.n_cols);
// Train the model.
Timer::Start("BRNN_optimization");
const double out = optimizer.Optimize(*this, parameter);
@@ -117,6 +174,8 @@ double BRNN<OutputLayerType, MergeLayerType, MergeOutputType,
OptimizerType optimizer;
WarnMessageMaxIterations<OptimizerType>(optimizer, this->predictors.n_cols);
// Train the model.
const double out = optimizer.Optimize(*this, parameter);
@@ -166,34 +225,34 @@ void BRNN<OutputLayerType, MergeLayerType, MergeOutputType,
size_t(predictors.n_cols - begin));
for (size_t seqNum = 0; seqNum < rho; ++seqNum)
{
forwardRNN.Forward(std::move(arma::mat(
forwardRNN.Forward(arma::mat(
predictors.slice(seqNum).colptr(begin),
predictors.n_rows, effectiveBatchSize, false, true)));
predictors.n_rows, effectiveBatchSize, false, true));
backwardRNN.Forward(std::move(arma::mat(
predictors.slice(rho - seqNum - 1).colptr(begin),
predictors.n_rows, effectiveBatchSize, false, true)));
boost::apply_visitor(SaveOutputParameterVisitor(
std::move(results1)), forwardRNN.network.back());
boost::apply_visitor(SaveOutputParameterVisitor(
std::move(results2)), backwardRNN.network.back());
boost::apply_visitor(SaveOutputParameterVisitor(results1),
forwardRNN.network.back());
boost::apply_visitor(SaveOutputParameterVisitor(results2),
backwardRNN.network.back());
}
reverse(results1.begin(), results1.end());
// Forward outputs from both RNN's through merge layer for each time step.
for (size_t seqNum = 0; seqNum < rho; ++seqNum)
{
boost::apply_visitor(LoadOutputParameterVisitor(
std::move(results1)), forwardRNN.network.back());
boost::apply_visitor(LoadOutputParameterVisitor(
std::move(results2)), backwardRNN.network.back());
boost::apply_visitor(LoadOutputParameterVisitor(results1),
forwardRNN.network.back());
boost::apply_visitor(LoadOutputParameterVisitor(results2),
backwardRNN.network.back());
boost::apply_visitor(ForwardVisitor(std::move(input),
std::move(boost::apply_visitor(outputParameterVisitor, mergeLayer))),
boost::apply_visitor(ForwardVisitor(input,
boost::apply_visitor(outputParameterVisitor, mergeLayer)),
mergeLayer);
boost::apply_visitor(ForwardVisitor(
std::move(boost::apply_visitor(outputParameterVisitor, mergeLayer)),
std::move(boost::apply_visitor(outputParameterVisitor, mergeOutput))),
boost::apply_visitor(outputParameterVisitor, mergeLayer),
boost::apply_visitor(outputParameterVisitor, mergeOutput)),
mergeOutput);
results.slice(seqNum).submat(0, begin, results.n_rows - 1, begin +
effectiveBatchSize - 1) =
@@ -243,17 +302,17 @@ double BRNN<OutputLayerType, MergeLayerType, MergeOutputType,
std::vector<arma::mat> results1, results2;
for (size_t seqNum = 0; seqNum < rho; ++seqNum)
{
forwardRNN.Forward(std::move(arma::mat(
forwardRNN.Forward(arma::mat(
predictors.slice(seqNum).colptr(begin),
predictors.n_rows, batchSize, false, true)));
backwardRNN.Forward(std::move(arma::mat(
predictors.n_rows, batchSize, false, true));
backwardRNN.Forward(arma::mat(
predictors.slice(rho - seqNum - 1).colptr(begin),
predictors.n_rows, batchSize, false, true)));
predictors.n_rows, batchSize, false, true));
boost::apply_visitor(SaveOutputParameterVisitor(
std::move(results1)), forwardRNN.network.back());
boost::apply_visitor(SaveOutputParameterVisitor(
std::move(results2)), backwardRNN.network.back());
boost::apply_visitor(SaveOutputParameterVisitor(results1),
forwardRNN.network.back());
boost::apply_visitor(SaveOutputParameterVisitor(results2),
backwardRNN.network.back());
}
if (outputSize == 0)
{
@@ -271,22 +330,22 @@ double BRNN<OutputLayerType, MergeLayerType, MergeOutputType,
{
responseSeq = seqNum;
}
boost::apply_visitor(LoadOutputParameterVisitor(
std::move(results1)), forwardRNN.network.back());
boost::apply_visitor(LoadOutputParameterVisitor(
std::move(results2)), backwardRNN.network.back());
boost::apply_visitor(LoadOutputParameterVisitor(results1),
forwardRNN.network.back());
boost::apply_visitor(LoadOutputParameterVisitor(results2),
backwardRNN.network.back());
boost::apply_visitor(ForwardVisitor(std::move(input),
std::move(boost::apply_visitor(outputParameterVisitor, mergeLayer))),
boost::apply_visitor(ForwardVisitor(input,
boost::apply_visitor(outputParameterVisitor, mergeLayer)),
mergeLayer);
boost::apply_visitor(ForwardVisitor(
std::move(boost::apply_visitor(outputParameterVisitor, mergeLayer)),
std::move(boost::apply_visitor(outputParameterVisitor, mergeOutput))),
mergeOutput);
performance += outputLayer.Forward(std::move(
boost::apply_visitor(outputParameterVisitor, mergeLayer),
boost::apply_visitor(outputParameterVisitor, mergeOutput)),
std::move(arma::mat(responses.slice(responseSeq).colptr(begin),
responses.n_rows, batchSize, false, true)));
mergeOutput);
performance += outputLayer.Forward(
boost::apply_visitor(outputParameterVisitor, mergeOutput),
arma::mat(responses.slice(responseSeq).colptr(begin),
responses.n_rows, batchSize, false, true));
}
return performance;
}
@@ -361,24 +420,24 @@ EvaluateWithGradient(const arma::mat& /* parameters */,
std::vector<arma::mat> results1, results2;
for (size_t seqNum = 0; seqNum < rho; ++seqNum)
{
forwardRNN.Forward(std::move(arma::mat(
forwardRNN.Forward(arma::mat(
predictors.slice(seqNum).colptr(begin),
predictors.n_rows, batchSize, false, true)));
backwardRNN.Forward(std::move(arma::mat(
predictors.n_rows, batchSize, false, true));
backwardRNN.Forward(arma::mat(
predictors.slice(rho - seqNum - 1).colptr(begin),
predictors.n_rows, batchSize, false, true)));
predictors.n_rows, batchSize, false, true));
for (size_t l = 0; l < networkSize; ++l)
{
boost::apply_visitor(SaveOutputParameterVisitor(
std::move(forwardRNNOutputParameter)), forwardRNN.network[l]);
forwardRNNOutputParameter), forwardRNN.network[l]);
boost::apply_visitor(SaveOutputParameterVisitor(
std::move(backwardRNNOutputParameter)), backwardRNN.network[l]);
backwardRNNOutputParameter), backwardRNN.network[l]);
}
boost::apply_visitor(SaveOutputParameterVisitor(
std::move(results1)), forwardRNN.network.back());
boost::apply_visitor(SaveOutputParameterVisitor(
std::move(results2)), backwardRNN.network.back());
boost::apply_visitor(SaveOutputParameterVisitor(results1),
forwardRNN.network.back());
boost::apply_visitor(SaveOutputParameterVisitor(results2),
backwardRNN.network.back());
}
if (outputSize == 0)
{
@@ -410,18 +469,18 @@ EvaluateWithGradient(const arma::mat& /* parameters */,
responseSeq = seqNum;
}
boost::apply_visitor(LoadOutputParameterVisitor(
std::move(results1)), forwardRNN.network.back());
results1), forwardRNN.network.back());
boost::apply_visitor(LoadOutputParameterVisitor(
std::move(results2)), backwardRNN.network.back());
boost::apply_visitor(ForwardVisitor(std::move(input),
std::move(boost::apply_visitor(outputParameterVisitor, mergeLayer))),
results2), backwardRNN.network.back());
boost::apply_visitor(ForwardVisitor(input,
boost::apply_visitor(outputParameterVisitor, mergeLayer)),
mergeLayer);
boost::apply_visitor(ForwardVisitor(
std::move(boost::apply_visitor(outputParameterVisitor, mergeLayer)),
std::move(results.slice(seqNum))), mergeOutput);
performance += outputLayer.Forward(std::move(results.slice(seqNum)),
std::move(arma::mat(responses.slice(responseSeq).colptr(begin),
responses.n_rows, batchSize, false, true)));
boost::apply_visitor(outputParameterVisitor, mergeLayer),
results.slice(seqNum)), mergeOutput);
performance += outputLayer.Forward(results.slice(seqNum),
arma::mat(responses.slice(responseSeq).colptr(begin),
responses.n_rows, batchSize, false, true));
}
// Calculate and storing delta parameters from output for t = 1 to T.
@@ -436,25 +495,25 @@ EvaluateWithGradient(const arma::mat& /* parameters */,
}
else if (single && seqNum == 0)
{
outputLayer.Backward(std::move(results.slice(seqNum)),
std::move(arma::mat(responses.slice(0).colptr(begin),
responses.n_rows, batchSize, false, true)), std::move(error));
outputLayer.Backward(results.slice(seqNum),
arma::mat(responses.slice(0).colptr(begin),
responses.n_rows, batchSize, false, true), error);
}
else
{
outputLayer.Backward(std::move(results.slice(seqNum)),
std::move(arma::mat(responses.slice(seqNum).colptr(begin),
responses.n_rows, batchSize, false, true)), std::move(error));
outputLayer.Backward(results.slice(seqNum),
arma::mat(responses.slice(seqNum).colptr(begin),
responses.n_rows, batchSize, false, true), error);
}
boost::apply_visitor(BackwardVisitor(std::move(results.slice(seqNum)),
std::move(error), std::move(delta)), mergeOutput);
boost::apply_visitor(BackwardVisitor(results.slice(seqNum), error, delta),
mergeOutput);
allDelta.push_back(arma::mat(delta));
}
// BPTT ForwardRNN from t = T to 1.
totalGradient = arma::mat(gradient.memptr(),
parameter.n_elem/2, 1, false, false);
parameter.n_elem / 2, 1, false, false);
forwardGradient.zeros();
forwardRNN.ResetGradients(forwardGradient);
@@ -467,32 +526,32 @@ EvaluateWithGradient(const arma::mat& /* parameters */,
for (size_t l = 0; l < networkSize; ++l)
{
boost::apply_visitor(LoadOutputParameterVisitor(
std::move(forwardRNNOutputParameter)),
forwardRNNOutputParameter),
forwardRNN.network[networkSize - 1 - l]);
}
boost::apply_visitor(BackwardVisitor(std::move(boost::apply_visitor(
outputParameterVisitor, forwardRNN.network.back())),
std::move(allDelta[rho - seqNum - 1]), std::move(delta), 0),
boost::apply_visitor(BackwardVisitor(boost::apply_visitor(
outputParameterVisitor, forwardRNN.network.back()),
allDelta[rho - seqNum - 1], delta, 0),
mergeLayer);
for (size_t i = 2; i < networkSize; ++i)
{
boost::apply_visitor(BackwardVisitor(
std::move(boost::apply_visitor(outputParameterVisitor,
forwardRNN.network[networkSize - i])),
std::move(boost::apply_visitor(deltaVisitor,
forwardRNN.network[networkSize - i + 1])), std::move(
boost::apply_visitor(outputParameterVisitor,
forwardRNN.network[networkSize - i]),
boost::apply_visitor(deltaVisitor,
forwardRNN.network[networkSize - i]))),
forwardRNN.network[networkSize - i + 1]),
boost::apply_visitor(deltaVisitor,
forwardRNN.network[networkSize - i])),
forwardRNN.network[networkSize - i]);
}
forwardRNN.Gradient(std::move(
forwardRNN.Gradient(
arma::mat(predictors.slice(rho - seqNum - 1).colptr(begin),
predictors.n_rows, batchSize, false, true)));
predictors.n_rows, batchSize, false, true));
boost::apply_visitor(GradientVisitor(
std::move(boost::apply_visitor(outputParameterVisitor,
forwardRNN.network[networkSize - 2])),
std::move(allDelta[rho - seqNum - 1]), 0), mergeLayer);
boost::apply_visitor(outputParameterVisitor,
forwardRNN.network[networkSize - 2]),
allDelta[rho - seqNum - 1], 0), mergeLayer);
totalGradient += forwardGradient;
}
@@ -506,31 +565,31 @@ EvaluateWithGradient(const arma::mat& /* parameters */,
for (size_t l = 0; l < networkSize; ++l)
{
boost::apply_visitor(LoadOutputParameterVisitor(
std::move(backwardRNNOutputParameter)),
backwardRNNOutputParameter),
backwardRNN.network[networkSize - 1 - l]);
}
boost::apply_visitor(BackwardVisitor(std::move(
boost::apply_visitor(BackwardVisitor(
boost::apply_visitor(outputParameterVisitor,
backwardRNN.network.back())),
std::move(allDelta[seqNum]), std::move(delta), 1), mergeLayer);
backwardRNN.network.back()),
allDelta[seqNum], delta, 1), mergeLayer);
for (size_t i = 2; i < networkSize; ++i)
{
boost::apply_visitor(BackwardVisitor(
std::move(boost::apply_visitor(outputParameterVisitor,
backwardRNN.network[networkSize - i])), std::move(boost::apply_visitor(
deltaVisitor, backwardRNN.network[networkSize - i + 1])), std::move(
boost::apply_visitor(outputParameterVisitor,
backwardRNN.network[networkSize - i]), boost::apply_visitor(
deltaVisitor, backwardRNN.network[networkSize - i + 1]),
boost::apply_visitor(deltaVisitor,
backwardRNN.network[networkSize - i]))),
backwardRNN.network[networkSize - i])),
backwardRNN.network[networkSize - i]);
}
backwardRNN.Gradient(std::move(
backwardRNN.Gradient(
arma::mat(predictors.slice(seqNum).colptr(begin),
predictors.n_rows, batchSize, false, true)));
predictors.n_rows, batchSize, false, true));
boost::apply_visitor(GradientVisitor(
std::move(boost::apply_visitor(outputParameterVisitor,
backwardRNN.network[networkSize - 2])),
std::move(allDelta[seqNum]), 1), mergeLayer);
allDelta[seqNum], 1), mergeLayer);
totalGradient += backwardGradient;
}
return performance;
@@ -592,6 +651,8 @@ void BRNN<OutputLayerType, MergeLayerType, MergeOutputType,
{
if (!reset)
{
// TODO: what if we call ResetParameters() multiple times? Do we have to
// remove any existing mergeLayer?
boost::apply_visitor(AddVisitor<CustomLayers...>(
forwardRNN.network.back()), mergeLayer);
boost::apply_visitor(AddVisitor<CustomLayers...>(
@@ -665,6 +726,8 @@ void BRNN<OutputLayerType, MergeLayerType, MergeOutputType,
ar & BOOST_SERIALIZATION_NVP(parameter);
ar & BOOST_SERIALIZATION_NVP(backwardRNN);
ar & BOOST_SERIALIZATION_NVP(forwardRNN);
// TODO: are there more parameters to be serialized?
}
} // namespace ann
@@ -60,7 +60,7 @@ class BernoulliDistribution
* @param eps The minimum value used for computing logarithms and
* denominators.
*/
BernoulliDistribution(const DataType&& param,
BernoulliDistribution(const DataType& param,
const bool applyLogistic = true,
const double eps = 1e-10);
@@ -69,7 +69,7 @@ class BernoulliDistribution
*
* @param observation The observation matrix.
*/
double Probability(const DataType&& observation) const
double Probability(const DataType& observation) const
{
return std::exp(LogProbability(observation));
}
@@ -79,7 +79,7 @@ class BernoulliDistribution
*
* @param observation The observation matrix.
*/
double LogProbability(const DataType&& observation) const;
double LogProbability(const DataType& observation) const;
/**
* Stores the gradient of the log probabilities of the observations in the
@@ -88,7 +88,7 @@ class BernoulliDistribution
* @param observation The observation matrix.
* @param output The output matrix where the gradients are stored.
*/
void LogProbBackward(const DataType&& observation, DataType&& output) const;
void LogProbBackward(const DataType& observation, DataType& output) const;
/**
* Return a matrix of randomly generated samples according to the
@@ -28,7 +28,7 @@ BernoulliDistribution<DataType>::BernoulliDistribution() :
template<typename DataType>
BernoulliDistribution<DataType>::BernoulliDistribution(
const DataType&& param,
const DataType& param,
const bool applyLogistic,
const double eps) :
logits(param),
@@ -36,7 +36,9 @@ BernoulliDistribution<DataType>::BernoulliDistribution(
eps(eps)
{
if (applyLogistic)
{
LogisticFunction::Fn(logits, probability);
}
else
{
probability = arma::mat(logits.memptr(), logits.n_rows,
@@ -58,7 +60,7 @@ DataType BernoulliDistribution<DataType>::Sample() const
template<typename DataType>
double BernoulliDistribution<DataType>::LogProbability(
const DataType&& observation) const
const DataType& observation) const
{
return arma::accu(arma::log(probability + eps) % observation +
arma::log(1 - probability + eps) % (1 - observation)) /
@@ -67,7 +69,7 @@ double BernoulliDistribution<DataType>::LogProbability(
template<typename DataType>
void BernoulliDistribution<DataType>::LogProbBackward(
const DataType&& observation, DataType&& output) const
const DataType& observation, DataType& output) const
{
if (!applyLogistic)
{
+49 -11
View File
@@ -30,6 +30,7 @@
#include <mlpack/methods/ann/layer/layer_types.hpp>
#include <mlpack/methods/ann/layer/layer.hpp>
#include <mlpack/methods/ann/init_rules/random_init.hpp>
#include <mlpack/methods/ann/layer/layer_traits.hpp>
#include <ensmallen.hpp>
namespace mlpack {
@@ -82,6 +83,35 @@ class FFN
//! Destructor to release allocated memory.
~FFN();
/**
* Check if the optimizer has MaxIterations() parameter, if it does
* then check if it's value is less than the number of datapoints
* in the dataset.
*
* @tparam OptimizerType Type of optimizer to use to train the model.
* @param optimizer optimizer used in the training process.
* @param samples Number of datapoints in the dataset.
*/
template<typename OptimizerType>
typename std::enable_if<
HasMaxIterations<OptimizerType, size_t&(OptimizerType::*)()>
::value, void>::type
WarnMessageMaxIterations(OptimizerType& optimizer, size_t samples) const;
/**
* Check if the optimizer has MaxIterations() parameter, if it
* doesn't then simply return from the function.
*
* @tparam OptimizerType Type of optimizer to use to train the model.
* @param optimizer optimizer used in the training process.
* @param samples Number of datapoints in the dataset.
*/
template<typename OptimizerType>
typename std::enable_if<
!HasMaxIterations<OptimizerType, size_t&(OptimizerType::*)()>
::value, void>::type
WarnMessageMaxIterations(OptimizerType& optimizer, size_t samples) const;
/**
* Train the feedforward network on the given input data using the given
* optimizer.
@@ -153,7 +183,9 @@ class FFN
* @param predictors Input variables.
* @param responses Target outputs for input variables.
*/
double Evaluate(arma::mat predictors, arma::mat responses);
template<typename PredictorsType, typename ResponsesType>
double Evaluate(const PredictorsType& predictors,
const ResponsesType& responses);
/**
* Evaluate the feedforward network with the given parameters. This function
@@ -313,7 +345,8 @@ class FFN
* @param inputs The input data.
* @param results The predicted results.
*/
void Forward(arma::mat inputs, arma::mat& results);
template<typename PredictorsType, typename ResponsesType>
void Forward(const PredictorsType& inputs, ResponsesType& results);
/**
* Perform a partial forward pass of the data.
@@ -326,8 +359,9 @@ class FFN
* @param begin The index of the first layer.
* @param end The index of the last layer.
*/
void Forward(arma::mat inputs,
arma::mat& results,
template<typename PredictorsType, typename ResponsesType>
void Forward(const PredictorsType& inputs ,
ResponsesType& results,
const size_t begin,
const size_t end);
@@ -342,7 +376,12 @@ class FFN
* @param gradients Computed gradients.
* @return Training error of the current pass.
*/
double Backward(arma::mat targets, arma::mat& gradients);
template<typename PredictorsType,
typename TargetsType,
typename GradientsType>
double Backward(const PredictorsType& inputs,
const TargetsType& targets,
GradientsType& gradients);
private:
// Helper functions.
@@ -352,7 +391,8 @@ class FFN
*
* @param input Data sequence to compute probabilities for.
*/
void Forward(arma::mat&& input);
template<typename InputType>
void Forward(const InputType& input);
/**
* Prepare the network for the given data.
@@ -373,7 +413,8 @@ class FFN
* Iterate through all layer modules and update the the gradient using the
* layer defined optimizer.
*/
void Gradient(arma::mat&& input);
template<typename InputType>
void Gradient(const InputType& input);
/**
* Reset the module status by setting the current deterministic parameter
@@ -427,9 +468,6 @@ class FFN
//! The current error for the backward pass.
arma::mat error;
//! THe current input of the forward/backward pass.
arma::mat currentInput;
//! Locally-stored delta visitor.
DeltaVisitor deltaVisitor;
@@ -496,7 +534,7 @@ template<typename OutputLayerType,
struct version<
mlpack::ann::FFN<OutputLayerType, InitializationRuleType, CustomLayer...>>
{
BOOST_STATIC_CONSTANT(int, value = 1);
BOOST_STATIC_CONSTANT(int, value = 2);
};
} // namespace serialization
+114 -64
View File
@@ -41,7 +41,7 @@ FFN<OutputLayerType, InitializationRuleType, CustomLayers...>::FFN(
numFunctions(0),
deterministic(true)
{
/* Nothing to do here */
/* Nothing to do here. */
}
template<typename OutputLayerType, typename InitializationRuleType,
@@ -67,6 +67,41 @@ void FFN<OutputLayerType, InitializationRuleType, CustomLayers...>::ResetData(
ResetParameters();
}
template<typename OutputLayerType, typename InitializationRuleType,
typename... CustomLayers>
template<typename OptimizerType>
typename std::enable_if<
HasMaxIterations<OptimizerType, size_t&(OptimizerType::*)()>
::value, void>::type
FFN<OutputLayerType, InitializationRuleType, CustomLayers...>::
WarnMessageMaxIterations(OptimizerType& optimizer, size_t samples) const
{
if (optimizer.MaxIterations() < samples &&
optimizer.MaxIterations() != 0)
{
Log::Warn << "The optimizer's maximum number of iterations "
<< "is less than the size of the dataset; the "
<< "optimizer will not pass over the entire "
<< "dataset. To fix this, modify the maximum "
<< "number of iterations to be at least equal "
<< "to the number of points of your dataset "
<< "(" << samples << ")." << std::endl;
}
}
template<typename OutputLayerType, typename InitializationRuleType,
typename... CustomLayers>
template<typename OptimizerType>
typename std::enable_if<
!HasMaxIterations<OptimizerType, size_t&(OptimizerType::*)()>
::value, void>::type
FFN<OutputLayerType, InitializationRuleType, CustomLayers...>::
WarnMessageMaxIterations(OptimizerType& /* optimizer */, size_t /* samples */)
const
{
return;
}
template<typename OutputLayerType, typename InitializationRuleType,
typename... CustomLayers>
template<typename OptimizerType, typename... CallbackTypes>
@@ -78,6 +113,8 @@ double FFN<OutputLayerType, InitializationRuleType, CustomLayers...>::Train(
{
ResetData(std::move(predictors), std::move(responses));
WarnMessageMaxIterations<OptimizerType>(optimizer, this->predictors.n_cols);
// Train the model.
Timer::Start("ffn_optimization");
const double out = optimizer.Optimize(*this, parameter, callbacks...);
@@ -100,6 +137,8 @@ double FFN<OutputLayerType, InitializationRuleType, CustomLayers...>::Train(
OptimizerType optimizer;
WarnMessageMaxIterations<OptimizerType>(optimizer, this->predictors.n_cols);
// Train the model.
Timer::Start("ffn_optimization");
const double out = optimizer.Optimize(*this, parameter, callbacks...);
@@ -112,8 +151,9 @@ double FFN<OutputLayerType, InitializationRuleType, CustomLayers...>::Train(
template<typename OutputLayerType, typename InitializationRuleType,
typename... CustomLayers>
template<typename PredictorsType, typename ResponsesType>
void FFN<OutputLayerType, InitializationRuleType, CustomLayers...>::Forward(
arma::mat inputs, arma::mat& results)
const PredictorsType& inputs, ResponsesType& results)
{
if (parameter.is_empty())
ResetParameters();
@@ -124,25 +164,28 @@ void FFN<OutputLayerType, InitializationRuleType, CustomLayers...>::Forward(
ResetDeterministic();
}
currentInput = std::move(inputs);
Forward(std::move(currentInput));
Forward(inputs);
results = boost::apply_visitor(outputParameterVisitor, network.back());
}
template<typename OutputLayerType, typename InitializationRuleType,
typename... CustomLayers>
template<typename PredictorsType, typename ResponsesType>
void FFN<OutputLayerType, InitializationRuleType, CustomLayers...>::Forward(
arma::mat inputs, arma::mat& results, const size_t begin, const size_t end)
const PredictorsType& inputs,
ResponsesType& results,
const size_t begin,
const size_t end)
{
boost::apply_visitor(ForwardVisitor(std::move(inputs), std::move(
boost::apply_visitor(outputParameterVisitor, network[begin]))),
boost::apply_visitor(ForwardVisitor(inputs,
boost::apply_visitor(outputParameterVisitor, network[begin])),
network[begin]);
for (size_t i = 1; i < end - begin + 1; ++i)
{
boost::apply_visitor(ForwardVisitor(std::move(boost::apply_visitor(
outputParameterVisitor, network[begin + i - 1])), std::move(
boost::apply_visitor(outputParameterVisitor, network[begin + i]))),
boost::apply_visitor(ForwardVisitor(boost::apply_visitor(
outputParameterVisitor, network[begin + i - 1]),
boost::apply_visitor(outputParameterVisitor, network[begin + i])),
network[begin + i]);
}
@@ -151,25 +194,28 @@ void FFN<OutputLayerType, InitializationRuleType, CustomLayers...>::Forward(
template<typename OutputLayerType, typename InitializationRuleType,
typename... CustomLayers>
template<typename PredictorsType, typename TargetsType, typename GradientsType>
double FFN<OutputLayerType, InitializationRuleType, CustomLayers...>::Backward(
arma::mat targets, arma::mat& gradients)
const PredictorsType& inputs,
const TargetsType& targets,
GradientsType& gradients)
{
double res = outputLayer.Forward(std::move(boost::apply_visitor(
outputParameterVisitor, network.back())), std::move(targets));
double res = outputLayer.Forward(boost::apply_visitor(
outputParameterVisitor, network.back()), targets);
for (size_t i = 0; i < network.size(); ++i)
{
res += boost::apply_visitor(lossVisitor, network[i]);
}
outputLayer.Backward(std::move(boost::apply_visitor(outputParameterVisitor,
network.back())), std::move(targets), std::move(error));
outputLayer.Backward(boost::apply_visitor(outputParameterVisitor,
network.back()), targets, error);
gradients = arma::zeros<arma::mat>(parameter.n_rows, parameter.n_cols);
Backward();
ResetGradients(gradients);
Gradient(std::move(currentInput));
Gradient(inputs);
return res;
}
@@ -189,8 +235,7 @@ void FFN<OutputLayerType, InitializationRuleType, CustomLayers...>::Predict(
}
arma::mat resultsTemp;
Forward(std::move(arma::mat(predictors.colptr(0),
predictors.n_rows, 1, false, true)));
Forward(arma::mat(predictors.colptr(0), predictors.n_rows, 1, false, true));
resultsTemp = boost::apply_visitor(outputParameterVisitor,
network.back()).col(0);
@@ -199,8 +244,7 @@ void FFN<OutputLayerType, InitializationRuleType, CustomLayers...>::Predict(
for (size_t i = 1; i < predictors.n_cols; i++)
{
Forward(std::move(arma::mat(predictors.colptr(i),
predictors.n_rows, 1, false, true)));
Forward(arma::mat(predictors.colptr(i), predictors.n_rows, 1, false, true));
resultsTemp = boost::apply_visitor(outputParameterVisitor,
network.back());
@@ -210,8 +254,9 @@ void FFN<OutputLayerType, InitializationRuleType, CustomLayers...>::Predict(
template<typename OutputLayerType, typename InitializationRuleType,
typename... CustomLayers>
template<typename PredictorsType, typename ResponsesType>
double FFN<OutputLayerType, InitializationRuleType, CustomLayers...>::Evaluate(
arma::mat predictors, arma::mat responses)
const PredictorsType& predictors, const ResponsesType& responses)
{
if (parameter.is_empty())
ResetParameters();
@@ -222,10 +267,10 @@ double FFN<OutputLayerType, InitializationRuleType, CustomLayers...>::Evaluate(
ResetDeterministic();
}
Forward(std::move(predictors));
Forward(predictors);
double res = outputLayer.Forward(std::move(boost::apply_visitor(
outputParameterVisitor, network.back())), std::move(responses));
double res = outputLayer.Forward(boost::apply_visitor(
outputParameterVisitor, network.back()), responses);
for (size_t i = 0; i < network.size(); ++i)
{
@@ -264,10 +309,10 @@ double FFN<OutputLayerType, InitializationRuleType, CustomLayers...>::Evaluate(
ResetDeterministic();
}
Forward(std::move(predictors.cols(begin, begin + batchSize - 1)));
Forward(predictors.cols(begin, begin + batchSize - 1));
double res = outputLayer.Forward(
std::move(boost::apply_visitor(outputParameterVisitor, network.back())),
std::move(responses.cols(begin, begin + batchSize - 1)));
boost::apply_visitor(outputParameterVisitor, network.back()),
responses.cols(begin, begin + batchSize - 1));
for (size_t i = 0; i < network.size(); ++i)
{
@@ -325,10 +370,10 @@ EvaluateWithGradient(const arma::mat& /* parameters */,
ResetDeterministic();
}
Forward(std::move(predictors.cols(begin, begin + batchSize - 1)));
Forward(predictors.cols(begin, begin + batchSize - 1));
double res = outputLayer.Forward(
std::move(boost::apply_visitor(outputParameterVisitor, network.back())),
std::move(responses.cols(begin, begin + batchSize - 1)));
boost::apply_visitor(outputParameterVisitor, network.back()),
responses.cols(begin, begin + batchSize - 1));
for (size_t i = 0; i < network.size(); ++i)
{
@@ -336,13 +381,13 @@ EvaluateWithGradient(const arma::mat& /* parameters */,
}
outputLayer.Backward(
std::move(boost::apply_visitor(outputParameterVisitor, network.back())),
std::move(responses.cols(begin, begin + batchSize - 1)),
std::move(error));
boost::apply_visitor(outputParameterVisitor, network.back()),
responses.cols(begin, begin + batchSize - 1),
error);
Backward();
ResetGradients(gradient);
Gradient(std::move(predictors.cols(begin, begin + batchSize - 1)));
Gradient(predictors.cols(begin, begin + batchSize - 1));
return res;
}
@@ -396,18 +441,19 @@ void FFN<OutputLayerType, InitializationRuleType,
size_t offset = 0;
for (size_t i = 0; i < network.size(); ++i)
{
offset += boost::apply_visitor(GradientSetVisitor(std::move(gradient),
offset), network[i]);
offset += boost::apply_visitor(GradientSetVisitor(gradient, offset),
network[i]);
}
}
template<typename OutputLayerType, typename InitializationRuleType,
typename... CustomLayers>
template<typename InputType>
void FFN<OutputLayerType, InitializationRuleType,
CustomLayers...>::Forward(arma::mat&& input)
CustomLayers...>::Forward(const InputType& input)
{
boost::apply_visitor(ForwardVisitor(std::move(input), std::move(
boost::apply_visitor(outputParameterVisitor, network.front()))),
boost::apply_visitor(ForwardVisitor(input,
boost::apply_visitor(outputParameterVisitor, network.front())),
network.front());
if (!reset)
@@ -434,9 +480,9 @@ void FFN<OutputLayerType, InitializationRuleType,
boost::apply_visitor(SetInputHeightVisitor(height), network[i]);
}
boost::apply_visitor(ForwardVisitor(std::move(boost::apply_visitor(
outputParameterVisitor, network[i - 1])), std::move(
boost::apply_visitor(outputParameterVisitor, network[i]))), network[i]);
boost::apply_visitor(ForwardVisitor(boost::apply_visitor(
outputParameterVisitor, network[i - 1]),
boost::apply_visitor(outputParameterVisitor, network[i])), network[i]);
if (!reset)
{
@@ -462,37 +508,38 @@ template<typename OutputLayerType, typename InitializationRuleType,
typename... CustomLayers>
void FFN<OutputLayerType, InitializationRuleType, CustomLayers...>::Backward()
{
boost::apply_visitor(BackwardVisitor(std::move(boost::apply_visitor(
outputParameterVisitor, network.back())), std::move(error), std::move(
boost::apply_visitor(deltaVisitor, network.back()))), network.back());
boost::apply_visitor(BackwardVisitor(boost::apply_visitor(
outputParameterVisitor, network.back()), error,
boost::apply_visitor(deltaVisitor, network.back())), network.back());
for (size_t i = 2; i < network.size(); ++i)
{
boost::apply_visitor(BackwardVisitor(std::move(boost::apply_visitor(
outputParameterVisitor, network[network.size() - i])), std::move(
boost::apply_visitor(deltaVisitor, network[network.size() - i + 1])),
std::move(boost::apply_visitor(deltaVisitor,
network[network.size() - i]))), network[network.size() - i]);
boost::apply_visitor(BackwardVisitor(boost::apply_visitor(
outputParameterVisitor, network[network.size() - i]),
boost::apply_visitor(deltaVisitor, network[network.size() - i + 1]),
boost::apply_visitor(deltaVisitor, network[network.size() - i])),
network[network.size() - i]);
}
}
template<typename OutputLayerType, typename InitializationRuleType,
typename... CustomLayers>
template<typename InputType>
void FFN<OutputLayerType, InitializationRuleType,
CustomLayers...>::Gradient(arma::mat&& input)
CustomLayers...>::Gradient(const InputType& input)
{
boost::apply_visitor(GradientVisitor(std::move(input), std::move(
boost::apply_visitor(deltaVisitor, network[1]))), network.front());
boost::apply_visitor(GradientVisitor(input,
boost::apply_visitor(deltaVisitor, network[1])), network.front());
for (size_t i = 1; i < network.size() - 1; ++i)
{
boost::apply_visitor(GradientVisitor(std::move(boost::apply_visitor(
outputParameterVisitor, network[i - 1])), std::move(
boost::apply_visitor(deltaVisitor, network[i + 1]))), network[i]);
boost::apply_visitor(GradientVisitor(boost::apply_visitor(
outputParameterVisitor, network[i - 1]),
boost::apply_visitor(deltaVisitor, network[i + 1])), network[i]);
}
boost::apply_visitor(GradientVisitor(std::move(boost::apply_visitor(
outputParameterVisitor, network[network.size() - 2])), std::move(error)),
boost::apply_visitor(GradientVisitor(boost::apply_visitor(
outputParameterVisitor, network[network.size() - 2]), error),
network[network.size() - 1]);
}
@@ -505,7 +552,13 @@ void FFN<OutputLayerType, InitializationRuleType, CustomLayers...>::serialize(
ar & BOOST_SERIALIZATION_NVP(parameter);
ar & BOOST_SERIALIZATION_NVP(width);
ar & BOOST_SERIALIZATION_NVP(height);
ar & BOOST_SERIALIZATION_NVP(currentInput);
// Early versions used the currentInput member, which is now no longer needed.
if (version < 2)
{
arma::mat currentInput; // Temporary matrix to output.
ar & BOOST_SERIALIZATION_NVP(currentInput);
}
// Earlier versions of the FFN code did not serialize whether or not the model
// was reset.
@@ -535,8 +588,8 @@ void FFN<OutputLayerType, InitializationRuleType, CustomLayers...>::serialize(
size_t offset = 0;
for (size_t i = 0; i < network.size(); ++i)
{
offset += boost::apply_visitor(WeightSetVisitor(std::move(parameter),
offset), network[i]);
offset += boost::apply_visitor(WeightSetVisitor(parameter, offset),
network[i]);
boost::apply_visitor(resetVisitor, network[i]);
}
@@ -562,7 +615,6 @@ void FFN<OutputLayerType, InitializationRuleType,
std::swap(parameter, network.parameter);
std::swap(numFunctions, network.numFunctions);
std::swap(error, network.error);
std::swap(currentInput, network.currentInput);
std::swap(deterministic, network.deterministic);
std::swap(delta, network.delta);
std::swap(inputParameter, network.inputParameter);
@@ -584,7 +636,6 @@ FFN<OutputLayerType, InitializationRuleType, CustomLayers...>::FFN(
parameter(network.parameter),
numFunctions(network.numFunctions),
error(network.error),
currentInput(network.currentInput),
deterministic(network.deterministic),
delta(network.delta),
inputParameter(network.inputParameter),
@@ -613,7 +664,6 @@ FFN<OutputLayerType, InitializationRuleType, CustomLayers...>::FFN(
parameter(std::move(network.parameter)),
numFunctions(network.numFunctions),
error(std::move(network.error)),
currentInput(std::move(network.currentInput)),
deterministic(network.deterministic),
delta(std::move(network.delta)),
inputParameter(std::move(network.inputParameter)),
+1 -1
View File
@@ -289,7 +289,7 @@ class GAN
*
* @param input Sampled noise.
*/
void Forward(arma::mat&& input);
void Forward(const arma::mat& input);
/**
* This function predicts the output of the network on the given input.
+17 -18
View File
@@ -258,28 +258,27 @@ GAN<Model, InitializationRuleType, Noise, PolicyType>::Evaluate(
currentTarget = arma::mat(responses.memptr() + i, 1, batchSize, false,
false);
discriminator.Forward(std::move(currentInput));
discriminator.Forward(currentInput);
double res = discriminator.outputLayer.Forward(
std::move(boost::apply_visitor(
boost::apply_visitor(
outputParameterVisitor,
discriminator.network.back())), std::move(currentTarget));
discriminator.network.back()), currentTarget);
noise.imbue( [&]() { return noiseFunction();} );
generator.Forward(std::move(noise));
generator.Forward(noise);
predictors.cols(numFunctions, numFunctions + batchSize - 1) =
boost::apply_visitor(outputParameterVisitor, generator.network.back());
discriminator.Forward(std::move(predictors.cols(numFunctions,
numFunctions + batchSize - 1)));
discriminator.Forward(predictors.cols(numFunctions,
numFunctions + batchSize - 1));
responses.cols(numFunctions, numFunctions + batchSize - 1) =
arma::zeros(1, batchSize);
currentTarget = arma::mat(responses.memptr() + numFunctions,
1, batchSize, false, false);
res += discriminator.outputLayer.Forward(
std::move(boost::apply_visitor(
outputParameterVisitor,
discriminator.network.back())), std::move(currentTarget));
boost::apply_visitor(outputParameterVisitor,
discriminator.network.back()), currentTarget);
return res;
}
@@ -341,7 +340,7 @@ EvaluateWithGradient(const arma::mat& /* parameters */,
i, gradientDiscriminator, batchSize);
noise.imbue( [&]() { return noiseFunction();} );
generator.Forward(std::move(noise));
generator.Forward(noise);
predictors.cols(numFunctions, numFunctions + batchSize - 1) =
boost::apply_visitor(outputParameterVisitor, generator.network.back());
responses.cols(numFunctions, numFunctions + batchSize - 1) =
@@ -419,18 +418,18 @@ template<
typename PolicyType
>
void GAN<Model, InitializationRuleType, Noise, PolicyType>::Forward(
arma::mat&& input)
const arma::mat& input)
{
if (parameter.is_empty())
{
Reset();
}
generator.Forward(std::move(input));
generator.Forward(input);
arma::mat ganOutput = boost::apply_visitor(outputParameterVisitor,
generator.network.back());
discriminator.Forward(std::move(ganOutput));
discriminator.Forward(ganOutput);
}
template<
@@ -453,7 +452,7 @@ Predict(arma::mat input, arma::mat& output)
ResetDeterministic();
}
Forward(std::move(input));
Forward(input);
output = boost::apply_visitor(outputParameterVisitor,
discriminator.network.back());
@@ -502,8 +501,8 @@ serialize(Archive& ar, const unsigned int /* version */)
size_t offset = 0;
for (size_t i = 0; i < generator.network.size(); ++i)
{
offset += boost::apply_visitor(WeightSetVisitor(std::move(
generator.parameter), offset), generator.network[i]);
offset += boost::apply_visitor(WeightSetVisitor(
generator.parameter, offset), generator.network[i]);
boost::apply_visitor(resetVisitor, generator.network[i]);
}
@@ -511,8 +510,8 @@ serialize(Archive& ar, const unsigned int /* version */)
offset = 0;
for (size_t i = 0; i < discriminator.network.size(); ++i)
{
offset += boost::apply_visitor(WeightSetVisitor(std::move(
discriminator.parameter), offset), discriminator.network[i]);
offset += boost::apply_visitor(WeightSetVisitor(
discriminator.parameter, offset), discriminator.network[i]);
boost::apply_visitor(resetVisitor, discriminator.network[i]);
}
+9 -9
View File
@@ -50,28 +50,28 @@ GAN<Model, InitializationRuleType, Noise, PolicyType>::Evaluate(
currentTarget = arma::mat(responses.memptr() + i, 1, batchSize, false,
false);
discriminator.Forward(std::move(currentInput));
discriminator.Forward(currentInput);
double res = discriminator.outputLayer.Forward(
std::move(boost::apply_visitor(
boost::apply_visitor(
outputParameterVisitor,
discriminator.network.back())), std::move(currentTarget));
discriminator.network.back()), currentTarget);
noise.imbue( [&]() { return noiseFunction();} );
generator.Forward(std::move(noise));
generator.Forward(noise);
predictors.cols(numFunctions, numFunctions + batchSize - 1) =
boost::apply_visitor(outputParameterVisitor, generator.network.back());
discriminator.Forward(std::move(predictors.cols(numFunctions,
numFunctions + batchSize - 1)));
discriminator.Forward(predictors.cols(numFunctions,
numFunctions + batchSize - 1));
responses.cols(numFunctions, numFunctions + batchSize - 1) =
-arma::ones(1, batchSize);
currentTarget = arma::mat(responses.memptr() + numFunctions,
1, batchSize, false, false);
res += discriminator.outputLayer.Forward(
std::move(boost::apply_visitor(
boost::apply_visitor(
outputParameterVisitor,
discriminator.network.back())), std::move(currentTarget));
discriminator.network.back()), currentTarget);
return res;
}
@@ -132,7 +132,7 @@ EvaluateWithGradient(const arma::mat& /* parameters */,
i, gradientDiscriminator, batchSize);
noise.imbue( [&]() { return noiseFunction();} );
generator.Forward(std::move(noise));
generator.Forward(noise);
predictors.cols(numFunctions, numFunctions + batchSize - 1) =
boost::apply_visitor(outputParameterVisitor, generator.network.back());
responses.cols(numFunctions, numFunctions + batchSize - 1) =
@@ -92,8 +92,8 @@ class NetworkInitialization
// hold various other modules.
for (size_t i = 0, offset = parameterOffset; i < network.size(); ++i)
{
offset += boost::apply_visitor(WeightSetVisitor(std::move(parameter),
offset), network[i]);
offset += boost::apply_visitor(WeightSetVisitor(parameter, offset),
network[i]);
boost::apply_visitor(resetVisitor, network[i]);
}
@@ -96,6 +96,10 @@ set(SOURCES
weight_norm_impl.hpp
hardshrink.hpp
hardshrink_impl.hpp
celu.hpp
celu_impl.hpp
softshrink.hpp
softshrink_impl.hpp
)
# Add directory name to sources.
+7 -7
View File
@@ -49,7 +49,7 @@ class Add
* @param output Resulting output activation.
*/
template<typename eT>
void Forward(const arma::Mat<eT>&& input, arma::Mat<eT>&& output);
void Forward(const arma::Mat<eT>& input, arma::Mat<eT>& output);
/**
* Ordinary feed backward pass of a neural network, calculating the function
@@ -61,9 +61,9 @@ class Add
* @param g The calculated gradient.
*/
template<typename eT>
void Backward(const arma::Mat<eT>&& /* input */,
const arma::Mat<eT>&& gy,
arma::Mat<eT>&& g);
void Backward(const arma::Mat<eT>& /* input */,
const arma::Mat<eT>& gy,
arma::Mat<eT>& g);
/**
* Calculate the gradient using the output delta and the input activation.
@@ -73,9 +73,9 @@ class Add
* @param gradient The calculated gradient.
*/
template<typename eT>
void Gradient(const arma::Mat<eT>&& /* input */,
arma::Mat<eT>&& error,
arma::Mat<eT>&& gradient);
void Gradient(const arma::Mat<eT>& /* input */,
const arma::Mat<eT>& error,
arma::Mat<eT>& gradient);
//! Get the parameters.
OutputDataType const& Parameters() const { return weights; }
+7 -7
View File
@@ -29,7 +29,7 @@ Add<InputDataType, OutputDataType>::Add(const size_t outSize) :
template<typename InputDataType, typename OutputDataType>
template<typename eT>
void Add<InputDataType, OutputDataType>::Forward(
const arma::Mat<eT>&& input, arma::Mat<eT>&& output)
const arma::Mat<eT>& input, arma::Mat<eT>& output)
{
output = input;
output.each_col() += weights;
@@ -38,9 +38,9 @@ void Add<InputDataType, OutputDataType>::Forward(
template<typename InputDataType, typename OutputDataType>
template<typename eT>
void Add<InputDataType, OutputDataType>::Backward(
const arma::Mat<eT>&& /* input */,
const arma::Mat<eT>&& gy,
arma::Mat<eT>&& g)
const arma::Mat<eT>& /* input */,
const arma::Mat<eT>& gy,
arma::Mat<eT>& g)
{
g = gy;
}
@@ -48,9 +48,9 @@ void Add<InputDataType, OutputDataType>::Backward(
template<typename InputDataType, typename OutputDataType>
template<typename eT>
void Add<InputDataType, OutputDataType>::Gradient(
const arma::Mat<eT>&& /* input */,
arma::Mat<eT>&& error,
arma::Mat<eT>&& gradient)
const arma::Mat<eT>& /* input */,
const arma::Mat<eT>& error,
arma::Mat<eT>& gradient)
{
gradient = error;
}
+43 -15
View File
@@ -50,6 +50,15 @@ class AddMerge
*/
AddMerge(const bool model = false, const bool run = true);
/**
* Create the AddMerge object using the specified parameters.
*
* @param model Expose all the network modules.
* @param run Call the Forward/Backward method before the output is merged.
* @param ownsLayers Delete the layers when this is deallocated.
*/
AddMerge(const bool model, const bool run, const bool ownsLayers);
//! Destructor to release allocated memory.
~AddMerge();
@@ -61,7 +70,7 @@ class AddMerge
* @param output Resulting output activation.
*/
template<typename InputType, typename OutputType>
void Forward(InputType&& /* input */, OutputType&& output);
void Forward(const InputType& /* input */, OutputType& output);
/**
* Ordinary feed backward pass of a neural network, calculating the function
@@ -73,9 +82,9 @@ class AddMerge
* @param g The calculated gradient.
*/
template<typename eT>
void Backward(const arma::Mat<eT>&& /* input */,
arma::Mat<eT>&& gy,
arma::Mat<eT>&& g);
void Backward(const arma::Mat<eT>& /* input */,
const arma::Mat<eT>& gy,
arma::Mat<eT>& g);
/**
* This is the overload of Backward() that runs only a specific layer with
@@ -87,9 +96,9 @@ class AddMerge
* @param The index of the layer to run.
*/
template<typename eT>
void Backward(const arma::Mat<eT>&& /* input */,
arma::Mat<eT>&& gy,
arma::Mat<eT>&& g,
void Backward(const arma::Mat<eT>& /* input */,
const arma::Mat<eT>& gy,
arma::Mat<eT>& g,
const size_t index);
/*
@@ -100,9 +109,9 @@ class AddMerge
* @param gradient The calculated gradient.
*/
template<typename eT>
void Gradient(arma::Mat<eT>&& input,
arma::Mat<eT>&& error,
arma::Mat<eT>&& gradient);
void Gradient(const arma::Mat<eT>& input,
const arma::Mat<eT>& error,
arma::Mat<eT>& gradient);
/*
* This is the overload of Gradient() that runs a specific layer with the
@@ -114,9 +123,9 @@ class AddMerge
* @param The index of the layer to run.
*/
template<typename eT>
void Gradient(arma::Mat<eT>&& input,
arma::Mat<eT>&& error,
arma::Mat<eT>&& gradient,
void Gradient(const arma::Mat<eT>& input,
const arma::Mat<eT>& error,
arma::Mat<eT>& gradient,
const size_t index);
/*
@@ -184,8 +193,9 @@ class AddMerge
//! before merging the output.
bool run;
//! We need this to know whether we should delete the layer in the destructor.
bool ownsLayer;
//! We need this to know whether we should delete the internally-held layers
//! in the destructor.
bool ownsLayers;
//! Locally-stored network modules.
std::vector<LayerTypes<CustomLayers...> > network;
@@ -221,6 +231,24 @@ class AddMerge
} // namespace ann
} // namespace mlpack
//! Set the serialization version of the AddMerge class.
namespace boost {
namespace serialization {
template<
typename InputDataType,
typename OutputDataType,
typename... CustomLayers
>
struct version<mlpack::ann::AddMerge<
InputDataType, OutputDataType, CustomLayers...>>
{
BOOST_STATIC_CONSTANT(int, value = 1);
};
} // namespace serialization
} // namespace boost
// Include implementation.
#include "add_merge_impl.hpp"
+40 -25
View File
@@ -27,7 +27,16 @@ template<typename InputDataType, typename OutputDataType,
typename... CustomLayers>
AddMerge<InputDataType, OutputDataType, CustomLayers...>::AddMerge(
const bool model, const bool run) :
model(model), run(run), ownsLayer(!model)
model(model), run(run), ownsLayers(!model)
{
// Nothing to do here.
}
template<typename InputDataType, typename OutputDataType,
typename... CustomLayers>
AddMerge<InputDataType, OutputDataType, CustomLayers...>::AddMerge(
const bool model, const bool run, const bool ownsLayers) :
model(model), run(run), ownsLayers(ownsLayers)
{
// Nothing to do here.
}
@@ -36,7 +45,7 @@ template<typename InputDataType, typename OutputDataType,
typename... CustomLayers>
AddMerge<InputDataType, OutputDataType, CustomLayers...>::~AddMerge()
{
if (ownsLayer)
if (!model && ownsLayers)
{
std::for_each(network.begin(), network.end(),
boost::apply_visitor(deleteVisitor));
@@ -47,14 +56,14 @@ template <typename InputDataType, typename OutputDataType,
typename... CustomLayers>
template<typename InputType, typename OutputType>
void AddMerge<InputDataType, OutputDataType, CustomLayers...>::Forward(
InputType&& input, OutputType&& output)
const InputType& input, OutputType& output)
{
if (run)
{
for (size_t i = 0; i < network.size(); ++i)
{
boost::apply_visitor(ForwardVisitor(std::move(input), std::move(
boost::apply_visitor(outputParameterVisitor, network[i]))),
boost::apply_visitor(ForwardVisitor(input,
boost::apply_visitor(outputParameterVisitor, network[i])),
network[i]);
}
}
@@ -70,15 +79,17 @@ template<typename InputDataType, typename OutputDataType,
typename... CustomLayers>
template<typename eT>
void AddMerge<InputDataType, OutputDataType, CustomLayers...>::Backward(
const arma::Mat<eT>&& /* input */, arma::Mat<eT>&& gy, arma::Mat<eT>&& g)
const arma::Mat<eT>& /* input */,
const arma::Mat<eT>& gy,
arma::Mat<eT>& g)
{
if (run)
{
for (size_t i = 0; i < network.size(); ++i)
{
boost::apply_visitor(BackwardVisitor(std::move(boost::apply_visitor(
outputParameterVisitor, network[i])), std::move(gy), std::move(
boost::apply_visitor(deltaVisitor, network[i]))), network[i]);
boost::apply_visitor(BackwardVisitor(boost::apply_visitor(
outputParameterVisitor, network[i]), gy,
boost::apply_visitor(deltaVisitor, network[i])), network[i]);
}
g = boost::apply_visitor(deltaVisitor, network[0]);
@@ -95,12 +106,14 @@ template<typename InputDataType, typename OutputDataType,
typename... CustomLayers>
template<typename eT>
void AddMerge<InputDataType, OutputDataType, CustomLayers...>::Backward(
const arma::Mat<eT>&& /* input */, arma::Mat<eT>&& gy, arma::Mat<eT>&& g,
const arma::Mat<eT>& /* input */,
const arma::Mat<eT>& gy,
arma::Mat<eT>& g,
const size_t index)
{
boost::apply_visitor(BackwardVisitor(std::move(boost::apply_visitor(
outputParameterVisitor, network[index])), std::move(gy), std::move(
boost::apply_visitor(deltaVisitor, network[index]))), network[index]);
boost::apply_visitor(BackwardVisitor(boost::apply_visitor(
outputParameterVisitor, network[index]), gy,
boost::apply_visitor(deltaVisitor, network[index])), network[index]);
g = boost::apply_visitor(deltaVisitor, network[index]);
}
@@ -108,16 +121,15 @@ template<typename InputDataType, typename OutputDataType,
typename... CustomLayers>
template<typename eT>
void AddMerge<InputDataType, OutputDataType, CustomLayers...>::Gradient(
arma::Mat<eT>&& input,
arma::Mat<eT>&& error,
arma::Mat<eT>&& /* gradient */ )
const arma::Mat<eT>& input,
const arma::Mat<eT>& error,
arma::Mat<eT>& /* gradient */ )
{
if (run)
{
for (size_t i = 0; i < network.size(); ++i)
{
boost::apply_visitor(GradientVisitor(std::move(input), std::move(error)),
network[i]);
boost::apply_visitor(GradientVisitor(input, error), network[i]);
}
}
}
@@ -126,20 +138,19 @@ template<typename InputDataType, typename OutputDataType,
typename... CustomLayers>
template<typename eT>
void AddMerge<InputDataType, OutputDataType, CustomLayers...>::Gradient(
arma::Mat<eT>&& input,
arma::Mat<eT>&& error,
arma::Mat<eT>&& /* gradient */,
const arma::Mat<eT>& input,
const arma::Mat<eT>& error,
arma::Mat<eT>& /* gradient */,
const size_t index)
{
boost::apply_visitor(GradientVisitor(std::move(input), std::move(error)),
network[index]);
boost::apply_visitor(GradientVisitor(input, error), network[index]);
}
template<typename InputDataType, typename OutputDataType,
typename... CustomLayers>
template<typename Archive>
void AddMerge<InputDataType, OutputDataType, CustomLayers...>::serialize(
Archive& ar, const unsigned int /* version */)
Archive& ar, const unsigned int version)
{
// Be sure to clear other layers before loading.
if (Archive::is_loading::value)
@@ -148,7 +159,11 @@ void AddMerge<InputDataType, OutputDataType, CustomLayers...>::serialize(
ar & BOOST_SERIALIZATION_NVP(network);
ar & BOOST_SERIALIZATION_NVP(model);
ar & BOOST_SERIALIZATION_NVP(run);
ar & BOOST_SERIALIZATION_NVP(ownsLayer);
if (version >= 1)
ar & BOOST_SERIALIZATION_NVP(ownsLayers);
else if (Archive::is_loading::value)
ownsLayers = !model;
}
} // namespace ann
@@ -35,7 +35,8 @@ namespace ann /** Artificial Neural Network. */ {
* Andreas Mayr},
* title = {Self-Normalizing Neural Networks},
* journal = {Advances in Neural Information Processing Systems},
* year = {2017}
* year = {2017},
* url = {https://arxiv.org/abs/1706.02515}
* }
* @endcode
*
@@ -65,7 +66,7 @@ class AlphaDropout
* @param output Resulting output activation.
*/
template<typename eT>
void Forward(const arma::Mat<eT>&& input, arma::Mat<eT>&& output);
void Forward(const arma::Mat<eT>& input, arma::Mat<eT>& output);
/**
* Ordinary feed backward pass of the alpha_dropout layer.
@@ -75,9 +76,9 @@ class AlphaDropout
* @param g The calculated gradient.
*/
template<typename eT>
void Backward(const arma::Mat<eT>&& /* input */,
arma::Mat<eT>&& gy,
arma::Mat<eT>&& g);
void Backward(const arma::Mat<eT>& /* input */,
const arma::Mat<eT>& gy,
arma::Mat<eT>& g);
//! Get the output parameter.
OutputDataType const& OutputParameter() const { return outputParameter; }
@@ -36,7 +36,7 @@ AlphaDropout<InputDataType, OutputDataType>::AlphaDropout(
template<typename InputDataType, typename OutputDataType>
template<typename eT>
void AlphaDropout<InputDataType, OutputDataType>::Forward(
const arma::Mat<eT>&& input, arma::Mat<eT>&& output)
const arma::Mat<eT>& input, arma::Mat<eT>& output)
{
// The dropout mask will not be multiplied in the deterministic mode
// (during testing).
@@ -58,7 +58,7 @@ void AlphaDropout<InputDataType, OutputDataType>::Forward(
template<typename InputDataType, typename OutputDataType>
template<typename eT>
void AlphaDropout<InputDataType, OutputDataType>::Backward(
const arma::Mat<eT>&& /* input */, arma::Mat<eT>&& gy, arma::Mat<eT>&& g)
const arma::Mat<eT>& /* input */, const arma::Mat<eT>& gy, arma::Mat<eT>& g)
{
g = gy % mask * a;
}
@@ -137,7 +137,7 @@ class AtrousConvolution
* @param output Resulting output activation.
*/
template<typename eT>
void Forward(const arma::Mat<eT>&& input, arma::Mat<eT>&& output);
void Forward(const arma::Mat<eT>& input, arma::Mat<eT>& output);
/**
* Ordinary feed backward pass of a neural network, calculating the function
@@ -149,9 +149,9 @@ class AtrousConvolution
* @param g The calculated gradient.
*/
template<typename eT>
void Backward(const arma::Mat<eT>&& /* input */,
arma::Mat<eT>&& gy,
arma::Mat<eT>&& g);
void Backward(const arma::Mat<eT>& /* input */,
const arma::Mat<eT>& gy,
arma::Mat<eT>& g);
/*
* Calculate the gradient using the output delta and the input activation.
@@ -161,9 +161,9 @@ class AtrousConvolution
* @param gradient The calculated gradient.
*/
template<typename eT>
void Gradient(const arma::Mat<eT>&& /* input */,
arma::Mat<eT>&& error,
arma::Mat<eT>&& gradient);
void Gradient(const arma::Mat<eT>& /* input */,
const arma::Mat<eT>& error,
arma::Mat<eT>& gradient);
//! Get the parameters.
const OutputDataType& Parameters() const { return weights; }
@@ -365,9 +365,6 @@ class AtrousConvolution
//! Locally-stored transformed output parameter.
arma::cube outputTemp;
//! Locally-stored transformed input parameter.
arma::cube inputTemp;
//! Locally-stored transformed padded input parameter.
arma::cube inputPaddedTemp;
@@ -184,10 +184,10 @@ void AtrousConvolution<
GradientConvolutionRule,
InputDataType,
OutputDataType
>::Forward(const arma::Mat<eT>&& input, arma::Mat<eT>&& output)
>::Forward(const arma::Mat<eT>& input, arma::Mat<eT>& output)
{
batchSize = input.n_cols;
inputTemp = arma::cube(const_cast<arma::Mat<eT>&&>(input).memptr(),
arma::cube inputTemp(const_cast<arma::Mat<eT>&>(input).memptr(),
inputWidth, inputHeight, inSize * batchSize, false, false);
if (padding.PadWLeft() != 0 || padding.PadWRight() != 0 ||
@@ -200,8 +200,7 @@ void AtrousConvolution<
for (size_t i = 0; i < inputTemp.n_slices; ++i)
{
padding.Forward(std::move(inputTemp.slice(i)),
std::move(inputPaddedTemp.slice(i)));
padding.Forward(inputTemp.slice(i), inputPaddedTemp.slice(i));
}
}
@@ -267,14 +266,14 @@ void AtrousConvolution<
InputDataType,
OutputDataType
>::Backward(
const arma::Mat<eT>&& /* input */, arma::Mat<eT>&& gy, arma::Mat<eT>&& g)
const arma::Mat<eT>& /* input */, const arma::Mat<eT>& gy, arma::Mat<eT>& g)
{
arma::cube mappedError(gy.memptr(), outputWidth, outputHeight,
outSize * batchSize, false, false);
arma::cube mappedError(((arma::Mat<eT>&) gy).memptr(), outputWidth,
outputHeight, outSize * batchSize, false, false);
g.set_size(inputTemp.n_rows * inputTemp.n_cols * inSize, batchSize);
gTemp = arma::Cube<eT>(g.memptr(), inputTemp.n_rows,
inputTemp.n_cols, inputTemp.n_slices, false, false);
g.set_size(inputWidth * inputHeight * inSize, batchSize);
gTemp = arma::Cube<eT>(g.memptr(), inputWidth, inputHeight,
inSize * batchSize, false, false);
gTemp.zeros();
for (size_t outMap = 0, outMapIdx = 0, batchCount = 0; outMap <
@@ -326,12 +325,14 @@ void AtrousConvolution<
InputDataType,
OutputDataType
>::Gradient(
const arma::Mat<eT>&& /* input */,
arma::Mat<eT>&& error,
arma::Mat<eT>&& gradient)
const arma::Mat<eT>& input,
const arma::Mat<eT>& error,
arma::Mat<eT>& gradient)
{
arma::cube mappedError(error.memptr(), outputWidth, outputHeight,
outSize * batchSize, false, false);
arma::cube mappedError(((arma::Mat<eT>&) error).memptr(), outputWidth,
outputHeight, outSize * batchSize, false, false);
arma::cube inputTemp(const_cast<arma::Mat<eT>&>(input).memptr(),
inputWidth, inputHeight, inSize * batchSize, false, false);
gradient.set_size(weights.n_elem, 1);
gradientTemp = arma::Cube<eT>(gradient.memptr(), weight.n_rows,
+4 -4
View File
@@ -69,7 +69,7 @@ class BaseLayer
* @param output Resulting output activation.
*/
template<typename InputType, typename OutputType>
void Forward(const InputType&& input, OutputType&& output)
void Forward(const InputType& input, OutputType& output)
{
ActivationFunction::Fn(input, output);
}
@@ -84,9 +84,9 @@ class BaseLayer
* @param g The calculated gradient.
*/
template<typename eT>
void Backward(const arma::Mat<eT>&& input,
arma::Mat<eT>&& gy,
arma::Mat<eT>&& g)
void Backward(const arma::Mat<eT>& input,
const arma::Mat<eT>& gy,
arma::Mat<eT>& g)
{
arma::Mat<eT> derivative;
ActivationFunction::Deriv(input, derivative);
+7 -7
View File
@@ -81,7 +81,7 @@ class BatchNorm
* @param output Resulting output activations.
*/
template<typename eT>
void Forward(const arma::Mat<eT>&& input, arma::Mat<eT>&& output);
void Forward(const arma::Mat<eT>& input, arma::Mat<eT>& output);
/**
* Backward pass through the layer.
@@ -91,9 +91,9 @@ class BatchNorm
* @param g The calculated gradient.
*/
template<typename eT>
void Backward(const arma::Mat<eT>&& input,
arma::Mat<eT>&& gy,
arma::Mat<eT>&& g);
void Backward(const arma::Mat<eT>& input,
const arma::Mat<eT>& gy,
arma::Mat<eT>& g);
/**
* Calculate the gradient using the output delta and the input activations.
@@ -103,9 +103,9 @@ class BatchNorm
* @param gradient The calculated gradient.
*/
template<typename eT>
void Gradient(const arma::Mat<eT>&& input,
arma::Mat<eT>&& error,
arma::Mat<eT>&& gradient);
void Gradient(const arma::Mat<eT>& input,
const arma::Mat<eT>& error,
arma::Mat<eT>& gradient);
//! Get the parameters.
OutputDataType const& Parameters() const { return weights; }
@@ -63,7 +63,7 @@ void BatchNorm<InputDataType, OutputDataType>::Reset()
template<typename InputDataType, typename OutputDataType>
template<typename eT>
void BatchNorm<InputDataType, OutputDataType>::Forward(
const arma::Mat<eT>&& input, arma::Mat<eT>&& output)
const arma::Mat<eT>& input, arma::Mat<eT>& output)
{
// Mean and variance over the entire training set will be used to compute
// the forward pass when deterministic is set to true.
@@ -106,7 +106,7 @@ void BatchNorm<InputDataType, OutputDataType>::Forward(
template<typename InputDataType, typename OutputDataType>
template<typename eT>
void BatchNorm<InputDataType, OutputDataType>::Backward(
const arma::Mat<eT>&& input, arma::Mat<eT>&& gy, arma::Mat<eT>&& g)
const arma::Mat<eT>& input, const arma::Mat<eT>& gy, arma::Mat<eT>& g)
{
const arma::mat stdInv = 1.0 / arma::sqrt(variance + eps);
@@ -130,9 +130,9 @@ void BatchNorm<InputDataType, OutputDataType>::Backward(
template<typename InputDataType, typename OutputDataType>
template<typename eT>
void BatchNorm<InputDataType, OutputDataType>::Gradient(
const arma::Mat<eT>&& /* input */,
arma::Mat<eT>&& error,
arma::Mat<eT>&& gradient)
const arma::Mat<eT>& /* input */,
const arma::Mat<eT>& error,
arma::Mat<eT>& gradient)
{
gradient.set_size(size + size, 1);
@@ -65,7 +65,7 @@ class BilinearInterpolation
* @param output The resulting interpolated output matrix.
*/
template<typename eT>
void Forward(const arma::Mat<eT>&& input, arma::Mat<eT>&& output);
void Forward(const arma::Mat<eT>& input, arma::Mat<eT>& output);
/**
* Ordinary feed backward pass of a neural network, calculating the function
@@ -79,9 +79,9 @@ class BilinearInterpolation
* @param output The resulting down-sampled output.
*/
template<typename eT>
void Backward(const arma::Mat<eT>&& /*input*/,
arma::Mat<eT>&& gradient,
arma::Mat<eT>&& output);
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; }
@@ -54,7 +54,7 @@ BilinearInterpolation(
template<typename InputDataType, typename OutputDataType>
template<typename eT>
void BilinearInterpolation<InputDataType, OutputDataType>::Forward(
const arma::Mat<eT>&& input, arma::Mat<eT>&& output)
const arma::Mat<eT>& input, arma::Mat<eT>& output)
{
batchSize = input.n_cols;
if (output.is_empty())
@@ -68,7 +68,7 @@ void BilinearInterpolation<InputDataType, OutputDataType>::Forward(
assert(inRowSize >= 2);
assert(inColSize >= 2);
arma::cube inputAsCube(const_cast<arma::Mat<eT>&&>(input).memptr(),
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);
@@ -114,9 +114,9 @@ void BilinearInterpolation<InputDataType, OutputDataType>::Forward(
template<typename InputDataType, typename OutputDataType>
template<typename eT>
void BilinearInterpolation<InputDataType, OutputDataType>::Backward(
const arma::Mat<eT>&& /*input*/,
arma::Mat<eT>&& gradient,
arma::Mat<eT>&& output)
const arma::Mat<eT>& /*input*/,
const arma::Mat<eT>& gradient,
arma::Mat<eT>& output)
{
if (output.is_empty())
output.set_size(inRowSize * inColSize * depth, batchSize);
@@ -129,8 +129,8 @@ void BilinearInterpolation<InputDataType, OutputDataType>::Backward(
assert(outRowSize >= 2);
assert(outColSize >= 2);
arma::cube gradientAsCube(gradient.memptr(), outRowSize, outColSize,
depth * batchSize, false, false);
arma::cube gradientAsCube(((arma::Mat<eT>&) gradient).memptr(), outRowSize,
outColSize, depth * batchSize, false, false);
arma::cube outputAsCube(output.memptr(), inRowSize, inColSize,
depth * batchSize, false, true);
+5 -4
View File
@@ -33,7 +33,8 @@ namespace ann /** Artificial Neural Network. */ {
* title = {Understanding and Improving Convolutional Neural Networks
* via Concatenated Rectified Linear Units},
* author = {LWenling Shang, Kihyuk Sohn, Diogo Almeida, Honglak Lee},
* year = {2016}
* year = {2016},
* url = {https://arxiv.org/abs/1603.05201}
* }
* @endcode
*
@@ -57,13 +58,13 @@ class CReLU
/**
* Ordinary feed forward pass of a neural network, evaluating the function
* f(x) by propagating the activity forward through f.
* Works only for 2D Tenosrs.
* Works only for 2D Tensors.
*
* @param input Input data used for evaluating the specified function.
* @param output Resulting output activation.
*/
template<typename InputType, typename OutputType>
void Forward(const InputType&& input, OutputType&& output);
void Forward(const InputType& input, OutputType& output);
/**
* Ordinary feed backward pass of a neural network, calculating the function
@@ -75,7 +76,7 @@ class CReLU
* @param g The calculated gradient.
*/
template<typename DataType>
void Backward(const DataType&& input, DataType&& gy, DataType&& g);
void Backward(const DataType& input, const DataType& gy, DataType& g);
//! Get the output parameter.
OutputDataType const& OutputParameter() const { return outputParameter; }
+2 -2
View File
@@ -27,7 +27,7 @@ CReLU<InputDataType, OutputDataType>::CReLU()
template<typename InputDataType, typename OutputDataType>
template<typename InputType, typename OutputType>
void CReLU<InputDataType, OutputDataType>::Forward(
const InputType&& input, OutputType&& output)
const InputType& input, OutputType& output)
{
output = arma::join_cols(arma::max(input, 0.0 * input), arma::max(
(-1 * input), 0.0 * input));
@@ -36,7 +36,7 @@ void CReLU<InputDataType, OutputDataType>::Forward(
template<typename InputDataType, typename OutputDataType>
template<typename DataType>
void CReLU<InputDataType, OutputDataType>::Backward(
const DataType&& input, DataType&& gy, DataType&& g)
const DataType& input, const DataType& gy, DataType& g)
{
DataType temp;
temp = gy % (input >= 0.0);

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