Merge branch 'master' into patch-2

This commit is contained in:
Marcus Edel
2020-04-07 21:00:55 +02:00
committed by GitHub
58 changed files with 3078 additions and 177 deletions
-17
View File
@@ -57,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
+2
View File
@@ -328,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!")
@@ -348,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 ()
+15 -3
View File
@@ -2,8 +2,10 @@
###### ????-??-??
* Updated terminal state for Pendulum environment (#2354).
### mlpack 3.3.0
###### 2020-04-07
* 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
@@ -40,6 +42,9 @@
* 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).
@@ -55,7 +60,7 @@
* 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)
@@ -65,7 +70,7 @@
* Bump minimum Boost version to 1.58 (#2305).
* Refactor STB support so HAS_STB macro is not needed when compiling against
* Refactor STB support so `HAS_STB` macro is not needed when compiling against
mlpack (#2312).
* Add Hard Shrink Activation Function (#2186).
@@ -74,6 +79,13 @@
* Add Hinge Embedding Loss Function (#2229).
* Add Cosine Embedding Loss Function (#2209).
* Add Margin Ranking Loss Function (#2264).
* Bugfix for incorrect parameter vector sizes in logistic regression and
softmax regression (#2359).
### mlpack 3.2.2
###### 2019-11-26
* Add `valid` and `same` padding option in `Convolution` and `Atrous
+1 -1
View File
@@ -23,7 +23,7 @@ src="https://cdn.rawgit.com/mlpack/mlpack.org/e7d36ed8/mlpack-black.svg" style="
<p align="center">
<em>
Download:
<a href="https://www.mlpack.org/files/mlpack-3.2.2.tar.gz">current stable version (3.2.2)</a>
<a href="https://www.mlpack.org/files/mlpack-3.3.0.tar.gz">current stable version (3.3.0)</a>
</em>
</p>
@@ -104,16 +104,16 @@
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>false</ConformanceMode>
<AdditionalIncludeDirectories>C:\boost\boost_1_66_0;C:\mlpack\armadillo-8.500.1\include;C:\mlpack\mlpack-3.2.1\build\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>C:\boost\boost_1_66_0;C:\mlpack\armadillo-8.500.1\include;C:\mlpack\mlpack-3.3.0\build\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>C:\mlpack\mlpack-3.2.1\build\Debug\mlpack.lib;C:\boost\boost_1_66_0\lib64-msvc-14.1\libboost_serialization-vc141-mt-gd-x64-1_66.lib;C:\boost\boost_1_66_0\lib64-msvc-14.1\libboost_program_options-vc141-mt-gd-x64-1_66.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>C:\mlpack\mlpack-3.3.0\build\Debug\mlpack.lib;C:\boost\boost_1_66_0\lib64-msvc-14.1\libboost_serialization-vc141-mt-gd-x64-1_66.lib;C:\boost\boost_1_66_0\lib64-msvc-14.1\libboost_program_options-vc141-mt-gd-x64-1_66.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<PostBuildEvent>
<Command>xcopy /y "C:\mlpack\mlpack-3.2.1\build\Debug\mlpack.dll" $(OutDir)
xcopy /y "C:\mlpack\mlpack-3.2.1\packages\OpenBLAS.0.2.14.1\lib\native\bin\x64\*.dll" $(OutDir)
<Command>xcopy /y "C:\mlpack\mlpack-3.3.0\build\Debug\mlpack.dll" $(OutDir)
xcopy /y "C:\mlpack\mlpack-3.3.0\packages\OpenBLAS.0.2.14.1\lib\native\bin\x64\*.dll" $(OutDir)
xcopy /y "$(ProjectDir)..\..\..\..\src\mlpack\tests\data\german.csv" "$(ProjectDir)data\german.csv*"</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
+6 -6
View File
@@ -30,7 +30,7 @@ to build mlpack on Windows, see \ref build_windows (alternatively, you can read
is based on older versions).
You can download the latest mlpack release from here:
<a href="https://www.mlpack.org/files/mlpack-3.2.2.tar.gz">mlpack-3.2.2</a>
<a href="https://www.mlpack.org/files/mlpack-3.3.0.tar.gz">mlpack-3.3.0</a>
@section build_simple Simple Linux build instructions
@@ -38,9 +38,9 @@ Assuming all dependencies are installed in the system, you can run the commands
below directly to build and install mlpack.
@code
$ wget https://www.mlpack.org/files/mlpack-3.2.2.tar.gz
$ tar -xvzpf mlpack-3.2.2.tar.gz
$ mkdir mlpack-3.2.2/build && cd mlpack-3.2.2/build
$ wget https://www.mlpack.org/files/mlpack-3.3.0.tar.gz
$ tar -xvzpf mlpack-3.3.0.tar.gz
$ mkdir mlpack-3.3.0/build && cd mlpack-3.3.0/build
$ cmake ../
$ make -j4 # The -j is the number of cores you want to use for a build.
$ sudo make install
@@ -65,8 +65,8 @@ configure mlpack.
First we should unpack the mlpack source and create a build directory.
@code
$ tar -xvzpf mlpack-3.2.2.tar.gz
$ cd mlpack-3.2.2
$ tar -xvzpf mlpack-3.3.0.tar.gz
$ cd mlpack-3.3.0
$ mkdir build
@endcode
+3 -3
View File
@@ -31,9 +31,9 @@ build and install mlpack. You can copy-paste the commands into your shell.
@code{.sh}
sudo apt-get install libboost-all-dev g++ cmake libarmadillo-dev python-pip wget
sudo pip install cython setuptools distutils numpy pandas
wget https://www.mlpack.org/files/mlpack-3.2.1.tar.gz
tar -xvzpf mlpack-3.2.1.tar.gz
mkdir -p mlpack-3.2.1/build/ && cd mlpack-3.2.1/build/
wget https://www.mlpack.org/files/mlpack-3.3.0.tar.gz
tar -xvzpf mlpack-3.3.0.tar.gz
mkdir -p mlpack-3.3.0/build/ && cd mlpack-3.3.0/build/
cmake ../ && make -j4 && sudo make install
@endcode
+4 -4
View File
@@ -29,18 +29,18 @@ mlpack and dependencies in Release Mode).
@code
- C:\boost\boost_1_71_0\lib\native\include
- C:\mlpack\armadillo-9.800.3\include
- C:\mlpack\mlpack-3.2.2\build\include
- C:\mlpack\mlpack-3.3.0\build\include
@endcode
- Under Linker > Input > Additional Dependencies add:
@code
- C:\mlpack\mlpack-3.2.2\build\Debug\mlpack.lib
- C:\mlpack\mlpack-3.3.0\build\Debug\mlpack.lib
- C:\boost\boost_1_71_0\lib64-msvc-14.2\libboost_serialization-vc142-mt-gd-x64-1_71.lib
- C:\boost\boost_1_71_0\lib64-msvc-14.2\libboost_program_options-vc142-mt-gd-x64-1_71.lib
@endcode
- Under Build Events > Post-Build Event > Command Line add:
@code
- xcopy /y "C:\mlpack\mlpack-3.2.2\build\Debug\mlpack.dll" $(OutDir)
- xcopy /y "C:\mlpack\mlpack-3.2.2\packages\OpenBLAS.0.2.14.1\lib\native\bin\x64\*.dll" $(OutDir)
- xcopy /y "C:\mlpack\mlpack-3.3.0\build\Debug\mlpack.dll" $(OutDir)
- xcopy /y "C:\mlpack\mlpack-3.3.0\packages\OpenBLAS.0.2.14.1\lib\native\bin\x64\*.dll" $(OutDir)
@endcode
@note Recent versions of Visual Studio set "Conformance Mode" enabled by default. This causes some issues with
+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.
*/
+1 -1
View File
@@ -44,7 +44,7 @@ target_link_libraries(mlpack ${MLPACK_LIBRARIES})
set_target_properties(mlpack
PROPERTIES
VERSION 3.2
VERSION 3.3
SOVERSION 3
)
@@ -3,6 +3,11 @@
* @author Ryan Curtin
*
* Get the Julia-named type of an mlpack C++ type.
*
* 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_BINDINGS_JULIA_GET_JULIA_TYPE_HPP
#define MLPACK_BINDINGS_JULIA_GET_JULIA_TYPE_HPP
@@ -4,6 +4,11 @@
*
* Get the printable type of a parameter. This type is not the C++ type but
* instead the Julia type that a user would use.
*
* 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_BINDINGS_JULIA_GET_PRINTABLE_TYPE_HPP
#define MLPACK_BINDINGS_JULIA_GET_PRINTABLE_TYPE_HPP
@@ -4,6 +4,11 @@
*
* Get the printable type of a parameter. This type is not the C++ type but
* instead the Julia type that a user would use.
*
* 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_BINDINGS_JULIA_GET_PRINTABLE_TYPE_IMPL_HPP
#define MLPACK_BINDINGS_JULIA_GET_PRINTABLE_TYPE_IMPL_HPP
+5
View File
@@ -3,6 +3,11 @@
* @author Ryan Curtin
*
* Implementations of Julia binding functionality.
*
* mlpack is free software; you may redistribute it and/or modify it under the
* terms of the 3-clause BSD license. You should have received a copy of the
* 3-clause BSD license along with mlpack. If not, see
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
*/
#include <mlpack/bindings/julia/julia_util.h>
#include <mlpack/prereqs.hpp>
+5
View File
@@ -3,6 +3,11 @@
* @author Ryan Curtin
*
* Print inline documentation for a single option.
*
* 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_BINDINGS_JULIA_PRINT_DOC_HPP
#define MLPACK_BINDINGS_JULIA_PRINT_DOC_HPP
@@ -4,6 +4,11 @@
*
* Print the declaration of an input parameter as part of a line in a Julia
* function definition.
*
* 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_BINDINGS_JULIA_PRINT_INPUT_PARAM_HPP
#define MLPACK_BINDINGS_JULIA_PRINT_INPUT_PARAM_HPP
@@ -3,6 +3,11 @@
* @author Ryan Curtin
*
* Print Julia code to handle input arguments.
*
* 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_BINDINGS_JULIA_PRINT_INPUT_PROCESSING_HPP
#define MLPACK_BINDINGS_JULIA_PRINT_INPUT_PROCESSING_HPP
@@ -3,6 +3,11 @@
* @author Ryan Curtin
*
* Print Julia code to handle input arguments.
*
* 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_BINDINGS_JULIA_PRINT_INPUT_PROCESSING_IMPL_HPP
#define MLPACK_BINDINGS_JULIA_PRINT_INPUT_PROCESSING_IMPL_HPP
+5
View File
@@ -3,6 +3,11 @@
* @author Ryan Curtin
*
* Implementation of utility PrintJL() function.
*
* mlpack is free software; you may redistribute it and/or modify it under the
* terms of the 3-clause BSD license. You should have received a copy of the
* 3-clause BSD license along with mlpack. If not, see
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
*/
#include "print_jl.hpp"
#include <mlpack/core/util/hyphenate_string.hpp>
+5
View File
@@ -3,6 +3,11 @@
* @author Ryan Curtin
*
* Definition of utility PrintJL() function.
*
* mlpack is free software; you may redistribute it and/or modify it under the
* terms of the 3-clause BSD license. You should have received a copy of the
* 3-clause BSD license along with mlpack. If not, see
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
*/
#ifndef MLPACK_BINDINGS_JULIA_PRINT_JL_HPP
#define MLPACK_BINDINGS_JULIA_PRINT_JL_HPP
@@ -3,6 +3,11 @@
* @author Ryan Curtin
*
* Print Julia code to handle output arguments.
*
* 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_BINDINGS_JULIA_PRINT_OUTPUT_PROCESSING_HPP
#define MLPACK_BINDINGS_JULIA_PRINT_OUTPUT_PROCESSING_HPP
@@ -3,6 +3,11 @@
* @author Ryan Curtin
*
* Print Julia code to handle output arguments.
*
* 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_BINDINGS_JULIA_PRINT_OUTPUT_PROCESSING_IMPL_HPP
#define MLPACK_BINDINGS_JULIA_PRINT_OUTPUT_PROCESSING_IMPL_HPP
@@ -4,6 +4,11 @@
*
* If the type is serializable, we need to define a special utility function to
* set a CLI parameter of that type.
*
* 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_BINDINGS_JULIA_PRINT_PARAM_DEFN_HPP
#define MLPACK_BINDINGS_JULIA_PRINT_PARAM_DEFN_HPP
+5
View File
@@ -4,6 +4,11 @@
*
* Given a C++ type name, turn it into something that has no special characters
* that can simply be printed.
*
* 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_BINDINGS_JULIA_STRIP_TYPE_HPP
#define MLPACK_BINDINGS_JULIA_STRIP_TYPE_HPP
+9
View File
@@ -69,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;
+8 -4
View File
@@ -3,19 +3,23 @@
* @author Mehul Kumar Nirala
*
* Implementation of image loading functionality via STB.
*
* mlpack is free software; you may redistribute it and/or modify it under the
* terms of the 3-clause BSD license. You should have received a copy of the
* 3-clause BSD license along with mlpack. If not, see
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
*/
#include "load.hpp"
#include "image_info.hpp"
#ifdef HAS_STB
// The definition of STB_IMAGE_IMPLEMENTATION means that the implementation will
// be included here directly.
#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>
#include <stb_image.h>
namespace mlpack {
namespace data {
+22 -5
View File
@@ -3,18 +3,29 @@
* @author Mehul Kumar Nirala
*
* Implementation of image saving functionality via STB.
*
* mlpack is free software; you may redistribute it and/or modify it under the
* terms of the 3-clause BSD license. You should have received a copy of the
* 3-clause BSD license along with mlpack. If not, see
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
*/
#include "save.hpp"
#ifdef HAS_STB
#define STB_IMAGE_STATIC
#define STB_IMAGE_IMPLEMENTATION
#include <stb_image.h>
// The implementation of the functions is included directly, so we need to make
// sure it doesn't get included twice. This is to work around a bug in old
// versions of STB where not all functions were correctly marked static.
#define STB_IMAGE_WRITE_STATIC
#define STB_IMAGE_WRITE_IMPLEMENTATION
#ifndef STB_IMAGE_WRITE_IMPLEMENTATION
#define STB_IMAGE_WRITE_IMPLEMENTATION
#else
#undef STB_IMAGE_WRITE_IMPLEMENTATION
#endif
#include <stb_image_write.h>
#ifndef STB_IMAGE_WRITE_IMPLEMENTATION
#define STB_IMAGE_WRITE_IMPLEMENTATION
#endif
namespace mlpack {
namespace data {
@@ -54,6 +65,12 @@ bool SaveImage(const std::string& filename,
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();
+3 -7
View File
@@ -328,15 +328,11 @@ bool Save(const std::vector<std::string>& files,
}
arma::Mat<unsigned char> img;
bool status = Save(files[0], img, info, fatal);
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);
}
+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
+28 -8
View File
@@ -81,14 +81,34 @@ struct IsVector<arma::subview_row<eT> >
const static bool value = true;
};
// I'm not so sure about this one. An SpSubview object can be a row or column,
// but it can also be a matrix subview.
// template<>
template<typename eT>
struct IsVector<arma::SpSubview<eT> >
{
const static bool value = true;
};
#if ((ARMA_VERSION_MAJOR >= 10) || \
((ARMA_VERSION_MAJOR == 9) && (ARMA_VERSION_MINOR >= 869)))
// Armadillo 9.869+ has SpSubview_col and SpSubview_row
template<typename eT>
struct IsVector<arma::SpSubview_col<eT> >
{
const static bool value = true;
};
template<typename eT>
struct IsVector<arma::SpSubview_row<eT> >
{
const static bool value = true;
};
#else
// fallback for older Armadillo versions
template<typename eT>
struct IsVector<arma::SpSubview<eT> >
{
const static bool value = true;
};
#endif
#endif
+2 -2
View File
@@ -17,8 +17,8 @@
// The version of mlpack. If this is a git repository, this will be a version
// with higher number than the most recent release.
#define MLPACK_VERSION_MAJOR 3
#define MLPACK_VERSION_MINOR 2
#define MLPACK_VERSION_PATCH 3
#define MLPACK_VERSION_MINOR 3
#define MLPACK_VERSION_PATCH 1
// The name of the version (for use by --version).
namespace mlpack {
+30 -5
View File
@@ -12,32 +12,57 @@
#ifndef MLPACK_METHODS_ANN_LAYER_LAYER_HPP
#define MLPACK_METHODS_ANN_LAYER_LAYER_HPP
#include "add.hpp"
#include "add_merge.hpp"
#include "alpha_dropout.hpp"
#include "atrous_convolution.hpp"
#include "base_layer.hpp"
#include "batch_norm.hpp"
#include "bilinear_interpolation.hpp"
#include "c_relu.hpp"
#include "celu.hpp"
#include "concat_performance.hpp"
#include "concat.hpp"
#include "concatenate.hpp"
#include "constant.hpp"
#include "convolution.hpp"
#include "dropconnect.hpp"
#include "dropout.hpp"
#include "elu.hpp"
#include "fast_lstm.hpp"
#include "flexible_relu.hpp"
#include "glimpse.hpp"
#include "gru.hpp"
#include "hard_tanh.hpp"
#include "hardshrink.hpp"
#include "highway.hpp"
#include "join.hpp"
#include "layer_norm.hpp"
#include "layer_types.hpp"
#include "leaky_relu.hpp"
#include "linear.hpp"
#include "linear_no_bias.hpp"
#include "log_softmax.hpp"
#include "lookup.hpp"
#include "lstm.hpp"
#include "max_pooling.hpp"
#include "mean_pooling.hpp"
#include "minibatch_discrimination.hpp"
#include "multiply_constant.hpp"
#include "multiply_merge.hpp"
#include "padding.hpp"
#include "gru.hpp"
#include "fast_lstm.hpp"
#include "recurrent.hpp"
#include "parametric_relu.hpp"
#include "recurrent_attention.hpp"
#include "recurrent.hpp"
#include "reinforce_normal.hpp"
#include "reparametrization.hpp"
#include "select.hpp"
#include "sequential.hpp"
#include "softshrink.hpp"
#include "subview.hpp"
#include "concat.hpp"
#include "vr_class_reward.hpp"
#include "transposed_convolution.hpp"
#include "virtual_batch_norm.hpp"
#include "vr_class_reward.hpp"
#include "weight_norm.hpp"
#endif
@@ -30,6 +30,7 @@
#include <mlpack/methods/ann/layer/leaky_relu.hpp>
#include <mlpack/methods/ann/layer/c_relu.hpp>
#include <mlpack/methods/ann/layer/flexible_relu.hpp>
#include <mlpack/methods/ann/layer/linear_no_bias.hpp>
#include <mlpack/methods/ann/layer/log_softmax.hpp>
#include <mlpack/methods/ann/layer/lookup.hpp>
#include <mlpack/methods/ann/layer/multiply_constant.hpp>
@@ -3,6 +3,8 @@
set(SOURCES
cross_entropy_error.hpp
cross_entropy_error_impl.hpp
cosine_embedding_loss.hpp
cosine_embedding_loss_impl.hpp
dice_loss.hpp
dice_loss_impl.hpp
earth_mover_distance.hpp
@@ -11,6 +13,8 @@ set(SOURCES
huber_loss_impl.hpp
kl_divergence.hpp
kl_divergence_impl.hpp
margin_ranking_loss.hpp
margin_ranking_loss_impl.hpp
mean_bias_error.hpp
mean_bias_error_impl.hpp
mean_squared_error.hpp
@@ -0,0 +1,141 @@
/**
* @file cosine_embedding_loss.hpp
* @author Kartik Dutt
*
* Definition of the Cosine Embedding loss function.
*
* mlpack is free software; you may redistribute it and/or modify it under the
* terms of the 3-clause BSD license. You should have received a copy of the
* 3-clause BSD license along with mlpack. If not, see
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
*/
#ifndef MLPACK_METHODS_ANN_LOSS_FUNCTION_COSINE_EMBEDDING_HPP
#define MLPACK_METHODS_ANN_LOSS_FUNCTION_COSINE_EMBEDDING_HPP
#include <mlpack/prereqs.hpp>
namespace mlpack {
namespace ann /** Artificial Neural Network. */ {
/**
* Cosine Embedding Loss function is used for measuring whether two inputs are
* similar or dissimilar, using the cosine distance, and is typically used
* for learning nonlinear embeddings or semi-supervised learning.
*
* @f{eqnarray*}{
* f(x) = 1 - cos(x1, x2) , for y = 1
* f(x) = max(0, cos(x1, x2) - margin) , for y = -1
* @f}
*
* @tparam InputDataType Type of the input data (arma::colvec, arma::mat,
* arma::sp_mat or arma::cube).
* @tparam OutputDataType Type of the output data (arma::colvec, arma::mat,
* arma::sp_mat or arma::cube).
*/
template <
typename InputDataType = arma::mat,
typename OutputDataType = arma::mat
>
class CosineEmbeddingLoss
{
public:
/**
* Create the CosineEmbeddingLoss object.
*
* @param margin Increases cosine distance in case of dissimilarity.
* Refer definition of cosine-embedding-loss above.
* @param similarity Determines whether to use similarity or dissimilarity for
* comparision.
* @param takeMean Boolean variable to specify whether to take mean or not.
* Specifies reduction method i.e. sum or mean corresponding
* to 0 and 1 respectively. Default value = 0.
*/
CosineEmbeddingLoss(const double margin = 0.0,
const bool similarity = true,
const bool takeMean = false);
/**
* Ordinary feed forward pass of a neural network.
*
* @param input Input data used for evaluating the specified function.
* @param target The target vector.
*/
template <typename InputType, typename TargetType>
typename InputType::elem_type Forward(const InputType& input,
const TargetType& target);
/**
* Ordinary feed backward pass of a neural network.
*
* @param input The propagated input activation.
* @param target The target vector.
* @param output The calculated error.
*/
template<typename InputType, typename TargetType, typename OutputType>
void Backward(const InputType& input,
const TargetType& target,
OutputType& output);
//! Get the input parameter.
InputDataType& InputParameter() const { return inputParameter; }
//! Modify the input parameter.
InputDataType& InputParameter() { return inputParameter; }
//! Get the output parameter.
OutputDataType& OutputParameter() const { return outputParameter; }
//! Modify the output parameter.
OutputDataType& OutputParameter() { return outputParameter; }
//! Get the delta.
OutputDataType& Delta() const { return delta; }
//! Modify the delta.
OutputDataType& Delta() { return delta; }
//! Get the value of takeMean.
bool TakeMean() const { return takeMean; }
//! Modify the value of takeMean.
bool& TakeMean() { return takeMean; }
//! Get the value of margin.
double Margin() const { return margin; }
//! Modify the value of takeMean.
double& Margin() { return margin; }
//! Get the value of similarity hyperparameter.
bool Similarity() const { return similarity; }
//! Modify the value of takeMean.
bool& Similarity() { return similarity; }
/**
* Serialize the layer.
*/
template<typename Archive>
void serialize(Archive& ar, const unsigned int /* version */);
private:
//! Locally-stored delta object.
OutputDataType delta;
//! Locally-stored input parameter object.
InputDataType inputParameter;
//! Locally-stored output parameter object.
OutputDataType outputParameter;
//! Locally-stored value of similarity hyper-parameter.
bool similarity;
//! Locally-stored value of margin hyper-parameter.
double margin;
//! Locally-stored value of takeMean hyper-parameter.
bool takeMean;
}; // class CosineEmbeddingLoss
} // namespace ann
} // namespace mlpack
// Include implementation.
#include "cosine_embedding_loss_impl.hpp"
#endif
@@ -0,0 +1,120 @@
/**
* @file cosine_embedding_loss_impl.hpp
* @author Kartik Dutt
*
* Implementation of the Cosine Embedding loss function.
*
* mlpack is free software; you may redistribute it and/or modify it under the
* terms of the 3-clause BSD license. You should have received a copy of the
* 3-clause BSD license along with mlpack. If not, see
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
*/
#ifndef MLPACK_METHODS_ANN_LOSS_FUNCTION_COSINE_EMBEDDING_IMPL_HPP
#define MLPACK_METHODS_ANN_LOSS_FUNCTION_COSINE_EMBEDDING_IMPL_HPP
// In case it hasn't yet been included.
#include "cosine_embedding_loss.hpp"
namespace mlpack {
namespace ann /** Artificial Neural Network. */ {
template<typename InputDataType, typename OutputDataType>
CosineEmbeddingLoss<InputDataType, OutputDataType>::CosineEmbeddingLoss(
const double margin, const bool similarity, const bool takeMean):
margin(margin), similarity(similarity), takeMean(takeMean)
{
// Nothing to do here.
}
template<typename InputDataType, typename OutputDataType>
template<typename InputType, typename TargetType>
typename InputType::elem_type
CosineEmbeddingLoss<InputDataType, OutputDataType>::Forward(
const InputType& input,
const TargetType& target)
{
typedef typename InputType::elem_type ElemType;
const size_t cols = input.n_cols;
const size_t batchSize = input.n_elem / cols;
if (arma::size(input) != arma::size(target))
Log::Fatal << "Input Tensors must have same dimensions." << std::endl;
arma::colvec inputTemp1 = arma::vectorise(input);
arma::colvec inputTemp2 = arma::vectorise(target);
ElemType loss = 0.0;
for (size_t i = 0; i < inputTemp1.n_elem; i += cols)
{
const ElemType cosDist = kernel::CosineDistance::Evaluate(
inputTemp1(arma::span(i, i + cols - 1)), inputTemp2(arma::span(i,
i + cols - 1)));
if (similarity)
loss += 1 - cosDist;
else
{
const ElemType currentLoss = cosDist - margin;
loss += currentLoss > 0 ? currentLoss : 0;
}
}
if (takeMean)
loss = (ElemType) loss / batchSize;
return loss;
}
template<typename InputDataType, typename OutputDataType>
template<typename InputType, typename TargetType, typename OutputType>
void CosineEmbeddingLoss<InputDataType, OutputDataType>::Backward(
const InputType& input,
const TargetType& target,
OutputType& output)
{
typedef typename InputType::elem_type ElemType;
const size_t cols = input.n_cols;
const size_t batchSize = input.n_elem / cols;
if (arma::size(input) != arma::size(target))
Log::Fatal << "Input Tensors must have same dimensions." << std::endl;
arma::colvec inputTemp1 = arma::vectorise(input);
arma::colvec inputTemp2 = arma::vectorise(target);
output.set_size(arma::size(inputTemp1));
arma::colvec outputTemp(output.memptr(), inputTemp1.n_elem,
false, false);
for (size_t i = 0; i < inputTemp1.n_elem; i += cols)
{
const ElemType cosDist = kernel::CosineDistance::Evaluate(inputTemp1(
arma::span(i, i + cols -1)), inputTemp2(arma::span(i, i + cols -1)));
if (cosDist < margin && !similarity)
outputTemp(arma::span(i, i + cols - 1)).zeros();
else
{
const int multiplier = similarity ? 1 : -1;
outputTemp(arma::span(i, i + cols -1)) = -1 * multiplier *
(arma::normalise(inputTemp2(arma::span(i, i + cols - 1))) -
cosDist * arma::normalise(inputTemp1(arma::span(i, i + cols -
1)))) / std::sqrt(arma::accu(arma::pow(inputTemp1(arma::span(i, i +
cols - 1)), 2)));
}
}
}
template<typename InputDataType, typename OutputDataType>
template<typename Archive>
void CosineEmbeddingLoss<InputDataType, OutputDataType>::serialize(
Archive& ar ,
const unsigned int /* version */)
{
ar & BOOST_SERIALIZATION_NVP(margin);
ar & BOOST_SERIALIZATION_NVP(similarity);
ar & BOOST_SERIALIZATION_NVP(takeMean);
}
} // namespace ann
} // namespace mlpack
#endif
@@ -0,0 +1,102 @@
/**
* @file margin_ranking_loss.hpp
* @author Andrei Mihalea
*
* Definition of the Margin Ranking Loss function.
*
* mlpack is free software; you may redistribute it and/or modify it under the
* terms of the 3-clause BSD license. You should have received a copy of the
* 3-clause BSD license along with mlpack. If not, see
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
*/
#ifndef MLPACK_ANN_LOSS_FUNCTION_MARGIN_RANKING_LOSS_HPP
#define MLPACK_ANN_LOSS_FUNCTION_MARGIN_RANKING_LOSS_HPP
#include <mlpack/prereqs.hpp>
namespace mlpack {
namespace ann /** Artificial Neural Network. */ {
/**
* Margin ranking loss measures the loss given inputs and a label vector with
* values of 1 or -1. If the label is 1 then the first input should be ranked
* higher than the second input at a distance larger than a margin, and vice-
* versa if the label is -1.
*
* @tparam InputDataType Type of the input data (arma::colvec, arma::mat,
* arma::sp_mat or arma::cube).
* @tparam OutputDataType Type of the output data (arma::colvec, arma::mat,
* arma::sp_mat or arma::cube).
*/
template <
typename InputDataType = arma::mat,
typename OutputDataType = arma::mat
>
class MarginRankingLoss
{
public:
/**
* Create the MarginRankingLoss object with Hyperparameter margin.
* Hyperparameter margin defines a minimum distance between correctly ranked
* samples.
*/
MarginRankingLoss(const double margin = 1.0);
/**
* Computes the Margin Ranking Loss function.
*
* @param input Concatenation of the two inputs for evaluating the specified
* function.
* @param target The label vector which contains values of -1 or 1.
*/
template<typename InputType, typename TargetType>
typename InputType::elem_type Forward(const InputType& input,
const TargetType& target);
/**
* Ordinary feed backward pass of a neural network.
*
* @param input The propagated concatenated input activation.
* @param target The label vector which contains -1 or 1 values.
* @param output The calculated error.
*/
template <
typename InputType,
typename TargetType,
typename OutputType
>
void Backward(const InputType& input,
const TargetType& target,
OutputType& output);
//! Get the output parameter.
OutputDataType& OutputParameter() const { return outputParameter; }
//! Modify the output parameter.
OutputDataType& OutputParameter() { return outputParameter; }
//! Get the margin parameter.
double Margin() const { return margin; }
//! Modify the margin parameter.
double& Margin() { return margin; }
/**
* Serialize the layer.
*/
template<typename Archive>
void serialize(Archive& ar, const unsigned int /* version */);
private:
//! Locally-stored output parameter object.
OutputDataType outputParameter;
//! The margin value used in calculating Margin Ranking Loss.
double margin;
}; // class MarginRankingLoss
} // namespace ann
} // namespace mlpack
// include implementation.
#include "margin_ranking_loss_impl.hpp"
#endif
@@ -0,0 +1,74 @@
/**
* @file margin_ranking_loss_impl.hpp
* @author Andrei Mihalea
*
* Implementation of the Margin Ranking Loss function.
*
* mlpack is free software; you may redistribute it and/or modify it under the
* terms of the 3-clause BSD license. You should have received a copy of the
* 3-clause BSD license along with mlpack. If not, see
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
*/
#ifndef MLPACK_METHODS_ANN_LOSS_FUNCTION_MARGIN_IMPL_LOSS_HPP
#define MLPACK_METHODS_ANN_LOSS_FUNCTION_MARGIN_IMPL_LOSS_HPP
// In case it hasn't been included.
#include "margin_ranking_loss.hpp"
namespace mlpack {
namespace ann /** Artifical Neural Network. */ {
template<typename InputDataType, typename OutputDataType>
MarginRankingLoss<InputDataType, OutputDataType>::MarginRankingLoss(
const double margin) : margin(margin)
{
// Nothing to do here.
}
template<typename InputDataType, typename OutputDataType>
template<typename InputType, typename TargetType>
typename InputType::elem_type
MarginRankingLoss<InputDataType, OutputDataType>::Forward(
const InputType& input,
const TargetType& target)
{
const int inputRows = input.n_rows;
const InputType& input1 = input.rows(0, inputRows / 2 - 1);
const InputType& input2 = input.rows(inputRows / 2, inputRows - 1);
return arma::accu(arma::max(arma::zeros(size(target)),
-target % (input1 - input2) + margin)) / target.n_cols;
}
template<typename InputDataType, typename OutputDataType>
template <
typename InputType,
typename TargetType,
typename OutputType
>
void MarginRankingLoss<InputDataType, OutputDataType>::Backward(
const InputType& input,
const TargetType& target,
OutputType& output)
{
const int inputRows = input.n_rows;
const InputType& input1 = input.rows(0, inputRows / 2 - 1);
const InputType& input2 = input.rows(inputRows / 2, inputRows - 1);
output = -target % (input1 - input2) + margin;
output.elem(arma::find(output >= 0)).ones();
output.elem(arma::find(output < 0)).zeros();
output = (input2 - input1) % output / target.n_cols;
}
template<typename InputDataType, typename OutputDataType>
template<typename Archive>
void MarginRankingLoss<InputDataType, OutputDataType>::serialize(
Archive& ar,
const unsigned int /* version */)
{
ar & BOOST_SERIALIZATION_NVP(margin);
}
} // namespace ann
} // namespace mlpack
#endif
@@ -25,7 +25,6 @@ LogisticRegression<MatType>::LogisticRegression(
const MatType& predictors,
const arma::Row<size_t>& responses,
const double lambda) :
parameters(arma::rowvec(predictors.n_rows + 1, arma::fill::zeros)),
lambda(lambda)
{
Train(predictors, responses);
@@ -60,7 +59,6 @@ LogisticRegression<MatType>::LogisticRegression(
const arma::Row<size_t>& responses,
OptimizerType& optimizer,
const double lambda) :
parameters(arma::rowvec(predictors.n_rows + 1, arma::fill::zeros)),
lambda(lambda)
{
Train(predictors, responses, optimizer);
@@ -85,9 +83,11 @@ double LogisticRegression<MatType>::Train(
OptimizerType& optimizer,
CallbackTypes&&... callbacks)
{
LogisticRegressionFunction<MatType> errorFunction(predictors,
responses,
lambda);
LogisticRegressionFunction<MatType> errorFunction(predictors, responses,
lambda);
// Set size of parameters vector according to the input data received.
parameters = arma::rowvec(predictors.n_rows + 1, arma::fill::zeros);
errorFunction.InitialPoint() = parameters;
Timer::Start("logistic_regression_optimization");
+9 -1
View File
@@ -40,4 +40,12 @@ add_markdown_docs(preprocess_imputer "cli" "preprocessing")
add_cli_executable(preprocess_scale)
add_python_binding(preprocess_scale)
add_markdown_docs(preprocess_scale "cli;python" "preprocessing")
add_julia_binding(preprocess_scale)
add_markdown_docs(preprocess_scale "cli;python;julia" "preprocessing")
if (STB_AVAILABLE)
add_cli_executable(image_converter)
add_python_binding(image_converter)
add_julia_binding(image_converter)
add_markdown_docs(image_converter "cli;python;julia" "preprocessing")
endif ()
@@ -0,0 +1,114 @@
/**
* @file image_converter_main.cpp
* @author Jeffin Sam
*
* A CLI executable to load and save a image dataset.
*
* mlpack is free software; you may redistribute it and/or modify it under the
* terms of the 3-clause BSD license. You should have received a copy of the
* 3-clause BSD license along with mlpack. If not, see
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
*/
#include <mlpack/prereqs.hpp>
#include <mlpack/core/util/cli.hpp>
#include <mlpack/core/util/mlpack_main.hpp>
#include <mlpack/core.hpp>
using namespace mlpack;
using namespace mlpack::util;
using namespace arma;
using namespace std;
using namespace mlpack::data;
PROGRAM_INFO("Image Converter",
// Short description.
"A utility to load an image or set of images into a single dataset that"
" can then be used by other mlpack methods and utilities. This can also"
" unpack an image dataset into individual files, for instance after mlpack"
" methods have been used.",
// Long description.
"This utility takes an image or an array of images and loads them to a"
" matrix. You can optionally specify the height " +
PRINT_PARAM_STRING("height") + " width " + PRINT_PARAM_STRING("width")
+ " and channel " + PRINT_PARAM_STRING("channels") + " of the images that"
" needs to be loaded; otherwise, these parameters will be automatically"
" detected from the image."
"\n"
"There are other options too, that can be specified such as " +
PRINT_PARAM_STRING("quality")
+ ".\n\n" +
"You can also provide a dataset and save them as images using " +
PRINT_PARAM_STRING("dataset") + " and " + PRINT_PARAM_STRING("save") +
" as an parameter. An example to load an image : " +
"\n\n" +
PRINT_CALL("image_converter", "input", "X", "height", 256, "width", 256,
"channels", 3, "output", "Y") +
"\n\n" +
" An example to save an image is :" +
"\n\n" +
PRINT_CALL("image_converter", "input", "X", "height", 256, "width", 256,
"channels", 3, "dataset", "Y", "save", true),
SEE_ALSO("@preprocess_binarize", "#preprocess_binarize"),
SEE_ALSO("@preprocess_describe", "#preprocess_describe"),
SEE_ALSO("@preprocess_imputer", "#preprocess_imputer"));
// DEFINE PARAM
PARAM_VECTOR_IN_REQ(string, "input", "Image filenames which have to "
"be loaded/saved.", "i");
PARAM_INT_IN("width", "Width of the image.", "w", 0);
PARAM_INT_IN("channels", "Number of channels in the image.", "c", 0);
PARAM_MATRIX_OUT("output", "Matrix to save images data to, Only"
"needed if you are specifying 'save' option.", "o");
PARAM_INT_IN("quality", "Compression of the image if saved as jpg (0-100).",
"q", 90);
PARAM_INT_IN("height", "Height of the images.", "H", 0);
PARAM_FLAG("save", "Save a dataset as images.", "s");
PARAM_MATRIX_IN("dataset", "Input matrix to save as images.", "I");
static void mlpackMain()
{
Timer::Start("Loading/Saving Image");
// Parse command line options.
const vector<string> fileNames = CLI::GetParam<vector<string> >("input");
arma::mat out;
if (!CLI::HasParam("save"))
{
ReportIgnoredParam("width", "Width of image is determined from file.");
ReportIgnoredParam("height", "Height of image is determined from file.");
ReportIgnoredParam("channels", "Number of channels determined from file.");
data::ImageInfo info;
Load(fileNames, out, info, true);
if (CLI::HasParam("output"))
CLI::GetParam<arma::mat>("output") = std::move(out);
}
else
{
RequireNoneOrAllPassed({ "save", "width", "height", "channels", "dataset" }
, true, "Image size information is needed when 'save' is specified!");
// Positive value for width.
RequireParamValue<int>("width", [](int x) { return x >= 0;}, true,
"width must be positive");
// Positive value for height.
RequireParamValue<int>("height", [](int x) { return x >= 0;}, true,
"height must be positive");
// Positive value for channel.
RequireParamValue<int>("channels", [](int x) { return x >= 0;}, true,
"channels must be positive");
// Positive value for quality.
RequireParamValue<int>("quality", [](int x) { return x >= 0;}, true,
"quality must be positive");
const size_t height = CLI::GetParam<int>("height");
const size_t width = CLI::GetParam<int>("width");
const size_t channels = CLI::GetParam<int>("channels");
const size_t quality = CLI::GetParam<int>("quality");
data::ImageInfo info(width, height, channels, quality);
Save(fileNames, CLI::GetParam<arma::mat>("dataset"), info, true);
}
}
@@ -10,9 +10,10 @@
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
*/
#include <mlpack/prereqs.hpp>
#include <mlpack/core/util/cli.hpp>
#include <mlpack/core/util/mlpack_main.hpp>
#include <mlpack/core/math/random.hpp>
#include <mlpack/core/util/cli.hpp>
#include <mlpack/core/math/ccov.hpp>
#include <mlpack/core/data/scaler_methods/max_abs_scaler.hpp>
#include <mlpack/core/data/scaler_methods/mean_normalization.hpp>
#include <mlpack/core/data/scaler_methods/min_max_scaler.hpp>
@@ -0,0 +1,14 @@
# Define the files we need to compile
# Anything not in this list will not be compiled into mlpack.
set(SOURCES
simple_dqn.hpp
)
# Add directory name to sources.
set(DIR_SRCS)
foreach(file ${SOURCES})
set(DIR_SRCS ${DIR_SRCS} ${CMAKE_CURRENT_SOURCE_DIR}/${file})
endforeach()
# Append sources (with directory name) to list of all mlpack sources (used at
# the parent scope).
set(MLPACK_SRCS ${MLPACK_SRCS} ${DIR_SRCS} PARENT_SCOPE)
@@ -0,0 +1,127 @@
/**
* @file simple_dqn.hpp
* @author Nishant Kumar
*
* This file contains the implementation of the simple deep q network.
*
* mlpack is free software; you may redistribute it and/or modify it under the
* terms of the 3-clause BSD license. You should have received a copy of the
* 3-clause BSD license along with mlpack. If not, see
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
*/
#ifndef MLPACK_METHODS_RL_SIMPLE_DQN_HPP
#define MLPACK_METHODS_RL_SIMPLE_DQN_HPP
#include <mlpack/prereqs.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>
namespace mlpack {
namespace rl {
using namespace mlpack::ann;
/**
* @tparam NetworkType The type of network used for simple dqn.
*/
template <typename NetworkType = FFN<MeanSquaredError<>,
GaussianInitialization>>
class SimpleDQN
{
public:
/**
* Default constructor.
*/
SimpleDQN() : network()
{ /* Nothing to do here. */ }
/**
* Construct an instance of SimpleDQN class.
*
* @param inputDim Number of inputs.
* @param h1 Number of neurons in hiddenlayer-1.
* @param h2 Number of neurons in hiddenlayer-2.
* @param outputDim Number of neurons in output layer.
*/
SimpleDQN(const int inputDim,
const int h1,
const int h2,
const int outputDim) : network()
{
FFN<MeanSquaredError<>, GaussianInitialization> model(MeanSquaredError<>(),
GaussianInitialization(0, 0.001));
model.Add<Linear<>>(inputDim, h1);
model.Add<ReLULayer<>>();
model.Add<Linear<>>(h1, h2);
model.Add<ReLULayer<>>();
model.Add<Linear<>>(h2, outputDim);
network = model;
}
SimpleDQN(NetworkType network) : network(std::move(network))
{ /* Nothing to do here. */ }
/**
* Predict the responses to a given set of predictors. The responses will
* reflect the output of the given output layer as returned by the
* output layer function.
*
* If you want to pass in a parameter and discard the original parameter
* object, be sure to use std::move to avoid unnecessary copy.
*
* @param state Input state.
* @param actionValue Matrix to put output action values of states input.
*/
void Predict(const arma::mat state, arma::mat& actionValue)
{
network.Predict(state, actionValue);
}
/**
* Perform the forward pass of the states in real batch mode.
*
* @param state The input state.
* @param target The predicted target.
*/
void Forward(const arma::mat state, arma::mat& target)
{
network.Forward(state, target);
}
/**
* Resets the parameters of the network.
*/
void ResetParameters()
{
network.ResetParameters();
}
//! Return the Parameters.
const arma::mat& Parameters() const { return network.Parameters(); }
//! Modify the Parameters.
arma::mat& Parameters() { return network.Parameters(); }
/**
* Perform the backward pass of the state in real batch mode.
*
* @param state The input state.
* @param target The training target.
* @return gradient The gradient.
*/
void Backward(const arma::mat state, arma::mat& target,
arma::mat& gradient)
{
network.Backward(state, target, gradient);
}
private:
//! Locally-stored network.
NetworkType network;
};
} // namespace rl
} // namespace mlpack
#endif
@@ -65,7 +65,7 @@ double SoftmaxRegression::Train(const arma::mat& data,
{
SoftmaxRegressionFunction regressor(data, labels, numClasses, lambda,
fitIntercept);
if (parameters.is_empty())
if (parameters.n_elem != regressor.GetInitialPoint().n_elem)
parameters = regressor.GetInitialPoint();
// Train the model.
@@ -88,7 +88,7 @@ double SoftmaxRegression::Train(const arma::mat& data,
{
SoftmaxRegressionFunction regressor(data, labels, numClasses, lambda,
fitIntercept);
if (parameters.is_empty())
if (parameters.n_elem != regressor.GetInitialPoint().n_elem)
parameters = regressor.GetInitialPoint();
// Train the model.
+1
View File
@@ -137,6 +137,7 @@ add_executable(mlpack_test
main_tests/kfn_test.cpp
main_tests/knn_test.cpp
main_tests/linear_regression_test.cpp
main_tests/image_converter_test.cpp
main_tests/linear_svm_test.cpp
main_tests/logistic_regression_test.cpp
main_tests/local_coordinate_coding_test.cpp
+91 -2
View File
@@ -12,6 +12,8 @@
#include <mlpack/core.hpp>
#include <boost/test/unit_test.hpp>
#include "test_tools.hpp"
#include "serialization.hpp"
using namespace mlpack;
using namespace mlpack::data;
@@ -43,7 +45,11 @@ BOOST_AUTO_TEST_CASE(LoadImageAPITest)
arma::Mat<unsigned char> matrix;
data::ImageInfo info;
BOOST_REQUIRE(data::Load("test_image.png", matrix, info, false) == true);
BOOST_REQUIRE_EQUAL(matrix.n_rows, 50 * 50 * 3); // width * height * channels.
// width * height * channels.
BOOST_REQUIRE_EQUAL(matrix.n_rows, 50 * 50 * 3);
BOOST_REQUIRE_EQUAL(info.Height(), 50);
BOOST_REQUIRE_EQUAL(info.Width(), 50);
BOOST_REQUIRE_EQUAL(info.Channels(), 3);
BOOST_REQUIRE_EQUAL(matrix.n_cols, 1);
}
@@ -64,8 +70,91 @@ BOOST_AUTO_TEST_CASE(SaveImageAPITest)
BOOST_REQUIRE_EQUAL(im1.n_cols, im2.n_cols);
BOOST_REQUIRE_EQUAL(im1.n_rows, im2.n_rows);
for (size_t i = 10; i < im1.n_elem; ++i)
for (size_t i = 0; i < im1.n_elem; ++i)
BOOST_REQUIRE_EQUAL(im1[i], im2[i]);
remove("APITest.bmp");
}
/**
* Test if an image with a wrong dimesion throws an expected
* exception while saving.
*/
BOOST_AUTO_TEST_CASE(SaveImageWrongInfo)
{
data::ImageInfo info(5, 5, 3, 90);
arma::Mat<unsigned char> im1;
size_t dimension = info.Width() * info.Height() * info.Channels();
im1 = arma::randi<arma::Mat<unsigned char>>(24 * 25 * 7, 1);
Log::Fatal.ignoreInput = true;
BOOST_REQUIRE_THROW(data::Save("APITest.bmp", im1, info, false),
std::runtime_error);
Log::Fatal.ignoreInput = false;
}
/**
* Test that the image is loaded correctly into the matrix using the API
* for vectors.
*/
BOOST_AUTO_TEST_CASE(LoadVectorImageAPITest)
{
arma::Mat<unsigned char> matrix;
data::ImageInfo info;
std::vector<std::string> files = {"test_image.png", "test_image.png"};
BOOST_REQUIRE(data::Load(files, matrix, info, false) == true);
// width * height * channels.
BOOST_REQUIRE_EQUAL(matrix.n_rows, 50 * 50 * 3);
BOOST_REQUIRE_EQUAL(info.Height(), 50);
BOOST_REQUIRE_EQUAL(info.Width(), 50);
BOOST_REQUIRE_EQUAL(info.Channels(), 3);
BOOST_REQUIRE_EQUAL(matrix.n_cols, 2);
}
/**
* Test if the image is saved correctly using API for arma mat.
*/
BOOST_AUTO_TEST_CASE(SaveImageMatAPITest)
{
data::ImageInfo info(5, 5, 3);
arma::Mat<unsigned char> im1;
size_t dimension = info.Width() * info.Height() * info.Channels();
im1 = arma::randi<arma::Mat<unsigned char>>(dimension, 1);
arma::mat input = arma::conv_to<arma::mat>::from(im1);
BOOST_REQUIRE(Save("APITest.bmp", input, info, false) == true);
arma::mat output;
BOOST_REQUIRE(Load("APITest.bmp", output, info, false) == true);
BOOST_REQUIRE_EQUAL(input.n_cols, output.n_cols);
BOOST_REQUIRE_EQUAL(input.n_rows, output.n_rows);
for (size_t i = 0; i < input.n_elem; ++i)
BOOST_REQUIRE_CLOSE(input[i], output[i], 1e-5);
remove("APITest.bmp");
}
/**
* Serialization test for the ImageInfo class.
*/
BOOST_AUTO_TEST_CASE(ImageInfoSerialization)
{
data::ImageInfo info(5, 5, 3, 90);
data::ImageInfo xmlInfo, textInfo, binaryInfo;
SerializeObjectAll(info, xmlInfo, textInfo, binaryInfo);
BOOST_REQUIRE_EQUAL(info.Width(), xmlInfo.Width());
BOOST_REQUIRE_EQUAL(info.Height(), xmlInfo.Height());
BOOST_REQUIRE_EQUAL(info.Channels(), xmlInfo.Channels());
BOOST_REQUIRE_EQUAL(info.Quality(), xmlInfo.Quality());
BOOST_REQUIRE_EQUAL(info.Width(), textInfo.Width());
BOOST_REQUIRE_EQUAL(info.Height(), textInfo.Height());
BOOST_REQUIRE_EQUAL(info.Channels(), textInfo.Channels());
BOOST_REQUIRE_EQUAL(info.Quality(), textInfo.Quality());
BOOST_REQUIRE_EQUAL(info.Width(), binaryInfo.Width());
BOOST_REQUIRE_EQUAL(info.Height(), binaryInfo.Height());
BOOST_REQUIRE_EQUAL(info.Channels(), binaryInfo.Channels());
BOOST_REQUIRE_EQUAL(info.Quality(), binaryInfo.Quality());
}
BOOST_AUTO_TEST_SUITE_END();
@@ -1002,4 +1002,25 @@ BOOST_AUTO_TEST_CASE(LogisticRegressionTrainReturnObjective)
BOOST_REQUIRE_EQUAL(std::isfinite(objVal), true);
}
/**
* Test that construction *then* training works fine. Thanks @Trento89 for the
* test case (see #2358).
*/
BOOST_AUTO_TEST_CASE(ConstructionThenTraining)
{
arma::mat myMatrix;
// Four points, three dimensions.
myMatrix << 0.555950 << 0.274690 << 0.540605 << 0.798938 << arma::endr
<< 0.948014 << 0.973234 << 0.216504 << 0.883152 << arma::endr
<< 0.023787 << 0.675382 << 0.231751 << 0.450332 << arma::endr;
arma::Row<size_t> myTargets("1 0 1 0");
regression::LogisticRegression<> lr;
// Make sure that training doesn't crash with invalid parameter sizes.
BOOST_REQUIRE_NO_THROW(lr.Train(myMatrix, myTargets));
}
BOOST_AUTO_TEST_SUITE_END();
+133
View File
@@ -22,11 +22,13 @@
#include <mlpack/methods/ann/loss_functions/sigmoid_cross_entropy_error.hpp>
#include <mlpack/methods/ann/loss_functions/cross_entropy_error.hpp>
#include <mlpack/methods/ann/loss_functions/reconstruction_loss.hpp>
#include <mlpack/methods/ann/loss_functions/margin_ranking_loss.hpp>
#include <mlpack/methods/ann/loss_functions/mean_squared_logarithmic_error.hpp>
#include <mlpack/methods/ann/loss_functions/mean_bias_error.hpp>
#include <mlpack/methods/ann/loss_functions/dice_loss.hpp>
#include <mlpack/methods/ann/loss_functions/log_cosh_loss.hpp>
#include <mlpack/methods/ann/loss_functions/hinge_embedding_loss.hpp>
#include <mlpack/methods/ann/loss_functions/cosine_embedding_loss.hpp>
#include <mlpack/methods/ann/init_rules/nguyen_widrow_init.hpp>
#include <mlpack/methods/ann/ffn.hpp>
@@ -578,4 +580,135 @@ BOOST_AUTO_TEST_CASE(HingeEmbeddingLossTest)
BOOST_REQUIRE_EQUAL(output.n_rows, input.n_rows);
BOOST_REQUIRE_EQUAL(output.n_cols, input.n_cols);
}
/**
* Simple test for the Cosine Embedding loss function.
*/
BOOST_AUTO_TEST_CASE(CosineEmbeddingLossTest)
{
arma::mat input1, input2, y, output;
double loss;
CosineEmbeddingLoss<> module;
// Test the Forward function. Loss should be 0 if input1 = input2 and y = 1.
input1 = arma::mat(1, 10);
input2 = arma::mat(1, 10);
input1.ones();
input2.ones();
y = arma::mat(1, 1);
y.ones();
loss = module.Forward(input1, input1);
BOOST_REQUIRE_SMALL(loss, 1e-6);
// Test the Backward function.
module.Backward(input1, input1, output);
BOOST_REQUIRE_SMALL(arma::accu(output), 1e-6);
// Check for dissimilarity.
module.Similarity() = false;
loss = module.Forward(input1, input1);
BOOST_REQUIRE_CLOSE(loss, 1.0, 1e-4);
// Test the Backward function.
module.Backward(input1, input1, output);
BOOST_REQUIRE_SMALL(arma::accu(output), 1e-6);
input1 = arma::mat(3, 2);
input2 = arma::mat(3, 2);
input1.fill(1);
input1(4) = 2;
input2.fill(1);
input2(0) = 2;
input2(1) = 2;
input2(2) = 2;
loss = module.Forward(input1, input2);
// Calculated using torch.nn.CosineEmbeddingLoss().
BOOST_REQUIRE_CLOSE(loss, 2.897367, 1e-3);
// Test the Backward function.
module.Backward(input1, input2, output);
BOOST_REQUIRE_CLOSE(arma::accu(output), 0.06324556, 1e-3);
// Check for correctness for cube.
CosineEmbeddingLoss<> module2(0.5, true);
arma::cube input3(3, 2, 2);
arma::cube input4(3, 2, 2);
input3.fill(1);
input4.fill(1);
input3(0) = 2;
input3(1) = 2;
input3(4) = 2;
input3(6) = 2;
input3(8) = 2;
input3(10) = 2;
input4(2) = 2;
input4(9) = 2;
input4(11) = 2;
loss = module2.Forward(input3, input4);
// Calculated using torch.nn.CosineEmbeddingLoss().
BOOST_REQUIRE_CLOSE(loss, 0.55395, 1e-3);
// Test the Backward function.
module2.Backward(input3, input4, output);
BOOST_REQUIRE_CLOSE(arma::accu(output), -0.36649111, 1e-3);
// Check Output for mean type of reduction.
CosineEmbeddingLoss<> module3(0.0, true, true);
loss = module3.Forward(input3, input4);
BOOST_REQUIRE_CLOSE(loss, 0.092325, 1e-3);
// Check correctness for cube.
module3.Similarity() = false;
loss = module3.Forward(input3, input4);
BOOST_REQUIRE_CLOSE(loss, 0.90767498236, 1e-3);
// Test the Backward function.
module3.Backward(input3, input4, output);
BOOST_REQUIRE_CLOSE(arma::accu(output), 0.36649111, 1e-4);
}
/*
* Simple test for the Margin Ranking Loss function.
*/
BOOST_AUTO_TEST_CASE(MarginRankingLossTest)
{
arma::mat input, input1, input2, target, output;
MarginRankingLoss<> module;
// Test the Forward function on a user generator input and compare it against
// the manually calculated result.
input1 = arma::mat("1 2 5 7 -1 -3");
input2 = arma::mat("-1 3 -4 11 3 -3");
input = arma::join_cols(input1, input2);
target = arma::mat("1 -1 -1 1 -1 1");
double error = module.Forward(input, target);
// Computed using torch.nn.functional.margin_ranking_loss()
BOOST_REQUIRE_CLOSE(error, 2.66667, 1e-3);
// Test the Backward function.
module.Backward(input, target, output);
CheckMatrices(output, arma::mat("-0.000000 0.166667 -1.500000 0.666667 "
"0.000000 -0.000000"), 1e-3);
BOOST_REQUIRE_EQUAL(output.n_rows, target.n_rows);
BOOST_REQUIRE_EQUAL(output.n_cols, target.n_cols);
// Test the error function on another input.
input1 = arma::mat("0.4287 -1.6208 -1.5006 -0.4473 1.5208 -4.5184 9.3574 "
"-4.8090 4.3455 5.2070");
input2 = arma::mat("-4.5288 -9.2766 -0.5882 -5.6643 -6.0175 8.8506 3.4759 "
"-9.4886 2.2755 8.4951");
input = arma::join_cols(input1, input2);
target = arma::mat("1 1 -1 1 -1 1 1 1 -1 1");
error = module.Forward(input, target);
BOOST_REQUIRE_CLOSE(error, 3.03530, 1e-3);
// Test the Backward function on the second input.
module.Backward(input, target, output);
CheckMatrices(output, arma::mat("0.000000 0.000000 0.091240 0.000000 "
"-0.753830 1.336900 0.000000 0.000000 -0.207000 0.328810"), 1e-6);
}
BOOST_AUTO_TEST_SUITE_END();
@@ -0,0 +1,185 @@
/**
* @file image_converter_test.cpp
* @author Jeffin Sam
*
* Test mlpackMain() of load_save_image_main.cpp.
*
* 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.
*/
#define BINDING_TYPE BINDING_TYPE_TEST
#include <mlpack/core.hpp>
static const std::string testName = "ImageConverter";
#include <mlpack/core/util/mlpack_main.hpp>
#include <mlpack/methods/preprocess/image_converter_main.cpp>
#include "test_helper.hpp"
#include <boost/test/unit_test.hpp>
#include "../test_tools.hpp"
using namespace mlpack;
struct ImageConverterTestFixture
{
public:
ImageConverterTestFixture()
{
// Cache in the options for this program.
CLI::RestoreSettings(testName);
}
~ImageConverterTestFixture()
{
// Clear the settings.
remove("test_image777.png");
remove("test_image999.png");
bindings::tests::CleanMemory();
CLI::ClearSettings();
}
};
BOOST_FIXTURE_TEST_SUITE(ImageConverterMainTest,
ImageConverterTestFixture);
BOOST_AUTO_TEST_CASE(LoadImageTest)
{
SetInputParam<vector<string>>("input", {"test_image.png", "test_image.png"});
mlpackMain();
arma::mat output = CLI::GetParam<arma::mat>("output");
// width * height * channels.
BOOST_REQUIRE_EQUAL(output.n_rows, 50 * 50 * 3);
BOOST_REQUIRE_EQUAL(output.n_cols, 2);
}
BOOST_AUTO_TEST_CASE(SaveImageTest)
{
arma::mat testimage = arma::conv_to<arma::mat>::from(
arma::randi<arma::Mat<unsigned char>>((5 * 5 * 3), 2));
SetInputParam<vector<string>>("input", {"test_image777.png",
"test_image999.png"});
SetInputParam("height", 5);
SetInputParam("width", 5);
SetInputParam("channels", 3);
SetInputParam("save", true);
SetInputParam("dataset", testimage);
mlpackMain();
CLI::ClearSettings();
CLI::RestoreSettings(testName);
SetInputParam<vector<string>>("input", {"test_image777.png",
"test_image999.png"});
SetInputParam("height", 5);
SetInputParam("width", 5);
SetInputParam("channels", 3);
mlpackMain();
arma::mat output = CLI::GetParam<arma::mat>("output");
BOOST_REQUIRE_EQUAL(output.n_rows, 5 * 5 * 3);
BOOST_REQUIRE_EQUAL(output.n_cols, 2);
for (size_t i = 0; i < output.n_elem; ++i)
BOOST_REQUIRE_CLOSE(testimage[i], output[i], 1e-5);
}
/**
* Check whether binding throws error if height, width or channel are not
* specified.
*/
BOOST_AUTO_TEST_CASE(IncompleteTest)
{
arma::mat testimage = arma::conv_to<arma::mat>::from(
arma::randi<arma::Mat<unsigned char>>((5 * 5 * 3), 2));
SetInputParam<vector<string>>("input", {"test_image777.png",
"test_image999.png"});
SetInputParam("save", true);
SetInputParam("height", 50);
SetInputParam("width", 50);
SetInputParam("dataset", testimage);
Log::Fatal.ignoreInput = true;
BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
Log::Fatal.ignoreInput = false;
}
/**
* Check for invalid height values.
*/
BOOST_AUTO_TEST_CASE(InvalidInputTest)
{
arma::mat testimage = arma::conv_to<arma::mat>::from(
arma::randi<arma::Mat<unsigned char>>((5 * 5 * 3), 2));
SetInputParam<vector<string>>("input", {"test_image777.png",
"test_image999.png"});
SetInputParam("save", true);
SetInputParam("dataset", testimage);
SetInputParam("height", -50);
SetInputParam("width", 50);
SetInputParam("channels", 3);
Log::Fatal.ignoreInput = true;
BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
Log::Fatal.ignoreInput = false;
}
/**
* Check for invalid width values.
*/
BOOST_AUTO_TEST_CASE(InvalidWidthTest)
{
arma::mat testimage = arma::conv_to<arma::mat>::from(
arma::randi<arma::Mat<unsigned char>>((5 * 5 * 3), 2));
SetInputParam<vector<string>>("input", {"test_image777.png",
"test_image999.png"});
SetInputParam("save", true);
SetInputParam("dataset", testimage);
SetInputParam("height", 50);
SetInputParam("width", -50);
SetInputParam("channels", 3);
Log::Fatal.ignoreInput = true;
BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
Log::Fatal.ignoreInput = false;
}
/**
* Check for invalid channel values.
*/
BOOST_AUTO_TEST_CASE(InvalidChannelTest)
{
arma::mat testimage = arma::conv_to<arma::mat>::from(
arma::randi<arma::Mat<unsigned char>>((5 * 5 * 3), 2));
SetInputParam<vector<string>>("input", {"test_image777.png",
"test_image999.png"});
SetInputParam("save", true);
SetInputParam("dataset", testimage);
SetInputParam("height", 50);
SetInputParam("width", 50);
SetInputParam("channels", -1);
Log::Fatal.ignoreInput = true;
BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
Log::Fatal.ignoreInput = false;
}
/**
* Check for invalid input values.
*/
BOOST_AUTO_TEST_CASE(EmptyInputTest)
{
SetInputParam<vector<string>>("input", {});
SetInputParam("height", 50);
SetInputParam("width", 50);
SetInputParam("channels", 50);
Log::Fatal.ignoreInput = true;
BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
Log::Fatal.ignoreInput = false;
}
BOOST_AUTO_TEST_SUITE_END();
+8 -36
View File
@@ -18,6 +18,7 @@
#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/q_networks/simple_dqn.hpp>
#include <mlpack/methods/reinforcement_learning/environment/mountain_car.hpp>
#include <mlpack/methods/reinforcement_learning/environment/acrobot.hpp>
#include <mlpack/methods/reinforcement_learning/environment/cart_pole.hpp>
@@ -41,13 +42,7 @@ BOOST_AUTO_TEST_SUITE(QLearningTest);
BOOST_AUTO_TEST_CASE(CartPoleWithDQN)
{
// 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);
SimpleDQN<> model(4, 128, 128, 2);
// Set up the policy and replay method.
GreedyPolicy<CartPole> policy(1.0, 1000, 0.1, 0.99);
@@ -107,13 +102,7 @@ BOOST_AUTO_TEST_CASE(CartPoleWithDQN)
BOOST_AUTO_TEST_CASE(CartPoleWithDQNPrioritizedReplay)
{
// 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);
SimpleDQN<> model(4, 128, 128, 2);
// Set up the policy and replay method.
GreedyPolicy<CartPole> policy(1.0, 1000, 0.1);
@@ -182,13 +171,7 @@ BOOST_AUTO_TEST_CASE(CartPoleWithDoubleDQN)
for (size_t trial = 0; trial < 4; ++trial)
{
// Set up the network.
FFN<MeanSquaredError<>, GaussianInitialization> model(MeanSquaredError<>(),
GaussianInitialization(0, 0.001));
model.Add<Linear<>>(4, 20);
model.Add<ReLULayer<>>();
model.Add<Linear<>>(20, 20);
model.Add<ReLULayer<>>();
model.Add<Linear<>>(20, 2);
SimpleDQN<> model(4, 20, 20, 2);
// Set up the policy and replay method.
GreedyPolicy<CartPole> policy(1.0, 1000, 0.1, 0.99);
@@ -251,13 +234,7 @@ BOOST_AUTO_TEST_CASE(AcrobotWithDQN)
for (size_t trial = 0; trial < 3; ++trial)
{
// Set up the network.
FFN<MeanSquaredError<>, GaussianInitialization> model(MeanSquaredError<>(),
GaussianInitialization(0, 0.001));
model.Add<Linear<>>(4, 64);
model.Add<ReLULayer<>>();
model.Add<Linear<>>(64, 32);
model.Add<ReLULayer<>>();
model.Add<Linear<>>(32, 3);
SimpleDQN<> model(4, 64, 32, 3);
// Set up the policy and replay method.
GreedyPolicy<Acrobot> policy(1.0, 1000, 0.1, 0.99);
@@ -328,13 +305,7 @@ BOOST_AUTO_TEST_CASE(MountainCarWithDQN)
for (size_t trial = 0; trial < 3; trial++)
{
// Set up the network.
FFN<MeanSquaredError<>, GaussianInitialization> model(MeanSquaredError<>(),
GaussianInitialization(0, 0.001));
model.Add<Linear<>>(2, 64);
model.Add<ReLULayer<>>();
model.Add<Linear<>>(64, 32);
model.Add<ReLULayer<>>();
model.Add<Linear<>>(32, 3);
SimpleDQN<> model(2, 64, 32, 3);
// Set up the policy and replay method.
GreedyPolicy<MountainCar> policy(1.0, 1000, 0.1, 0.99);
@@ -404,7 +375,8 @@ BOOST_AUTO_TEST_CASE(DoublePoleCartWithDQN)
bool success = false;
for (size_t trial = 0; trial < 4; trial++)
{
// Set up the network.
// Set up the network. Note that we use a custom model here, and
// pass it directly into the agent, without using SimpleDQN.
FFN<MeanSquaredError<>, GaussianInitialization> model(MeanSquaredError<>(),
GaussianInitialization(0, 0.001));
model.Add<Linear<>>(6, 256);
+2 -7
View File
@@ -13,6 +13,7 @@
#include <mlpack/core.hpp>
#include <mlpack/methods/reinforcement_learning/environment/mountain_car.hpp>
#include <mlpack/methods/reinforcement_learning/q_networks/simple_dqn.hpp>
#include <mlpack/methods/reinforcement_learning/environment/continuous_mountain_car.hpp>
#include <mlpack/methods/reinforcement_learning/environment/cart_pole.hpp>
#include <mlpack/methods/reinforcement_learning/environment/acrobot.hpp>
@@ -63,13 +64,7 @@ BOOST_AUTO_TEST_CASE(RewardClippedAcrobotWithDQN)
for (size_t trial = 0; trial < 3; ++trial)
{
// Set up the network.
FFN<MeanSquaredError<>, GaussianInitialization> model(MeanSquaredError<>(),
GaussianInitialization(0, 0.001));
model.Add<Linear<>>(4, 64);
model.Add<ReLULayer<>>();
model.Add<Linear<>>(64, 32);
model.Add<ReLULayer<>>();
model.Add<Linear<>>(32, 3);
SimpleDQN<> model(4, 64, 32, 3);
// Set up the policy and replay method.
GreedyPolicy<RewardClipping<Acrobot>> policy(1.0, 1000, 0.1, 0.99);
+910 -5
View File
@@ -16,6 +16,8 @@
#include <mlpack/core/data/tokenizers/char_extract.hpp>
#include <mlpack/core/data/string_encoding.hpp>
#include <mlpack/core/data/string_encoding_policies/dictionary_encoding_policy.hpp>
#include <mlpack/core/data/string_encoding_policies/bag_of_words_encoding_policy.hpp>
#include <mlpack/core/data/string_encoding_policies/tf_idf_encoding_policy.hpp>
#include <boost/test/unit_test.hpp>
#include <memory>
#include "test_tools.hpp"
@@ -54,6 +56,25 @@ static vector<string> stringEncodingUtf8Input = {
"\xE2\x93\x82\xE2\x93\x81\xE2\x93\x85\xE2\x92\xB6\xE2\x92\xB8\xE2\x93\x80"
};
/**
* Check the values of two 2D vectors.
*/
template<typename ValueType>
void CheckVectors(const vector<vector<ValueType>>& a,
const vector<vector<ValueType>>& b,
const ValueType tolerance = 1e-5)
{
BOOST_REQUIRE_EQUAL(a.size(), b.size());
for (size_t i = 0; i < a.size(); i++)
{
BOOST_REQUIRE_EQUAL(a[i].size(), b[i].size());
for (size_t j = 0; j < a[i].size(); j++)
BOOST_REQUIRE_CLOSE(a[i][j], b[i][j], tolerance);
}
}
/**
* Test the dictionary encoding algorithm.
*/
@@ -88,7 +109,7 @@ BOOST_AUTO_TEST_CASE(DictionaryEncodingTest)
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
};
CheckMatrices(output, expected);
CheckMatrices(output, expected.t());
}
/**
@@ -122,7 +143,7 @@ BOOST_AUTO_TEST_CASE(UnicodeDictionaryEncodingTest)
{ 5, 2, 3, 5, 4 }
};
CheckMatrices(output, expected);
CheckMatrices(output, expected.t());
}
/**
@@ -222,8 +243,8 @@ BOOST_AUTO_TEST_CASE(SplitByAnyOfTokenizerUnicodeTest)
}
/**
* Test the CharExtract tokenizer.
*/
* Test the CharExtract tokenizer.
*/
BOOST_AUTO_TEST_CASE(DictionaryEncodingIndividualCharactersTest)
{
vector<string> input = {
@@ -242,7 +263,7 @@ BOOST_AUTO_TEST_CASE(DictionaryEncodingIndividualCharactersTest)
{ 2, 4, 3, 2, 4, 3, 5 },
{ 1, 2, 4, 0, 0, 0, 0 }
};
CheckMatrices(output, target);
CheckMatrices(output, target.t());
}
/**
@@ -520,5 +541,889 @@ BOOST_AUTO_TEST_CASE(CharExtractDictionaryEncodingSerialization)
CheckMatrices(output, xmlOutput, textOutput, binaryOutput);
}
/**
* Test the Bag of Words encoding algorithm.
*/
BOOST_AUTO_TEST_CASE(BagOfWordsEncodingTest)
{
using DictionaryType = StringEncodingDictionary<boost::string_view>;
arma::mat output;
BagOfWordsEncoding<SplitByAnyOf::TokenType> encoder;
SplitByAnyOf tokenizer(" ,.");
encoder.Encode(stringEncodingInput, output, tokenizer);
const DictionaryType& dictionary = encoder.Dictionary();
// Checking that each token has a unique label.
std::unordered_map<size_t, size_t> keysCount;
for (auto& keyValue : dictionary.Mapping())
{
keysCount[keyValue.second]++;
BOOST_REQUIRE_EQUAL(keysCount[keyValue.second], 1);
}
/* The expected values were obtained by the following Python script:
from sklearn.feature_extraction.text import CountVectorizer
from collections import OrderedDict
import re
string_encoding_input = [
"mlpack is an intuitive, fast, and flexible C++ machine learning library "
"with bindings to other languages. ",
"It is meant to be a machine learning analog to LAPACK, and aims to "
"implement a wide array of machine learning methods and functions "
"as a \"swiss army knife\" for machine learning researchers.",
"In addition to its powerful C++ interface, mlpack also provides "
"command-line programs and Python bindings."
]
dictionary = OrderedDict()
count = 0
for line in string_encoding_input:
for word in re.split(' |,|\.', line):
if word and (not (word in dictionary)):
dictionary[word] = count
count += 1
def tokenizer(line):
return re.split(' |,|\.', line)
vectorizer = CountVectorizer(strip_accents=False, lowercase=False,
preprocessor=None, tokenizer=tokenizer, stop_words=None,
vocabulary=dictionary, binary=False)
X = vectorizer.fit_transform(string_encoding_input)
for row in X.toarray():
print("{ " + ", ".join(map(str, row)) + " },")
*/
arma::mat expected = {
{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 1, 0, 0, 0, 2, 0, 0, 3, 3, 0, 0, 0, 3, 0, 0, 1, 1, 1, 3, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }
};
CheckMatrices(output, expected.t());
}
/**
* Test the Bag of Words encoding algorithm. The output is saved into a vector.
*/
BOOST_AUTO_TEST_CASE(VectorBagOfWordsEncodingTest)
{
using DictionaryType = StringEncodingDictionary<boost::string_view>;
vector<vector<size_t>> output;
BagOfWordsEncoding<SplitByAnyOf::TokenType> encoder(
(BagOfWordsEncodingPolicy()));
SplitByAnyOf tokenizer(" ,.");
encoder.Encode(stringEncodingInput, output, tokenizer);
const DictionaryType& dictionary = encoder.Dictionary();
// Checking that each token has a unique label.
std::unordered_map<size_t, size_t> keysCount;
for (auto& keyValue : dictionary.Mapping())
{
keysCount[keyValue.second]++;
BOOST_REQUIRE_EQUAL(keysCount[keyValue.second], 1);
}
/* The expected values were obtained by the same script as in
BagOfWordsEncodingTest. */
vector<vector<size_t>> expected = {
{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 1, 0, 0, 0, 2, 0, 0, 3, 3, 0, 0, 0, 3, 0, 0, 1, 1, 1, 3, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }
};
BOOST_REQUIRE(output == expected);
}
/**
* Test the Bag of Words algorithm for individual characters.
*/
BOOST_AUTO_TEST_CASE(BagOfWordsEncodingIndividualCharactersTest)
{
vector<string> input = {
"GACCA",
"ABCABCD",
"GAB"
};
arma::mat output;
BagOfWordsEncoding<CharExtract::TokenType> encoder;
encoder.Encode(input, output, CharExtract());
arma::mat target = {
{ 1, 2, 2, 0, 0 },
{ 0, 2, 2, 2, 1 },
{ 1, 1, 0, 1, 0 }
};
CheckMatrices(output, target.t());
}
/**
* Test the Bag of Words encoding algorithm in case of individual
* characters encoding. The output type is vector<vector<size_t>>.
*/
BOOST_AUTO_TEST_CASE(VectorBagOfWordsEncodingIndividualCharactersTest)
{
std::vector<string> input = {
"GACCA",
"ABCABCD",
"GAB"
};
vector<vector<size_t>> output;
BagOfWordsEncoding<CharExtract::TokenType> encoder;
encoder.Encode(input, output, CharExtract());
vector<vector<size_t>> expected = {
{ 1, 2, 2, 0, 0 },
{ 0, 2, 2, 2, 1 },
{ 1, 1, 0, 1, 0 }
};
BOOST_REQUIRE(output == expected);
}
/**
* Test the Tf-Idf encoding algorithm with the raw count term frequency type
* and the smooth inverse document frequency type. These parameters are
* the default ones.
*/
BOOST_AUTO_TEST_CASE(RawCountSmoothIdfEncodingTest)
{
using DictionaryType = StringEncodingDictionary<boost::string_view>;
arma::mat output;
TfIdfEncoding<SplitByAnyOf::TokenType> encoder;
SplitByAnyOf tokenizer(" ,.");
encoder.Encode(stringEncodingInput, output, tokenizer);
const DictionaryType& dictionary = encoder.Dictionary();
// Checking that each token has a unique label.
std::unordered_map<size_t, size_t> keysCount;
for (auto& keyValue : dictionary.Mapping())
{
keysCount[keyValue.second]++;
BOOST_REQUIRE_EQUAL(keysCount[keyValue.second], 1);
}
/* The expected values were obtained by the following Python script:
from sklearn.feature_extraction.text import TfidfVectorizer
from collections import OrderedDict
import re
string_encoding_input = [
"mlpack is an intuitive, fast, and flexible C++ machine learning library "
"with bindings to other languages. ",
"It is meant to be a machine learning analog to LAPACK, and aims to "
"implement a wide array of machine learning methods and functions "
"as a \"swiss army knife\" for machine learning researchers.",
"In addition to its powerful C++ interface, mlpack also provides "
"command-line programs and Python bindings."
]
smooth_idf = True
tf_type = 'raw_count'
dictionary = OrderedDict()
count = 0
for line in string_encoding_input:
for word in re.split(' |,|\.', line):
if word and (not (word in dictionary)):
dictionary[word] = count
count += 1
def tokenizer(line):
return re.split(' |,|\.', line)
if tf_type == 'raw_count':
binary = False
sublinear_tf = False
elif tf_type == 'binary':
binary = True
sublinear_tf = False
elif tf_type == 'sublinear_tf':
binary = False
sublinear_tf = True
vectorizer = TfidfVectorizer(strip_accents=False, lowercase=False,
preprocessor=None, tokenizer=tokenizer, stop_words=None,
vocabulary=dictionary, binary=binary, norm=None, smooth_idf=smooth_idf,
sublinear_tf=sublinear_tf)
X = vectorizer.fit_transform(string_encoding_input)
def format_result(value):
if value == int(value):
return str(int(value))
else:
return "{0:.8f}".format(value)
for row in X.toarray():
print("{ " + ", ".join(map(format_result, row)) + " },")
*/
arma::mat expected = {
{ 1.28768207, 1.28768207, 1.69314718, 1.69314718, 1.69314718, 1, 1.69314718,
1.28768207, 1.28768207, 1.28768207, 1.69314718, 1.69314718, 1.28768207, 1,
1.69314718, 1.69314718, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 1.28768207, 0, 0, 0, 2, 0, 0, 3.86304622, 3.86304622, 0, 0, 0, 3, 0,
0, 1.69314718, 1.69314718, 1.69314718, 5.07944154, 1.69314718, 1.69314718,
1.69314718, 1.69314718, 1.69314718, 1.69314718, 1.69314718, 1.69314718,
1.69314718, 1.69314718, 1.69314718, 1.69314718, 1.69314718, 1.69314718,
1.69314718, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 1.28768207, 0, 0, 0, 0, 1, 0, 1.28768207, 0, 0, 0, 0, 1.28768207, 1, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.69314718,
1.69314718, 1.69314718, 1.69314718, 1.69314718, 1.69314718, 1.69314718,
1.69314718, 1.69314718, 1.69314718 }
};
CheckMatrices(output, expected.t(), 1e-6);
}
/**
* Test the Tf-Idf encoding algorithm with the raw count term frequency type
* and the smooth inverse document frequency type. These parameters are
* the default ones. The output type is vector<vector<double>>.
*/
BOOST_AUTO_TEST_CASE(VectorRawCountSmoothIdfEncodingTest)
{
using DictionaryType = StringEncodingDictionary<boost::string_view>;
vector<vector<double>> output;
TfIdfEncoding<SplitByAnyOf::TokenType> encoder(
(TfIdfEncodingPolicy()));
SplitByAnyOf tokenizer(" ,.");
encoder.Encode(stringEncodingInput, output, tokenizer);
const DictionaryType& dictionary = encoder.Dictionary();
// Checking that each token has a unique label.
std::unordered_map<size_t, size_t> keysCount;
for (auto& keyValue : dictionary.Mapping())
{
keysCount[keyValue.second]++;
BOOST_REQUIRE_EQUAL(keysCount[keyValue.second], 1);
}
/* The expected values were obtained by the same script as in
RawCountSmoothIdfEncodingTest. */
vector<vector<double>> expected = {
{ 1.28768207, 1.28768207, 1.69314718, 1.69314718, 1.69314718, 1, 1.69314718,
1.28768207, 1.28768207, 1.28768207, 1.69314718, 1.69314718, 1.28768207, 1,
1.69314718, 1.69314718, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 1.28768207, 0, 0, 0, 2, 0, 0, 3.86304622, 3.86304622, 0, 0, 0, 3, 0,
0, 1.69314718, 1.69314718, 1.69314718, 5.07944154, 1.69314718, 1.69314718,
1.69314718, 1.69314718, 1.69314718, 1.69314718, 1.69314718, 1.69314718,
1.69314718, 1.69314718, 1.69314718, 1.69314718, 1.69314718, 1.69314718,
1.69314718, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 1.28768207, 0, 0, 0, 0, 1, 0, 1.28768207, 0, 0, 0, 0, 1.28768207, 1, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.69314718,
1.69314718, 1.69314718, 1.69314718, 1.69314718, 1.69314718, 1.69314718,
1.69314718, 1.69314718, 1.69314718 }
};
CheckVectors(output, expected, 1e-6);
}
/**
* Test the Tf-Idf encoding algorithm for individual characters with the
* raw count term frequency type and the smooth inverse document frequency type.
* These parameters are the default ones.
*/
BOOST_AUTO_TEST_CASE(RawCountSmoothIdfEncodingIndividualCharactersTest)
{
vector<string> input = {
"GACCA",
"ABCABCD",
"GAB"
};
arma::mat output;
TfIdfEncoding<CharExtract::TokenType> encoder;
encoder.Encode(input, output, CharExtract());
/* The expected values were obtained by the following Python script:
from sklearn.feature_extraction.text import TfidfVectorizer
from collections import OrderedDict
import re
input_string = [
"GACCA",
"ABCABCD",
"GAB"
]
smooth_idf = True
tf_type = 'raw_count'
dictionary = OrderedDict()
count = 0
for line in input_string:
for word in list(line):
if word and (not (word in dictionary)):
dictionary[word] = count
count += 1
def tokenizer(line):
return list(line)
if tf_type == 'raw_count':
binary = False
sublinear_tf = False
elif tf_type == 'binary':
binary = True
sublinear_tf = False
elif tf_type == 'sublinear_tf':
binary = False
sublinear_tf = True
vectorizer = TfidfVectorizer(strip_accents=False, lowercase=False,
preprocessor=None, tokenizer=tokenizer, stop_words=None,
vocabulary=dictionary, binary=binary, norm=None, smooth_idf=smooth_idf,
sublinear_tf=sublinear_tf)
X = vectorizer.fit_transform(input_string)
def format_result(value):
if value == int(value):
return str(int(value))
else:
return "{0:.14f}".format(value)
for row in X.toarray():
print("{ " + ", ".join(map(format_result, row)) + " },")
*/
arma::mat target = {
{ 1.28768207245178, 2, 2.57536414490356, 0, 0 },
{ 0, 2, 2.57536414490356, 2.57536414490356, 1.69314718055995 },
{ 1.28768207245178, 1, 0, 1.28768207245178, 0 }
};
CheckMatrices(output, target.t(), 1e-12);
}
/**
* Test the Tf-Idf encoding algorithm for individual characters with the
* raw count term frequency type and the smooth inverse document frequency type.
* These parameters are the default ones. The output type is
* vector<vector<double>>.
*/
BOOST_AUTO_TEST_CASE(VectorRawCountSmoothIdfEncodingIndividualCharactersTest)
{
std::vector<string> input = {
"GACCA",
"ABCABCD",
"GAB"
};
vector<vector<double>> output;
TfIdfEncoding<CharExtract::TokenType> encoder;
encoder.Encode(input, output, CharExtract());
/* The expected values were obtained by the same script as in
RawCountSmoothIdfEncodingIndividualCharactersTest. */
vector<vector<double>> expected = {
{ 1.28768207245178, 2, 2.57536414490356, 0, 0 },
{ 0, 2, 2.57536414490356, 2.57536414490356, 1.69314718055995 },
{ 1.28768207245178, 1, 0, 1.28768207245178, 0 }
};
CheckVectors(output, expected, 1e-12);
}
/**
* Test the Tf-Idf encoding algorithm with the raw count term frequency type
* and the non-smooth inverse document frequency type.
*/
BOOST_AUTO_TEST_CASE(TfIdfRawCountEncodingTest)
{
using DictionaryType = StringEncodingDictionary<boost::string_view>;
arma::mat output;
TfIdfEncoding<SplitByAnyOf::TokenType> encoder(
TfIdfEncodingPolicy(TfIdfEncodingPolicy::TfTypes::RAW_COUNT, false));
SplitByAnyOf tokenizer(" ,.");
encoder.Encode(stringEncodingInput, output, tokenizer);
const DictionaryType& dictionary = encoder.Dictionary();
// Checking that each token has a unique label.
std::unordered_map<size_t, size_t> keysCount;
for (auto& keyValue : dictionary.Mapping())
{
keysCount[keyValue.second]++;
BOOST_REQUIRE_EQUAL(keysCount[keyValue.second], 1);
}
/* The expected values were obtained by almost the same script as in
RawCountSmoothIdfEncodingTest. The only difference is smooth_idf equals
False. */
arma::mat expected = {
{ 1.40546511, 1.40546511, 2.09861229, 2.09861229, 2.09861229, 1, 2.09861229,
1.40546511, 1.40546511, 1.40546511, 2.09861229, 2.09861229, 1.40546511, 1,
2.09861229, 2.09861229, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 1.40546511, 0, 0, 0, 2, 0, 0, 4.21639532, 4.21639532, 0, 0, 0, 3, 0, 0,
2.09861229, 2.09861229, 2.09861229, 6.29583687, 2.09861229, 2.09861229,
2.09861229, 2.09861229, 2.09861229, 2.09861229, 2.09861229, 2.09861229,
2.09861229, 2.09861229, 2.09861229, 2.09861229, 2.09861229, 2.09861229,
2.09861229, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 1.40546511, 0, 0, 0, 0, 1, 0, 1.40546511, 0, 0, 0, 0, 1.40546511, 1, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.09861229,
2.09861229, 2.09861229, 2.09861229, 2.09861229, 2.09861229, 2.09861229,
2.09861229, 2.09861229, 2.09861229 }
};
CheckMatrices(output, expected.t(), 1e-6);
}
/**
* Test the Tf-Idf encoding algorithm with the raw count term frequency type
* and the non-smooth inverse document frequency type. The output type is
* vector<vector<double>>.
*/
BOOST_AUTO_TEST_CASE(VectorTfIdfRawCountEncodingTest)
{
using DictionaryType = StringEncodingDictionary<boost::string_view>;
vector<vector<double>> output;
TfIdfEncoding<SplitByAnyOf::TokenType>
encoder(TfIdfEncodingPolicy::TfTypes::RAW_COUNT, false);
SplitByAnyOf tokenizer(" ,.");
encoder.Encode(stringEncodingInput, output, tokenizer);
const DictionaryType& dictionary = encoder.Dictionary();
// Checking that each token has a unique label.
std::unordered_map<size_t, size_t> keysCount;
for (auto& keyValue : dictionary.Mapping())
{
keysCount[keyValue.second]++;
BOOST_REQUIRE_EQUAL(keysCount[keyValue.second], 1);
}
/* The expected values were obtained by almost the same script as in
RawCountSmoothIdfEncodingTest. The only difference is smooth_idf equals
False. */
vector<vector<double>> expected = {
{ 1.40546511, 1.40546511, 2.09861229, 2.09861229, 2.09861229, 1, 2.09861229,
1.40546511, 1.40546511, 1.40546511, 2.09861229, 2.09861229, 1.40546511, 1,
2.09861229, 2.09861229, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 1.40546511, 0, 0, 0, 2, 0, 0, 4.21639532, 4.21639532, 0, 0, 0, 3, 0, 0,
2.09861229, 2.09861229, 2.09861229, 6.29583687, 2.09861229, 2.09861229,
2.09861229, 2.09861229, 2.09861229, 2.09861229, 2.09861229, 2.09861229,
2.09861229, 2.09861229, 2.09861229, 2.09861229, 2.09861229, 2.09861229,
2.09861229, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 1.40546511, 0, 0, 0, 0, 1, 0, 1.40546511, 0, 0, 0, 0, 1.40546511, 1, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.09861229,
2.09861229, 2.09861229, 2.09861229, 2.09861229, 2.09861229, 2.09861229,
2.09861229, 2.09861229, 2.09861229 }
};
CheckVectors(output, expected, 1e-6);
}
/**
* Test the Tf-Idf encoding algorithm for individual characters with the
* raw count term frequency type and the non-smooth inverse document frequency
* type.
*/
BOOST_AUTO_TEST_CASE(RawCountTfIdfEncodingIndividualCharactersTest)
{
vector<string> input = {
"GACCA",
"ABCABCD",
"GAB"
};
arma::mat output;
TfIdfEncoding<CharExtract::TokenType> encoder(
TfIdfEncodingPolicy::TfTypes::RAW_COUNT, false);
encoder.Encode(input, output, CharExtract());
/* The expected values were obtained by almost the same script as in
RawCountSmoothIdfEncodingIndividualCharactersTest. The only difference is
smooth_idf equals False. */
arma::mat target = {
{ 1.40546510810816, 2, 2.81093021621633, 0, 0 },
{ 0, 2, 2.81093021621633, 2.81093021621633, 2.09861228866811 },
{ 1.40546510810816, 1, 0, 1.40546510810816, 0 }
};
CheckMatrices(output, target.t(), 1e-12);
}
/**
* Test the Tf-Idf encoding algorithm for individual characters with the
* raw count term frequency type and the non-smooth inverse document frequency
* type. The output type is vector<vector<double>>.
*/
BOOST_AUTO_TEST_CASE(VectorRawCountTfIdfEncodingIndividualCharactersTest)
{
std::vector<string> input = {
"GACCA",
"ABCABCD",
"GAB"
};
vector<vector<double>> output;
TfIdfEncoding<CharExtract::TokenType> encoder(
TfIdfEncodingPolicy::TfTypes::RAW_COUNT, false);
encoder.Encode(input, output, CharExtract());
/* The expected values were obtained by almost the same script as in
RawCountSmoothIdfEncodingIndividualCharactersTest. The only difference is
smooth_idf equals False. */
vector<vector<double>> expected = {
{ 1.40546510810816, 2, 2.81093021621633, 0, 0 },
{ 0, 2, 2.81093021621633, 2.81093021621633, 2.09861228866811 },
{ 1.40546510810816, 1, 0, 1.40546510810816, 0 }
};
CheckVectors(output, expected, 1e-12);
}
/**
* Test the Tf-Idf encoding algorithm for individual characters with the
* binary term frequency type and the smooth inverse document frequency type.
*/
BOOST_AUTO_TEST_CASE(BinarySmoothIdfEncodingIndividualCharactersTest)
{
vector<string> input = {
"GACCA",
"ABCABCD",
"GAB"
};
arma::mat output;
TfIdfEncoding<CharExtract::TokenType> encoder(
TfIdfEncodingPolicy::TfTypes::BINARY, true);
encoder.Encode(input, output, CharExtract());
/* The expected values were obtained by almost the same script as in
RawCountSmoothIdfEncodingIndividualCharactersTest. The only difference is
tf_type equals 'binary'. */
arma::mat target = {
{ 1.28768207245178, 1, 1.28768207245178, 0, 0 },
{ 0, 1, 1.28768207245178, 1.28768207245178, 1.69314718055995 },
{ 1.28768207245178, 1, 0, 1.28768207245178, 0 }
};
CheckMatrices(output, target.t(), 1e-12);
}
/**
* Test the Tf-Idf encoding algorithm for individual characters with the
* binary term frequency type and the smooth inverse document frequency type.
* The output type is vector<vector<double>>.
*/
BOOST_AUTO_TEST_CASE(VectorBinarySmoothIdfEncodingIndividualCharactersTest)
{
std::vector<string> input = {
"GACCA",
"ABCABCD",
"GAB"
};
vector<vector<double>> output;
TfIdfEncoding<CharExtract::TokenType>
encoder(TfIdfEncodingPolicy::TfTypes::BINARY, true);
encoder.Encode(input, output, CharExtract());
/* The expected values were obtained by almost the same script as in
RawCountSmoothIdfEncodingIndividualCharactersTest. The only difference is
tf_type equals 'binary'. */
vector<vector<double>> expected = {
{ 1.28768207245178, 1, 1.28768207245178, 0, 0 },
{ 0, 1, 1.28768207245178, 1.28768207245178, 1.69314718055995 },
{ 1.28768207245178, 1, 0, 1.28768207245178, 0 }
};
CheckVectors(output, expected, 1e-12);
}
/**
* Test the Tf-Idf encoding algorithm for individual characters with the
* binary term frequency type and the non-smooth inverse document frequency
* type.
*/
BOOST_AUTO_TEST_CASE(BinaryTfIdfEncodingIndividualCharactersTest)
{
vector<string> input = {
"GACCA",
"ABCABCD",
"GAB"
};
arma::mat output;
TfIdfEncoding<CharExtract::TokenType> encoder(
TfIdfEncodingPolicy::TfTypes::BINARY, false);
encoder.Encode(input, output, CharExtract());
/* The expected values were obtained by almost the same script as in
RawCountSmoothIdfEncodingIndividualCharactersTest. The only difference is
tf_type equals 'binary' and smooth_idf equals False. */
arma::mat target = {
{ 1.40546510810816, 1, 1.40546510810816, 0, 0 },
{ 0, 1, 1.40546510810816, 1.40546510810816, 2.09861228866811 },
{ 1.40546510810816, 1, 0, 1.40546510810816, 0 }
};
CheckMatrices(output, target.t(), 1e-12);
}
/**
* Test the Tf-Idf encoding algorithm for individual characters with the
* sublinear term frequency type and the smooth inverse document frequency
* type.
*/
BOOST_AUTO_TEST_CASE(SublinearSmoothIdfEncodingIndividualCharactersTest)
{
vector<string> input = {
"GACCA",
"ABCABCD",
"GAB"
};
arma::mat output;
TfIdfEncoding<CharExtract::TokenType> encoder(
TfIdfEncodingPolicy::TfTypes::SUBLINEAR_TF, true);
encoder.Encode(input, output, CharExtract());
/* The expected values were obtained by almost the same script as in
RawCountSmoothIdfEncodingIndividualCharactersTest. The only difference is
tf_type equals 'sublinear_tf'. */
arma::mat target = {
{ 1.28768207245178, 1.69314718055995, 2.18023527042932, 0, 0 },
{ 0, 1.69314718055995, 2.18023527042932, 2.18023527042932,
1.69314718055995 },
{ 1.28768207245178, 1, 0, 1.28768207245178, 0 }
};
CheckMatrices(output, target.t(), 1e-12);
}
/**
* Test the Tf-Idf encoding algorithm for individual characters with the
* sublinear term frequency type and the non-smooth inverse document frequency
* type.
*/
BOOST_AUTO_TEST_CASE(SublinearTfIdfEncodingIndividualCharactersTest)
{
vector<string> input = {
"GACCA",
"ABCABCD",
"GAB"
};
arma::mat output;
TfIdfEncoding<CharExtract::TokenType>
encoder(TfIdfEncodingPolicy::TfTypes::SUBLINEAR_TF, false);
encoder.Encode(input, output, CharExtract());
/* The expected values were obtained by almost the same script as in
RawCountSmoothIdfEncodingIndividualCharactersTest. The only difference is
tf_type equals 'sublinear_tf' and smooth_idf equals False. */
arma::mat target = {
{ 1.40546510810816, 1.69314718055995, 2.37965928516872, 0, 0 },
{ 0, 1.69314718055995, 2.37965928516872, 2.37965928516872,
2.09861228866811 },
{ 1.40546510810816, 1, 0, 1.40546510810816, 0 }
};
CheckMatrices(output, target.t(), 1e-12);
}
/**
* Test the Tf-Idf encoding algorithm for individual characters with the
* standard term frequency type and the smooth inverse document frequency
* type.
*/
BOOST_AUTO_TEST_CASE(TermFrequencySmoothIdfEncodingIndividualCharactersTest)
{
vector<string> input = {
"GACCA",
"ABCABCD",
"GAB"
};
arma::mat output;
TfIdfEncoding<CharExtract::TokenType> encoder(
TfIdfEncodingPolicy::TfTypes::TERM_FREQUENCY, true);
encoder.Encode(input, output, CharExtract());
/* The expected values were obtained by the following Python script:
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.feature_extraction.text import TfidfTransformer
from collections import OrderedDict
import numpy as np
import re
input_string = [
"GACCA",
"ABCABCD",
"GAB"
]
smooth_idf = True
dictionary = OrderedDict()
count = 0
for line in input_string:
for word in list(line):
if word and (not (word in dictionary)):
dictionary[word] = count
count += 1
def tokenizer(line):
return list(line)
vectorizer = CountVectorizer(strip_accents=False, lowercase=False,
preprocessor=None, tokenizer=tokenizer, stop_words=None,
vocabulary=dictionary, binary=False)
count = vectorizer.fit_transform(input_string)
lens = np.array(list(map(len, input_string))).reshape(len(input_string), 1)
tf = count.toarray() / lens
transformer = TfidfTransformer(norm=None, smooth_idf=smooth_idf,
sublinear_tf=False)
X = transformer.fit_transform(tf)
def format_result(value):
if value == int(value):
return str(int(value))
else:
return "{0:.16}".format(value)
for row in X.toarray():
print("{ " + ", ".join(map(format_result, row)) + " },")
*/
arma::mat target = {
{ 0.2575364144903562, 0.4, 0.5150728289807124, 0, 0 },
{ 0, 0.2857142857142857, 0.3679091635576516, 0.3679091635576516,
0.2418781686514208 },
{ 0.4292273574839269, 0.3333333333333333, 0, 0.4292273574839269, 0 }
};
CheckMatrices(output, target.t(), 1e-12);
}
/**
* Test the Tf-Idf encoding algorithm for individual characters with the
* standard term frequency type and the non-smooth inverse document frequency
* type.
*/
BOOST_AUTO_TEST_CASE(TermFrequencyTfIdfEncodingIndividualCharactersTest)
{
vector<string> input = {
"GACCA",
"ABCABCD",
"GAB"
};
arma::mat output;
TfIdfEncoding<CharExtract::TokenType> encoder(
TfIdfEncodingPolicy::TfTypes::TERM_FREQUENCY, false);
encoder.Encode(input, output, CharExtract());
/* The expected values were obtained by almost the same script as in
TermFrequencySmoothIdfEncodingIndividualCharactersTest. The only difference
is smooth_idf equals False. */
arma::mat target = {
{ 0.2810930216216329, 0.4, 0.5621860432432658, 0, 0 },
{ 0, 0.2857142857142857, 0.4015614594594755, 0.4015614594594755,
0.2998017555240157 },
{ 0.4684883693693881, 0.3333333333333333, 0, 0.4684883693693881, 0 }
};
CheckMatrices(output, target.t(), 1e-12);
}
/**
* Serialization test for the Tf-Idf encoding algorithm with
* the SplitByAnyOf tokenizer.
*/
BOOST_AUTO_TEST_CASE(SplitByAnyOfTfIdfEncodingSerialization)
{
using EncoderType = TfIdfEncoding<SplitByAnyOf::TokenType>;
EncoderType encoder;
SplitByAnyOf tokenizer(" ,.\"");
arma::mat output;
encoder.Encode(stringEncodingInput, output, tokenizer);
EncoderType xmlEncoder, textEncoder, binaryEncoder;
arma::mat xmlOutput, textOutput, binaryOutput;
SerializeObjectAll(encoder, xmlEncoder, textEncoder, binaryEncoder);
CheckDictionaries(encoder.Dictionary(), xmlEncoder.Dictionary());
CheckDictionaries(encoder.Dictionary(), textEncoder.Dictionary());
CheckDictionaries(encoder.Dictionary(), binaryEncoder.Dictionary());
xmlEncoder.Encode(stringEncodingInput, xmlOutput, tokenizer);
textEncoder.Encode(stringEncodingInput, textOutput, tokenizer);
binaryEncoder.Encode(stringEncodingInput, binaryOutput, tokenizer);
CheckMatrices(output, xmlOutput, textOutput, binaryOutput);
}
BOOST_AUTO_TEST_SUITE_END();