Merge branch 'master' into cereal

Signed-off-by: Omar Shrit <omar@shrit.me>
This commit is contained in:
Omar Shrit
2020-09-08 13:37:43 +02:00
31 changed files with 956 additions and 440 deletions
+4 -3
View File
@@ -24,8 +24,9 @@ steps:
sudo apt-get install -y --allow-unauthenticated libopenblas-dev liblapack-dev g++ libboost1.70-dev libarmadillo-dev xz-utils libcereal-dev
if [ "$(binding)" == "python" ]; then
/usr/bin/python3 -m pip install --upgrade pip
/usr/bin/python3 -m pip install --upgrade --ignore-installed setuptools cython pandas
export PYBIN=$(which python)
$PYBIN -m pip install --upgrade pip
$PYBIN -m pip install --upgrade --ignore-installed setuptools cython pandas
fi
if [ "a$(julia.version)" != "a" ]; then
@@ -55,7 +56,7 @@ steps:
export GOPATH=$PWD/src/mlpack/bindings/go
go get -u -t gonum.org/v1/gonum/...
fi
cmake $(CMakeArgs) ..
cmake $(CMakeArgs) -DPYTHON_EXECUTABLE=`which python` ..
displayName: 'CMake'
# Build mlpack
+2
View File
@@ -418,6 +418,8 @@ find_package(cereal "${CEREAL_VERSION}" REQUIRED)
# Unfortunately this configuration variable is necessary and will need to be
# updated as time goes on and new versions are released.
set(Boost_ADDITIONAL_VERSIONS
"1.74.0" "1.74"
"17.3.0" "17.3"
"1.72.0" "1.72"
"1.71.0" "1.71"
"1.70.0" "1.70"
+1 -1
View File
@@ -4,7 +4,7 @@
# Project related configuration options
#---------------------------------------------------------------------------
PROJECT_NAME = mlpack
PROJECT_NUMBER = 3.3.2
PROJECT_NUMBER = 3.4.1
OUTPUT_DIRECTORY = ./doc
CREATE_SUBDIRS = NO
OUTPUT_LANGUAGE = English
+16
View File
@@ -1,5 +1,21 @@
### mlpack ?.?.?
###### ????-??-??
### mlpack 3.4.1
###### 2020-09-07
* Fix incorrect parsing of required matrix/model parameters for command-line
bindings (#2600).
* Add manual type specification support to `data::Load()` and `data::Save()`
(#2084, #2135, #2602).
* Remove use of internal Armadillo functionality (#2596, #2601, #2602).
### mlpack 3.4.0
###### 2020-09-01
* Issue warnings when metrics produce NaNs in KFoldCV (#2595).
* Added bindings for _R_ during Google Summer of Code (#2556).
* Added common striptype function for all bindings (#2556).
+2 -2
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.4.1.tar.gz">current stable version (3.4.1)</a>
</em>
</p>
@@ -153,7 +153,7 @@ on Ubuntu, you can install mlpack with the following command:
Note: Older Ubuntu versions may not have the most recent version of mlpack
available---for instance, at the time of this writing, Ubuntu 16.04 only has
mlpack 3.2.2 available. Options include upgrading your Ubuntu version, finding
mlpack 3.4.1 available. Options include upgrading your Ubuntu version, finding
a PPA or other non-official sources, or installing with a manual build.
There are some useful pages to consult in addition to this section:
@@ -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.2\build\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>C:\boost\boost_1_66_0;C:\mlpack\armadillo-8.500.1\include;C:\mlpack\mlpack-3.4.1\build\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>C:\mlpack\mlpack-3.2.2\build\Debug\mlpack.lib;C:\boost\boost_1_66_0\lib64-msvc-14.1\libboost_serialization-vc141-mt-gd-x64-1_66.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>C:\mlpack\mlpack-3.4.1\build\Debug\mlpack.lib;C:\boost\boost_1_66_0\lib64-msvc-14.1\libboost_serialization-vc141-mt-gd-x64-1_66.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<PostBuildEvent>
<Command>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)
<Command>xcopy /y "C:\mlpack\mlpack-3.4.1\build\Debug\mlpack.dll" $(OutDir)
xcopy /y "C:\mlpack\mlpack-3.4.1\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.4.1.tar.gz">mlpack-3.4.1</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.4.1.tar.gz
$ tar -xvzpf mlpack-3.4.1.tar.gz
$ mkdir mlpack-3.4.1/build && cd mlpack-3.4.1/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.4.1.tar.gz
$ cd mlpack-3.4.1
$ mkdir build
@endcode
+3 -3
View File
@@ -32,9 +32,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.2.tar.gz
tar -xvzpf mlpack-3.2.2.tar.gz
mkdir -p mlpack-3.2.2/build/ && cd mlpack-3.2.2/build/
wget https://www.mlpack.org/files/mlpack-3.4.1.tar.gz
tar -xvzpf mlpack-3.4.1.tar.gz
mkdir -p mlpack-3.4.1/build/ && cd mlpack-3.4.1/build/
cmake ../ && make -j4 && sudo make install
@endcode
+4 -4
View File
@@ -29,17 +29,17 @@ 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.4.1\build\include
@endcode
- Under Linker > Input > Additional Dependencies add:
@code
- C:\mlpack\mlpack-3.2.2\build\Debug\mlpack.lib
- C:\mlpack\mlpack-3.4.1\build\Debug\mlpack.lib
- C:\boost\boost_1_71_0\lib64-msvc-14.2\libboost_serialization-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.4.1\build\Debug\mlpack.dll" $(OutDir)
- xcopy /y "C:\mlpack\mlpack-3.4.1\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
+1 -1
View File
@@ -54,7 +54,7 @@ target_link_libraries(mlpack ${MLPACK_LIBRARIES})
set_target_properties(mlpack
PROPERTIES
VERSION 3.3
VERSION 3.4
SOVERSION 3
)
@@ -47,8 +47,8 @@ void ParseCommandLine(int argc, char** argv)
{
// Add the parameter to desc.
util::ParamData& d = it->second;
IO::GetSingleton().functionMap[d.tname]["AddToCLI11"]
(d, NULL, (void*) &app);
IO::GetSingleton().functionMap[d.tname]["AddToCLI11"](d, NULL, (void*)
&app);
}
// Mark that we did parsing.
@@ -136,13 +136,15 @@ void ParseCommandLine(int argc, char** argv)
util::ParamData d = iter->second;
if (d.required)
{
const std::string cliName;
// CLI11 expects the parameter name to have "--" prepended.
std::string cliName;
IO::GetSingleton().functionMap[d.tname]["MapParameterName"](d, NULL,
(void*) &cliName);
cliName = "--" + cliName;
if (!app.count(cliName))
{
Log::Fatal << "Required option --" << cliName << " is undefined."
Log::Fatal << "Required option " << cliName << " is undefined."
<< std::endl;
}
}
+16 -1
View File
@@ -246,17 +246,32 @@ double KFoldCV<MLAlgorithm,
{
arma::vec evaluations(k);
size_t numInvalidScores = 0;
for (size_t i = 0; i < k; ++i)
{
MLAlgorithm&& model = base.Train(GetTrainingSubset(xs, i),
GetTrainingSubset(ys, i), args...);
evaluations(i) = Metric::Evaluate(model, GetValidationSubset(xs, i),
GetValidationSubset(ys, i));
if (std::isnan(evaluations(i)) || std::isinf(evaluations(i)))
{
++numInvalidScores;
Log::Warn << "KFoldCV::TrainAndEvaluate(): fold " << i << " returned "
<< "a score of " << evaluations(i) << "; ignoring when computing "
<< "the average score." << std::endl;
}
if (i == k - 1)
modelPtr.reset(new MLAlgorithm(std::move(model)));
}
return arma::mean(evaluations);
if (numInvalidScores == k)
{
Log::Warn << "KFoldCV::TrainAndEvaluate(): all folds returned invalid "
<< "scores! Returning 0.0 as overall score." << std::endl;
return 0.0;
}
return arma::mean(evaluations.elem(arma::find_finite(evaluations)));
}
template<typename MLAlgorithm,
+2
View File
@@ -3,6 +3,8 @@
set(SOURCES
dataset_mapper.hpp
dataset_mapper_impl.hpp
detect_file_type.hpp
detect_file_type.cpp
extension.hpp
format.hpp
has_serialize.hpp
+289
View File
@@ -0,0 +1,289 @@
/**
* @file core/data/detect_file_type.cpp
* @author Conrad Sanderson
* @author Ryan Curtin
*
* Functionality to guess the type of a file by inspecting it. Parts of the
* implementation are adapted from the Armadillo sources and relicensed to be a
* part of mlpack with permission from Conrad.
*
* 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 "extension.hpp"
#include "detect_file_type.hpp"
#include <boost/algorithm/string/trim.hpp>
#include <boost/tokenizer.hpp>
#include <boost/algorithm/string.hpp>
namespace mlpack {
namespace data {
/**
* Given a file type, return a logical name corresponding to that file type.
*
* @param type Type to get the logical name of.
*/
std::string GetStringType(const arma::file_type& type)
{
switch (type)
{
case arma::csv_ascii: return "CSV data";
case arma::raw_ascii: return "raw ASCII formatted data";
case arma::raw_binary: return "raw binary formatted data";
case arma::arma_ascii: return "Armadillo ASCII formatted data";
case arma::arma_binary: return "Armadillo binary formatted data";
case arma::pgm_binary: return "PGM data";
case arma::hdf5_binary: return "HDF5 data";
default: return "";
}
}
/**
* Given an istream, attempt to guess the file type. This is taken originally
* from Armadillo's function guess_file_type_internal(), but we avoid using
* internal Armadillo functionality.
*
* @param f Opened istream to look into to guess the file type.
*/
arma::file_type GuessFileType(std::istream& f)
{
f.clear();
const std::fstream::pos_type pos1 = f.tellg();
f.clear();
f.seekg(0, std::ios::end);
f.clear();
// Get the length of the stream.
const std::fstream::pos_type pos2 = f.tellg();
// Compute length of the stream.
const arma::uword nMax = ((pos1 >= 0) && (pos2 >= 0) && (pos2 > pos1)) ?
arma::uword(pos2 - pos1) : arma::uword(0);
f.clear();
f.seekg(pos1);
// Handle empty files.
if (nMax == 0)
return arma::file_type_unknown;
const arma::uword nUse = std::min(nMax, arma::uword(4096));
unsigned char* dataMem = new unsigned char[nUse];
memset(dataMem, 0, nUse);
f.clear();
f.read(reinterpret_cast<char*>(dataMem), std::streamsize(nUse));
const bool loadOkay = f.good();
f.clear();
f.seekg(pos1);
if (!loadOkay)
{
delete[] dataMem;
return arma::file_type_unknown;
}
bool hasBinary = false;
bool hasBracket = false;
bool hasComma = false;
for (arma::uword i = 0; i < nUse; ++i)
{
const unsigned char val = dataMem[i];
if ((val <= 8) || (val >= 123))
{
hasBinary = true;
break;
} // The range checking can be made more elaborate.
if ((val == '(') || (val == ')'))
{
hasBracket = true;
}
if (val == ',')
{
hasComma = true;
}
}
delete[] dataMem;
if (hasBinary)
return arma::raw_binary;
if (hasComma && (hasBracket == false))
return arma::csv_ascii;
return arma::raw_ascii;
}
/**
* Attempt to auto-detect the type of a file given its extension, and by
* inspecting the parts of the file to disambiguate between types when
* necessary. (For instance, a .csv file could be delimited by spaces, commas,
* or tabs.) This is meant to be used during loading.
*
* @param stream Opened file stream to look into for autodetection.
* @param filename Name of the file.
* @return The detected file type.
*/
arma::file_type AutoDetect(std::fstream& stream,
const std::string& filename)
{
// Get the extension.
std::string extension = Extension(filename);
arma::file_type detectedLoadType = arma::file_type_unknown;
if (extension == "csv" || extension == "tsv")
{
detectedLoadType = GuessFileType(stream);
if (detectedLoadType == arma::csv_ascii)
{
if (extension == "tsv")
Log::Warn << "'" << filename << "' is comma-separated, not "
"tab-separated!" << std::endl;
}
else if (detectedLoadType == arma::raw_ascii) // .csv file can be tsv.
{
if (extension == "csv")
{
// We should issue a warning, but we don't want to issue the warning if
// there is only one column in the CSV (since there will be no commas
// anyway, and it will be detected as arma::raw_ascii).
const std::streampos pos = stream.tellg();
std::string line;
std::getline(stream, line, '\n');
boost::trim(line);
// Reset stream position.
stream.seekg(pos);
// If there are no spaces or whitespace in the line, then we shouldn't
// print the warning.
if ((line.find(' ') != std::string::npos) ||
(line.find('\t') != std::string::npos))
{
Log::Warn << "'" << filename << "' is not a standard csv file."
<< std::endl;
}
}
}
else
{
detectedLoadType = arma::file_type_unknown;
}
}
else if (extension == "txt")
{
// This could be raw ASCII or Armadillo ASCII (ASCII with size header).
// We'll let Armadillo do its guessing (although we have to check if it is
// arma_ascii ourselves) and see what we come up with.
// This is adapted from load_auto_detect() in diskio_meat.hpp.
const std::string ARMA_MAT_TXT = "ARMA_MAT_TXT";
std::string rawHeader(ARMA_MAT_TXT.length(), '\0');
std::streampos pos = stream.tellg();
stream.read(&rawHeader[0], std::streamsize(ARMA_MAT_TXT.length()));
stream.clear();
stream.seekg(pos); // Reset stream position after peeking.
if (rawHeader == ARMA_MAT_TXT)
{
detectedLoadType = arma::arma_ascii;
}
else // It's not arma_ascii. Now we let Armadillo guess.
{
detectedLoadType = GuessFileType(stream);
if (detectedLoadType != arma::raw_ascii &&
detectedLoadType != arma::csv_ascii)
detectedLoadType = arma::file_type_unknown;
}
}
else if (extension == "bin")
{
// This could be raw binary or Armadillo binary (binary with header). We
// will check to see if it is Armadillo binary.
const std::string ARMA_MAT_BIN = "ARMA_MAT_BIN";
std::string rawHeader(ARMA_MAT_BIN.length(), '\0');
std::streampos pos = stream.tellg();
stream.read(&rawHeader[0], std::streamsize(ARMA_MAT_BIN.length()));
stream.clear();
stream.seekg(pos); // Reset stream position after peeking.
if (rawHeader == ARMA_MAT_BIN)
{
detectedLoadType = arma::arma_binary;
}
else // We can only assume it's raw binary.
{
detectedLoadType = arma::raw_binary;
}
}
else if (extension == "pgm")
{
detectedLoadType = arma::pgm_binary;
}
else if (extension == "h5" || extension == "hdf5" || extension == "hdf" ||
extension == "he5")
{
detectedLoadType = arma::hdf5_binary;
}
else // Unknown extension...
{
detectedLoadType = arma::file_type_unknown;
}
return detectedLoadType;
}
/**
* Return the type based only on the extension.
*
* @param filename Name of the file whose type we should detect.
* @return Detected type of file.
*/
arma::file_type DetectFromExtension(const std::string& filename)
{
const std::string extension = Extension(filename);
if (extension == "csv")
{
return arma::csv_ascii;
}
else if (extension == "txt")
{
return arma::raw_ascii;
}
else if (extension == "bin")
{
return arma::arma_binary;
}
else if (extension == "pgm")
{
return arma::pgm_binary;
}
else if (extension == "h5" || extension == "hdf5" || extension == "hdf" ||
extension == "he5")
{
return arma::hdf5_binary;
}
else
{
return arma::file_type_unknown;
}
}
} // namespace data
} // namespace mlpack
+61
View File
@@ -0,0 +1,61 @@
/**
* @file core/data/detect_file_type.hpp
* @author Conrad Sanderson
* @author Ryan Curtin
*
* Functionality to guess the type of a file by inspecting it. Parts of the
* implementation are adapted from the Armadillo sources and relicensed to be a
* part of mlpack with permission from Conrad.
*
* 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_DETECT_FILE_TYPE_HPP
#define MLPACK_CORE_DATA_DETECT_FILE_TYPE_HPP
namespace mlpack {
namespace data {
/**
* Given a file type, return a logical name corresponding to that file type.
*
* @param type Type to get the logical name of.
*/
std::string GetStringType(const arma::file_type& type);
/**
* Given an istream, attempt to guess the file type. This is taken originally
* from Armadillo's function guess_file_type_internal(), but we avoid using
* internal Armadillo functionality.
*
* @param f Opened istream to look into to guess the file type.
*/
arma::file_type GuessFileType(std::istream& f);
/**
* Attempt to auto-detect the type of a file given its extension, and by
* inspecting the parts of the file to disambiguate between types when
* necessary. (For instance, a .csv file could be delimited by spaces, commas,
* or tabs.) This is meant to be used during loading.
*
* @param stream Opened file stream to look into for autodetection.
* @param filename Name of the file.
* @return The detected file type. arma::file_type_unknown if unknown.
*/
arma::file_type AutoDetect(std::fstream& stream,
const std::string& filename);
/**
* Return the type based only on the extension.
*
* @param filename Name of the file whose type we should detect.
* @return Detected type of file. arma::file_type_unknown if unknown.
*/
arma::file_type DetectFromExtension(const std::string& filename);
} // namespace data
} // namespace mlpack
#endif
+12 -6
View File
@@ -18,32 +18,38 @@ namespace data /** Functions to load and save matrices and models. */ {
template bool Load<int>(const std::string&,
arma::Mat<int>&,
const bool,
const bool);
const bool,
const arma::file_type);
template bool Load<unsigned int>(const std::string&,
arma::Mat<unsigned int>&,
const bool,
const bool);
const bool,
const arma::file_type);
template bool Load<unsigned long>(const std::string&,
arma::Mat<unsigned long>&,
const bool,
const bool);
const bool,
const arma::file_type);
template bool Load<unsigned long long>(const std::string&,
arma::Mat<unsigned long long>&,
const bool,
const bool);
const bool,
const arma::file_type);
template bool Load<float>(const std::string&,
arma::Mat<float>&,
const bool,
const bool);
const bool,
const arma::file_type);
template bool Load<double>(const std::string&,
arma::Mat<double>&,
const bool,
const bool);
const bool,
const arma::file_type);
template bool Load<int>(const std::string&,
arma::SpMat<int>&,
+32 -21
View File
@@ -28,23 +28,25 @@ namespace data /** Functions to load and save matrices and models. */ {
/**
* Loads a matrix from file, guessing the filetype from the extension. This
* will transpose the matrix at load time (unless the transpose parameter is set
* to false). If the filetype cannot be determined, an error will be given.
* to false).
*
* The supported types of files are the same as found in Armadillo:
*
* - CSV (csv_ascii), denoted by .csv, or optionally .txt
* - TSV (raw_ascii), denoted by .tsv, .csv, or .txt
* - ASCII (raw_ascii), denoted by .json
* - Armadillo ASCII (arma_ascii), also denoted by .txt
* - PGM (pgm_binary), denoted by .pgm
* - PPM (ppm_binary), denoted by .ppm
* - Raw binary (raw_binary), denoted by .bin
* - Armadillo binary (arma_binary), denoted by .bin
* - HDF5, denoted by .hdf, .hdf5, .h5, or .he5
* - CSV (arma::csv_ascii), denoted by .csv, or optionally .txt
* - TSV (arma::raw_ascii), denoted by .tsv, .csv, or .txt
* - ASCII (arma::raw_ascii), denoted by .json
* - Armadillo ASCII (arma::arma_ascii), also denoted by .txt
* - PGM (arma::pgm_binary), denoted by .pgm
* - PPM (arma::ppm_binary), denoted by .ppm
* - Raw binary (arma::raw_binary), denoted by .bin
* - Armadillo binary (arma::arma_binary), denoted by .bin
* - HDF5 (arma::hdf5_binary), denoted by .hdf, .hdf5, .h5, or .he5
*
* If the file extension is not one of those types, an error will be given.
* This is preferable to Armadillo's default behavior of loading an unknown
* filetype as raw_binary, which can have very confusing effects.
* By default, this function will try to automatically determine the type of
* file to load based on its extension and by inspecting the file. If you know
* the file type and want to specify it manually, override the default
* `inputLoadType` parameter with the correct type above (e.g.
* `arma::csv_ascii`.)
*
* If the parameter 'fatal' is set to true, a std::runtime_error exception will
* be thrown if the matrix does not load successfully. The parameter
@@ -57,13 +59,15 @@ namespace data /** Functions to load and save matrices and models. */ {
* @param matrix Matrix to load contents of file into.
* @param fatal If an error should be reported as fatal (default false).
* @param transpose If true, transpose the matrix after loading (default true).
* @param inputLoadType Used to determine the type of file to load (default arma::auto_detect).
* @return Boolean value indicating success or failure of load.
*/
template<typename eT>
bool Load(const std::string& filename,
arma::Mat<eT>& matrix,
const bool fatal = false,
const bool transpose = true);
const bool transpose = true,
const arma::file_type inputLoadType = arma::auto_detect);
/**
* Loads a sparse matrix from file, using arma::coord_ascii format. This
@@ -110,38 +114,45 @@ bool Load(const std::string& filename,
extern template bool Load<int>(const std::string&,
arma::Mat<int>&,
const bool,
const bool);
const bool,
const arma::file_type);
// size_t and uword should be one of these three typedefs.
extern template bool Load<unsigned int>(const std::string&,
arma::Mat<unsigned int>&,
const bool,
const bool);
const bool,
const arma::file_type);
extern template bool Load<unsigned long>(const std::string&,
arma::Mat<unsigned long>&,
const bool,
const bool);
const bool,
const arma::file_type);
extern template bool Load<unsigned long long>(const std::string&,
arma::Mat<unsigned long long>&,
const bool,
const bool);
const bool,
const arma::file_type);
extern template bool Load<float>(const std::string&,
arma::Mat<float>&,
const bool,
const bool);
const bool,
const arma::file_type);
extern template bool Load<double>(const std::string&,
arma::Mat<double>&,
const bool,
const bool);
const bool,
const arma::file_type);
extern template bool Load<int>(const std::string&,
arma::Mat<int>&,
const bool,
const bool);
const bool,
const arma::file_type);
extern template bool Load<unsigned int>(const std::string&,
arma::SpMat<unsigned int>&,
+24 -141
View File
@@ -21,6 +21,7 @@
#include "load_csv.hpp"
#include "load.hpp"
#include "extension.hpp"
#include "detect_file_type.hpp"
#include <boost/algorithm/string/trim.hpp>
#include <boost/tokenizer.hpp>
@@ -88,13 +89,11 @@ template<typename eT>
bool Load(const std::string& filename,
arma::Mat<eT>& matrix,
const bool fatal,
const bool transpose)
const bool transpose,
const arma::file_type inputLoadType)
{
Timer::Start("loading_data");
// Get the extension.
std::string extension = Extension(filename);
// Catch nonexistent files by opening the stream ourselves.
std::fstream stream;
#ifdef _WIN32 // Always open in binary mode on Windows.
@@ -114,129 +113,33 @@ bool Load(const std::string& filename,
return false;
}
bool unknownType = false;
arma::file_type loadType;
arma::file_type loadType = inputLoadType;
std::string stringType;
if (extension == "csv" || extension == "tsv")
if (inputLoadType == arma::auto_detect)
{
#if (ARMA_VERSION_MAJOR == 9 && ARMA_VERSION_MINOR >= 800)
loadType = arma::diskio::guess_file_type_internal(stream);
#else
loadType = arma::diskio::guess_file_type(stream);
#endif
if (loadType == arma::csv_ascii)
// Attempt to auto-detect the type from the given file.
loadType = AutoDetect(stream, filename);
// Provide error if we don't know the type.
if (loadType == arma::file_type_unknown)
{
if (extension == "tsv")
Log::Warn << "'" << filename << "' is comma-separated, not "
"tab-separated!" << std::endl;
stringType = "CSV data";
}
else if (loadType == arma::raw_ascii) // .csv file can be tsv.
{
if (extension == "csv")
{
// We should issue a warning, but we don't want to issue the warning if
// there is only one column in the CSV (since there will be no commas
// anyway, and it will be detected as arma::raw_ascii).
const std::streampos pos = stream.tellg();
std::string line;
std::getline(stream, line, '\n');
boost::trim(line);
Timer::Stop("loading_data");
if (fatal)
Log::Fatal << "Unable to detect type of '" << filename << "'; "
<< "incorrect extension?" << std::endl;
else
Log::Warn << "Unable to detect type of '" << filename << "'; load "
<< " failed. Incorrect extension?" << std::endl;
// Reset stream position.
stream.seekg(pos);
// If there are no spaces or whitespace in the line, then we shouldn't
// print the warning.
if ((line.find(' ') != std::string::npos) ||
(line.find('\t') != std::string::npos))
{
Log::Warn << "'" << filename << "' is not a standard csv file."
<< std::endl;
}
}
stringType = "raw ASCII formatted data";
}
else
{
unknownType = true;
loadType = arma::raw_binary; // Won't be used; prevent a warning.
stringType = "";
return false;
}
}
else if (extension == "txt")
stringType = GetStringType(loadType);
#ifndef ARMA_USE_HDF5
if (inputLoadType == arma::hdf5_binary)
{
// This could be raw ASCII or Armadillo ASCII (ASCII with size header).
// We'll let Armadillo do its guessing (although we have to check if it is
// arma_ascii ourselves) and see what we come up with.
// This is taken from load_auto_detect() in diskio_meat.hpp
const std::string ARMA_MAT_TXT = "ARMA_MAT_TXT";
// char* rawHeader = new char[ARMA_MAT_TXT.length() + 1];
std::string rawHeader(ARMA_MAT_TXT.length(), '\0');
std::streampos pos = stream.tellg();
stream.read(&rawHeader[0], std::streamsize(ARMA_MAT_TXT.length()));
stream.clear();
stream.seekg(pos); // Reset stream position after peeking.
if (rawHeader == ARMA_MAT_TXT)
{
loadType = arma::arma_ascii;
stringType = "Armadillo ASCII formatted data";
}
else // It's not arma_ascii. Now we let Armadillo guess.
{
#if (ARMA_VERSION_MAJOR == 9 && ARMA_VERSION_MINOR >= 800)
loadType = arma::diskio::guess_file_type_internal(stream);
#else
loadType = arma::diskio::guess_file_type(stream);
#endif
if (loadType == arma::raw_ascii) // Raw ASCII (space-separated).
stringType = "raw ASCII formatted data";
else if (loadType == arma::csv_ascii) // CSV can be .txt too.
stringType = "CSV data";
else // Unknown .txt... we will throw an error.
unknownType = true;
}
}
else if (extension == "bin")
{
// This could be raw binary or Armadillo binary (binary with header). We
// will check to see if it is Armadillo binary.
const std::string ARMA_MAT_BIN = "ARMA_MAT_BIN";
std::string rawHeader(ARMA_MAT_BIN.length(), '\0');
std::streampos pos = stream.tellg();
stream.read(&rawHeader[0], std::streamsize(ARMA_MAT_BIN.length()));
stream.clear();
stream.seekg(pos); // Reset stream position after peeking.
if (rawHeader == ARMA_MAT_BIN)
{
stringType = "Armadillo binary formatted data";
loadType = arma::arma_binary;
}
else // We can only assume it's raw binary.
{
stringType = "raw binary formatted data";
loadType = arma::raw_binary;
}
}
else if (extension == "pgm")
{
loadType = arma::pgm_binary;
stringType = "PGM data";
}
else if (extension == "h5" || extension == "hdf5" || extension == "hdf" ||
extension == "he5")
{
#ifdef ARMA_USE_HDF5
loadType = arma::hdf5_binary;
stringType = "HDF5 data";
#else
// Ensure that HDF5 is supported.
Timer::Stop("loading_data");
if (fatal)
Log::Fatal << "Attempted to load '" << filename << "' as HDF5 data, but "
@@ -248,28 +151,8 @@ bool Load(const std::string& filename,
<< std::endl;
return false;
}
#endif
}
else // Unknown extension...
{
unknownType = true;
loadType = arma::raw_binary; // Won't be used; prevent a warning.
stringType = "";
}
// Provide error if we don't know the type.
if (unknownType)
{
Timer::Stop("loading_data");
if (fatal)
Log::Fatal << "Unable to detect type of '" << filename << "'; "
<< "incorrect extension?" << std::endl;
else
Log::Warn << "Unable to detect type of '" << filename << "'; load failed."
<< " Incorrect extension?" << std::endl;
return false;
}
// Try to load the file; but if it's raw_binary, it could be a problem.
if (loadType == arma::raw_binary)
+22 -15
View File
@@ -31,33 +31,40 @@ namespace data /** Functions to load and save matrices. */ {
*
* The supported types of files are the same as found in Armadillo:
*
* - CSV (csv_ascii), denoted by .csv, or optionally .txt
* - ASCII (raw_ascii), denoted by .json
* - Armadillo ASCII (arma_ascii), also denoted by .txt
* - PGM (pgm_binary), denoted by .pgm
* - PPM (ppm_binary), denoted by .ppm
* - Raw binary (raw_binary), denoted by .bin
* - Armadillo binary (arma_binary), denoted by .bin
* - HDF5 (hdf5_binary), denoted by .hdf5, .hdf, .h5, or .he5
* - CSV (arma::csv_ascii), denoted by .csv, or optionally .txt
* - ASCII (arma::raw_ascii), denoted by .json
* - Armadillo ASCII (arma::arma_ascii), also denoted by .txt
* - PGM (arma::pgm_binary), denoted by .pgm
* - PPM (arma::ppm_binary), denoted by .ppm
* - Raw binary (arma::raw_binary), denoted by .bin
* - Armadillo binary (arma::arma_binary), denoted by .bin
* - HDF5 (arma::hdf5_binary), denoted by .hdf5, .hdf, .h5, or .he5
*
* If the file extension is not one of those types, an error will be given. If
* the 'fatal' parameter is set to true, a std::runtime_error exception will be
* thrown upon failure. If the 'transpose' parameter is set to true, the matrix
* will be transposed before saving. Generally, because mlpack stores matrices
* in a column-major format and most datasets are stored on disk as row-major,
* this parameter should be left at its default value of 'true'.
* By default, this function will try to automatically determine the format to
* save with based only on the filename's extension. If you would prefer to
* specify a file type manually, override the default
* `inputSaveType` parameter with the correct type above (e.g.
* `arma::csv_ascii`.)
*
* If the 'fatal' parameter is set to true, a std::runtime_error exception will
* be thrown upon failure. If the 'transpose' parameter is set to true, the
* matrix will be transposed before saving. Generally, because mlpack stores
* matrices in a column-major format and most datasets are stored on disk as
* row-major, this parameter should be left at its default value of 'true'.
*
* @param filename Name of file to save to.
* @param matrix Matrix to save into file.
* @param fatal If an error should be reported as fatal (default false).
* @param transpose If true, transpose the matrix before saving (default true).
* @param inputSaveType File type to save to (defaults to arma::auto_detect).
* @return Boolean value indicating success or failure of save.
*/
template<typename eT>
bool Save(const std::string& filename,
const arma::Mat<eT>& matrix,
const bool fatal = false,
bool transpose = true);
bool transpose = true,
arma::file_type inputSaveType = arma::auto_detect);
/**
* Saves a sparse matrix to file, guessing the filetype from the
+28 -17
View File
@@ -15,6 +15,7 @@
// In case it hasn't already been included.
#include "save.hpp"
#include "extension.hpp"
#include "detect_file_type.hpp"
#include <cereal/archives/xml.hpp>
#include <cereal/archives/json.hpp>
@@ -26,43 +27,53 @@ namespace data {
template<typename eT>
bool Save(const std::string& filename,
const arma::Col<eT>& vec,
const bool fatal)
const bool fatal,
arma::file_type inputSaveType)
{
// Don't transpose: one observation per line (for CSVs at least).
return Save(filename, vec, fatal, false);
return Save(filename, vec, fatal, false, inputSaveType);
}
template<typename eT>
bool Save(const std::string& filename,
const arma::Row<eT>& rowvec,
const bool fatal)
const bool fatal,
arma::file_type inputSaveType)
{
return Save(filename, rowvec, fatal, true);
return Save(filename, rowvec, fatal, true, inputSaveType);
}
template<typename eT>
bool Save(const std::string& filename,
const arma::Mat<eT>& matrix,
const bool fatal,
bool transpose)
bool transpose,
arma::file_type inputSaveType)
{
Timer::Start("saving_data");
// First we will try to discriminate by file extension.
std::string extension = Extension(filename);
if (extension == "")
{
Timer::Stop("saving_data");
if (fatal)
Log::Fatal << "No extension given with filename '" << filename << "'; "
<< "type unknown. Save failed." << std::endl;
else
Log::Warn << "No extension given with filename '" << filename << "'; "
<< "type unknown. Save failed." << std::endl;
arma::file_type saveType = inputSaveType;
std::string stringType = "";
return false;
if (inputSaveType == arma::auto_detect)
{
// Detect the file type using only the extension.
saveType = DetectFromExtension(filename);
if (saveType == arma::file_type_unknown)
{
if (fatal)
Log::Fatal << "Could not detect type of file '" << filename << "' for "
<< "writing. Save failed." << std::endl;
else
Log::Warn << "Could not detect type of file '" << filename << "' for "
<< "writing. Save failed." << std::endl;
return false;
}
}
stringType = GetStringType(saveType);
// Catch errors opening the file.
std::fstream stream;
#ifdef _WIN32 // Always open in binary mode on Windows.
+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 4
#define MLPACK_VERSION_PATCH 2
// The name of the version (for use by --version).
namespace mlpack {
@@ -5,6 +5,11 @@
* Definition of the BayesianRidge class, which performs the
* bayesian linear regression. According to the armadillo standards,
* all the functions consider data in column-major format.
*
* 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_BAYESIAN_LINEAR_REGRESSION_HPP
+5 -7
View File
@@ -16,7 +16,6 @@ add_executable(mlpack_test
emst_test.cpp
fastmks_test.cpp
facilities_test.cpp
feedforward_network_test.cpp
gan_test.cpp
gmm_test.cpp
hmm_test.cpp
@@ -25,7 +24,6 @@ add_executable(mlpack_test
hyperplane_test.cpp
init_rules_test.cpp
kde_test.cpp
kmeans_test.cpp
krann_search_test.cpp
ksinit_test.cpp
lars_test.cpp
@@ -59,9 +57,7 @@ add_executable(mlpack_test
random_forest_test.cpp
random_test.cpp
range_search_test.cpp
rbm_network_test.cpp
rectangle_tree_test.cpp
recurrent_network_test.cpp
reward_clipping_test.cpp
rl_components_test.cpp
serialization.cpp
@@ -97,7 +93,6 @@ add_executable(mlpack_test
main_tests/hmm_viterbi_test.cpp
main_tests/hoeffding_tree_test.cpp
main_tests/kde_test.cpp
main_tests/kmeans_test.cpp
main_tests/krann_test.cpp
main_tests/linear_svm_test.cpp
main_tests/lmnn_test.cpp
@@ -135,12 +130,14 @@ add_executable(mlpack_catch_test
cv_test.cpp
decision_stump_test.cpp
decision_tree_test.cpp
feedforward_network_test.cpp
image_load_test.cpp
imputation_test.cpp
kernel_pca_test.cpp
kernel_test.cpp
kernel_traits_test.cpp
kfn_test.cpp
kmeans_test.cpp
knn_test.cpp
linear_regression_test.cpp
load_save_test.cpp
@@ -149,6 +146,8 @@ add_executable(mlpack_catch_test
one_hot_encoding_test.cpp
quic_svd_test.cpp
randomized_svd_test.cpp
rbm_network_test.cpp
recurrent_network_test.cpp
regularized_svd_test.cpp
scaling_test.cpp
serialization_catch.cpp
@@ -169,6 +168,7 @@ add_executable(mlpack_catch_test
main_tests/image_converter_test.cpp
main_tests/kernel_pca_test.cpp
main_tests/kfn_test.cpp
main_tests/kmeans_test.cpp
main_tests/knn_test.cpp
main_tests/linear_regression_test.cpp
main_tests/nca_test.cpp
@@ -229,8 +229,6 @@ add_custom_command(TARGET mlpack_test
set(parallel_tests
"AsyncLearningTest;"
"LocalCoordinateCodingTest;"
"FeedForwardNetworkTest;"
"RecurrentNetworkTest;"
"GMMTest;"
"CFTest;"
"HMMTest;"
+20
View File
@@ -380,6 +380,26 @@ TEST_CASE("SimpleCVMSETest", "[CVTest]")
REQUIRE(std::abs(weightedCV2.Evaluate() - expectedMSE) > 1e-5);
}
/**
* Test that scores of -nan are filtered out.
*/
TEST_CASE("FilterNANCVTest", "[CVTest]")
{
// Create a dataset with only one positive label, so it will not be in every
// fold.
arma::mat data(3, 10, arma::fill::randu);
arma::Row<size_t> labels(10, arma::fill::zeros);
labels[0] = 1;
const size_t numClasses = 2;
KFoldCV<NaiveBayesClassifier<>, F1<Binary>> kfoldcv(2, data, labels,
numClasses);
const double result = kfoldcv.Evaluate();
REQUIRE(!std::isnan(result));
REQUIRE(!std::isinf(result));
}
template<typename... DTArgs>
arma::Row<size_t> PredictLabelsWithDT(const arma::mat& data,
const DTArgs&... args)
+18 -23
View File
@@ -19,17 +19,14 @@
#include <ensmallen.hpp>
#include <boost/test/unit_test.hpp>
#include "test_tools.hpp"
#include "serialization.hpp"
#include "catch.hpp"
#include "serialization_catch.hpp"
#include "custom_layer.hpp"
using namespace mlpack;
using namespace mlpack::ann;
using namespace mlpack::kmeans;
BOOST_AUTO_TEST_SUITE(FeedForwardNetworkTest);
/**
* Train and evaluate a model with the specified structure.
*/
@@ -57,13 +54,13 @@ void TestNetwork(ModelType& model,
size_t correct = arma::accu(prediction == testLabels);
double classificationError = 1 - double(correct) / testData.n_cols;
BOOST_REQUIRE_LE(classificationError, classificationErrorThreshold);
REQUIRE(classificationError <= classificationErrorThreshold);
}
/**
* Train the vanilla network on a larger dataset.
*/
BOOST_AUTO_TEST_CASE(VanillaNetworkTest)
TEST_CASE("FFVanillaNetworkTest", "[FeedForwardNetworkTest]")
{
// Load the dataset.
arma::mat trainData;
@@ -131,7 +128,7 @@ BOOST_AUTO_TEST_CASE(VanillaNetworkTest)
TestNetwork<>(model1, dataset, labels, dataset, labels, 10, 0.2);
}
BOOST_AUTO_TEST_CASE(ForwardBackwardTest)
TEST_CASE("ForwardBackwardTest", "[FeedForwardNetworkTest]")
{
arma::mat dataset;
dataset.load("mnist_first250_training_4s_and_9s.arm");
@@ -204,13 +201,13 @@ BOOST_AUTO_TEST_CASE(ForwardBackwardTest)
}
}
BOOST_REQUIRE(converged);
REQUIRE(converged);
}
/**
* Train the dropout network on a larger dataset.
*/
BOOST_AUTO_TEST_CASE(DropoutNetworkTest)
TEST_CASE("DropoutNetworkTest", "[FeedForwardNetworkTest]")
{
// Load the dataset.
arma::mat trainData;
@@ -284,7 +281,7 @@ BOOST_AUTO_TEST_CASE(DropoutNetworkTest)
/**
* Train the highway network on a larger dataset.
*/
BOOST_AUTO_TEST_CASE(HighwayNetworkTest)
TEST_CASE("HighwayNetworkTest", "[FeedForwardNetworkTest]")
{
arma::mat dataset;
dataset.load("mnist_first250_training_4s_and_9s.arm");
@@ -311,7 +308,7 @@ BOOST_AUTO_TEST_CASE(HighwayNetworkTest)
/**
* Train the DropConnect network on a larger dataset.
*/
BOOST_AUTO_TEST_CASE(DropConnectNetworkTest)
TEST_CASE("DropConnectNetworkTest", "[FeedForwardNetworkTest]")
{
// Load the dataset.
arma::mat trainData;
@@ -385,7 +382,7 @@ BOOST_AUTO_TEST_CASE(DropConnectNetworkTest)
* Test miscellaneous things of FFN,
* e.g. copy/move constructor, assignment operator.
*/
BOOST_AUTO_TEST_CASE(FFNMiscTest)
TEST_CASE("FFNMiscTest", "[FeedForwardNetworkTest]")
{
FFN<MeanSquaredError<>> model;
model.Add<Linear<>>(2, 3);
@@ -400,7 +397,7 @@ BOOST_AUTO_TEST_CASE(FFNMiscTest)
/**
* Test that serialization works ok.
*/
BOOST_AUTO_TEST_CASE(SerializationTest)
TEST_CASE("FFSerializationTest", "[FeedForwardNetworkTest]")
{
// Load the dataset.
arma::mat trainData;
@@ -449,7 +446,7 @@ BOOST_AUTO_TEST_CASE(SerializationTest)
* Test if the custom layers work. The target is to see if the code compiles
* when the Train and Prediction are called.
*/
BOOST_AUTO_TEST_CASE(CustomLayerTest)
TEST_CASE("CustomLayerTest", "[FeedForwardNetworkTest]")
{
// Load the dataset.
arma::mat trainData;
@@ -481,7 +478,7 @@ BOOST_AUTO_TEST_CASE(CustomLayerTest)
/**
* Test the overload of Forward function which allows partial forward pass.
*/
BOOST_AUTO_TEST_CASE(PartialForwardTest)
TEST_CASE("PartialForwardTest", "[FeedForwardNetworkTest]")
{
FFN<NegativeLogLikelihood<>, RandomInitialization> model;
model.Add<Linear<> >(5, 10);
@@ -528,7 +525,7 @@ BOOST_AUTO_TEST_CASE(PartialForwardTest)
/**
* Test that FFN::Train() returns finite objective value.
*/
BOOST_AUTO_TEST_CASE(FFNTrainReturnObjective)
TEST_CASE("FFNTrainReturnObjective", "[FeedForwardNetworkTest]")
{
// Load the dataset.
arma::mat trainData;
@@ -557,13 +554,13 @@ BOOST_AUTO_TEST_CASE(FFNTrainReturnObjective)
double objVal = model.Train(trainData, trainLabels, opt);
BOOST_REQUIRE_EQUAL(std::isfinite(objVal), true);
REQUIRE(std::isfinite(objVal) == true);
}
/**
* Test that FFN::Model() allows us to access the instantiated network.
*/
BOOST_AUTO_TEST_CASE(FFNReturnModel)
TEST_CASE("FFNReturnModel", "[FeedForwardNetworkTest]")
{
// Create dummy network.
FFN<NegativeLogLikelihood<> > model;
@@ -598,7 +595,7 @@ BOOST_AUTO_TEST_CASE(FFNReturnModel)
* Test to see if the FFN code compiles when the Optimizer
* doesn't have the MaxIterations() method.
*/
BOOST_AUTO_TEST_CASE(OptimizerTest)
TEST_CASE("OptimizerTest", "[FeedForwardNetworkTest]")
{
// Load the dataset.
arma::mat trainData;
@@ -626,7 +623,7 @@ BOOST_AUTO_TEST_CASE(OptimizerTest)
/**
* Train the RBF network on a larger dataset.
*/
BOOST_AUTO_TEST_CASE(RBFNetworkTest)
TEST_CASE("RBFNetworkTest", "[FeedForwardNetworkTest]")
{
// Load the dataset.
arma::mat trainData;
@@ -703,5 +700,3 @@ BOOST_AUTO_TEST_CASE(RBFNetworkTest)
// RBFN neural net with MeanSquaredError.
TestNetwork<>(model1, dataset, labels1, dataset, labels, 10, 0.1);
}
BOOST_AUTO_TEST_SUITE_END();
+99
View File
@@ -598,6 +598,105 @@ BOOST_AUTO_TEST_CASE(InputMatrixParamTest)
BOOST_REQUIRE_CLOSE(dataset[i], dataset2[i], 1e-10);
}
// Make sure we can correctly load required matrix parameters.
BOOST_AUTO_TEST_CASE(RequiredInputMatrixParamTest)
{
AddRequiredCLIOptions();
// --matrix is an input parameter; it won't be transposed.
PARAM_MATRIX_IN_REQ("matrix", "Test matrix", "m");
// Set some fake arguments.
const char* argv[3];
argv[0] = "./test";
argv[1] = "--matrix_file";
argv[2] = "test_data_3_1000.csv";
int argc = 3;
// The const-cast is a little hacky but should be fine...
ParseCommandLine(argc, const_cast<char**>(argv));
// The --matrix parameter should exist.
BOOST_REQUIRE(IO::HasParam("matrix"));
// The --matrix_file parameter should not exist (it should be transparent from
// inside the program).
Log::Fatal.ignoreInput = true;
BOOST_REQUIRE_THROW(IO::HasParam("matrix_file"), runtime_error);
Log::Fatal.ignoreInput = false;
arma::mat dataset = IO::GetParam<arma::mat>("matrix");
arma::mat dataset2 = IO::GetParam<arma::mat>("matrix");
BOOST_REQUIRE_EQUAL(dataset.n_rows, 3);
BOOST_REQUIRE_EQUAL(dataset.n_cols, 1000);
BOOST_REQUIRE_EQUAL(dataset2.n_rows, 3);
BOOST_REQUIRE_EQUAL(dataset2.n_cols, 1000);
for (size_t i = 0; i < dataset.n_elem; ++i)
BOOST_REQUIRE_CLOSE(dataset[i], dataset2[i], 1e-10);
}
// Make sure loading required matrix options by alias succeeds.
BOOST_AUTO_TEST_CASE(RequiredInputMatrixParamAliasTest)
{
AddRequiredCLIOptions();
// --matrix is an input parameter; it won't be transposed.
PARAM_MATRIX_IN_REQ("matrix", "Test matrix", "m");
// Set some fake arguments.
const char* argv[3];
argv[0] = "./test";
argv[1] = "-m";
argv[2] = "test_data_3_1000.csv";
int argc = 3;
// The const-cast is a little hacky but should be fine...
ParseCommandLine(argc, const_cast<char**>(argv));
// The --matrix parameter should exist.
BOOST_REQUIRE(IO::HasParam("matrix"));
// The --matrix_file parameter should not exist (it should be transparent from
// inside the program).
Log::Fatal.ignoreInput = true;
BOOST_REQUIRE_THROW(IO::HasParam("matrix_file"), runtime_error);
Log::Fatal.ignoreInput = false;
arma::mat dataset = IO::GetParam<arma::mat>("matrix");
arma::mat dataset2 = IO::GetParam<arma::mat>("matrix");
BOOST_REQUIRE_EQUAL(dataset.n_rows, 3);
BOOST_REQUIRE_EQUAL(dataset.n_cols, 1000);
BOOST_REQUIRE_EQUAL(dataset2.n_rows, 3);
BOOST_REQUIRE_EQUAL(dataset2.n_cols, 1000);
for (size_t i = 0; i < dataset.n_elem; ++i)
BOOST_REQUIRE_CLOSE(dataset[i], dataset2[i], 1e-10);
}
// Make sure that when we don't pass a required matrix, parsing fails.
BOOST_AUTO_TEST_CASE(RequiredUnspecifiedInputMatrixParamTest)
{
AddRequiredCLIOptions();
// --matrix is an input parameter; it won't be transposed.
PARAM_MATRIX_IN_REQ("matrix", "Test matrix", "m");
// Set some fake arguments.
const char* argv[1];
argv[0] = "./test";
int argc = 1;
// The const-cast is a little hacky but should be fine...
Log::Fatal.ignoreInput = true;
BOOST_REQUIRE_THROW(ParseCommandLine(argc, const_cast<char**>(argv)),
std::exception);
Log::Fatal.ignoreInput = false;
}
BOOST_AUTO_TEST_CASE(InputMatrixNoTransposeParamTest)
{
AddRequiredCLIOptions();
+80 -85
View File
@@ -22,9 +22,8 @@
#include <mlpack/core/tree/cover_tree/cover_tree.hpp>
#include <mlpack/methods/neighbor_search/neighbor_search.hpp>
#include <boost/test/unit_test.hpp>
#include "catch.hpp"
#include <mlpack/methods/kmeans/kill_empty_clusters.hpp>
#include "test_tools.hpp"
using namespace mlpack;
using namespace mlpack::kmeans;
@@ -32,8 +31,6 @@ using namespace mlpack::metric;
using namespace mlpack::tree;
using namespace mlpack::neighbor;
BOOST_AUTO_TEST_SUITE(KMeansTest);
// Generate dataset; written transposed because it's easier to read.
arma::mat kMeansData(" 0.0 0.0;" // Class 1.
" 0.3 0.4;"
@@ -69,7 +66,7 @@ arma::mat kMeansData(" 0.0 0.0;" // Class 1.
/**
* 30-point 3-class test case for K-Means.
*/
BOOST_AUTO_TEST_CASE(KMeansSimpleTest)
TEST_CASE("KMeansSimpleTest", "[KMeansTest]")
{
// This test was originally written to use RandomPartition, and is left that
// way because RandomPartition gives better initializations here.
@@ -83,30 +80,30 @@ BOOST_AUTO_TEST_CASE(KMeansSimpleTest)
size_t firstClass = assignments(0);
for (size_t i = 1; i < 13; ++i)
BOOST_REQUIRE_EQUAL(assignments(i), firstClass);
REQUIRE(assignments(i) == firstClass);
size_t secondClass = assignments(13);
// To ensure that class 1 != class 2.
BOOST_REQUIRE_NE(firstClass, secondClass);
REQUIRE(firstClass != secondClass);
for (size_t i = 13; i < 20; ++i)
BOOST_REQUIRE_EQUAL(assignments(i), secondClass);
REQUIRE(assignments(i) == secondClass);
size_t thirdClass = assignments(20);
// To ensure that this is the third class which we haven't seen yet.
BOOST_REQUIRE_NE(firstClass, thirdClass);
BOOST_REQUIRE_NE(secondClass, thirdClass);
REQUIRE(firstClass != thirdClass);
REQUIRE(secondClass != thirdClass);
for (size_t i = 20; i < 30; ++i)
BOOST_REQUIRE_EQUAL(assignments(i), thirdClass);
REQUIRE(assignments(i) == thirdClass);
}
/**
* Make sure the empty cluster policy class does nothing.
*/
BOOST_AUTO_TEST_CASE(AllowEmptyClusterTest)
TEST_CASE("AllowEmptyClusterTest", "[KMeansTest]")
{
arma::Row<size_t> assignments;
assignments.randu(30);
@@ -129,17 +126,17 @@ BOOST_AUTO_TEST_CASE(AllowEmptyClusterTest)
// Make sure no assignments were changed.
for (size_t i = 0; i < assignments.n_elem; ++i)
BOOST_REQUIRE_EQUAL(assignments[i], assignmentsOld[i]);
REQUIRE(assignments[i] == assignmentsOld[i]);
// Make sure no counts were changed.
for (size_t i = 0; i < 3; ++i)
BOOST_REQUIRE_EQUAL(counts[i], countsOld[i]);
REQUIRE(counts[i] == countsOld[i]);
}
/**
* Make sure kill empty cluster policy removes the empty cluster.
*/
BOOST_AUTO_TEST_CASE(KillEmptyClusterTest)
TEST_CASE("KillEmptyClusterTest", "[KMeansTest]")
{
arma::Row<size_t> assignments;
assignments.randu(30);
@@ -162,20 +159,20 @@ BOOST_AUTO_TEST_CASE(KillEmptyClusterTest)
// Make sure no assignments were changed.
for (size_t i = 0; i < assignments.n_elem; ++i)
BOOST_REQUIRE_EQUAL(assignments[i], assignmentsOld[i]);
REQUIRE(assignments[i] == assignmentsOld[i]);
// Make sure no counts were changed for clusters that are not empty.
for (size_t i = 0; i < 2; ++i)
BOOST_REQUIRE_EQUAL(counts[i], countsOld[i]);
REQUIRE(counts[i] == countsOld[i]);
// Make sure that counts contain one less element than old counts.
BOOST_REQUIRE_GT(countsOld.n_elem, counts.n_elem);
REQUIRE(countsOld.n_elem > counts.n_elem);
}
/**
* Make sure the max variance method finds the correct point.
*/
BOOST_AUTO_TEST_CASE(MaxVarianceNewClusterTest)
TEST_CASE("MaxVarianceNewClusterTest", "[KMeansTest]")
{
// Five points.
arma::mat data("0.4 1.0 5.0 -2.0 -2.5;"
@@ -220,22 +217,22 @@ BOOST_AUTO_TEST_CASE(MaxVarianceNewClusterTest)
assignments[i] = closestCluster;
}
BOOST_REQUIRE_EQUAL(assignments[0], 0);
BOOST_REQUIRE_EQUAL(assignments[1], 0);
BOOST_REQUIRE_EQUAL(assignments[2], 2);
BOOST_REQUIRE_EQUAL(assignments[3], 1);
BOOST_REQUIRE_EQUAL(assignments[4], 1);
REQUIRE(assignments[0] == 0);
REQUIRE(assignments[1] == 0);
REQUIRE(assignments[2] == 2);
REQUIRE(assignments[3] == 1);
REQUIRE(assignments[4] == 1);
// Ensure that the counts are right.
BOOST_REQUIRE_EQUAL(counts[0], 2);
BOOST_REQUIRE_EQUAL(counts[1], 2);
BOOST_REQUIRE_EQUAL(counts[2], 1);
REQUIRE(counts[0] == 2);
REQUIRE(counts[1] == 2);
REQUIRE(counts[2] == 1);
}
/**
* Make sure the random partitioner seems to return valid results.
*/
BOOST_AUTO_TEST_CASE(RandomPartitionTest)
TEST_CASE("RandomPartitionTest", "[KMeansTest]")
{
arma::mat data;
data.randu(2, 1000); // One thousand points.
@@ -246,17 +243,17 @@ BOOST_AUTO_TEST_CASE(RandomPartitionTest)
RandomPartition::Cluster(data, 18, assignments);
// Ensure that the right number of assignments were given.
BOOST_REQUIRE_EQUAL(assignments.n_elem, 1000);
REQUIRE(assignments.n_elem == 1000);
// Ensure that no value is greater than 17 (the maximum valid cluster).
for (size_t i = 0; i < 1000; ++i)
BOOST_REQUIRE_LT(assignments[i], 18);
REQUIRE(assignments[i] < 18);
}
/**
* Make sure that random initialization fails for a corner case dataset.
*/
BOOST_AUTO_TEST_CASE(RandomInitialAssignmentFailureTest)
TEST_CASE("RandomInitialAssignmentFailureTest", "[KMeansTest]")
{
// This is a very synthetic dataset. It is one Gaussian with a huge number of
// points combined with one faraway Gaussian with very few points. Normally,
@@ -292,14 +289,14 @@ BOOST_AUTO_TEST_CASE(RandomInitialAssignmentFailureTest)
// Only one success allowed. The probability of two successes should be
// infinitesimal.
BOOST_REQUIRE_LT(successes, 2);
REQUIRE(successes < 2);
}
/**
* Make sure that specifying initial assignments is successful for a corner case
* dataset which doesn't usually converge otherwise.
*/
BOOST_AUTO_TEST_CASE(InitialAssignmentTest)
TEST_CASE("InitialAssignmentTest", "[KMeansTest]")
{
// For a better description of this dataset, see
// RandomInitialAssignmentFailureTest.
@@ -321,9 +318,9 @@ BOOST_AUTO_TEST_CASE(InitialAssignmentTest)
// Check results.
for (size_t i = 0; i < 10000; ++i)
BOOST_REQUIRE_EQUAL(assignments[i], 0);
REQUIRE(assignments[i] == 0);
for (size_t i = 10000; i < 10002; ++i)
BOOST_REQUIRE_EQUAL(assignments[i], 1);
REQUIRE(assignments[i] == 1);
// Now, slightly harder. Give it one incorrect assignment in each cluster.
// The wrong assignment should be quickly fixed.
@@ -334,16 +331,16 @@ BOOST_AUTO_TEST_CASE(InitialAssignmentTest)
// Check results.
for (size_t i = 0; i < 10000; ++i)
BOOST_REQUIRE_EQUAL(assignments[i], 0);
REQUIRE(assignments[i] == 0);
for (size_t i = 10000; i < 10002; ++i)
BOOST_REQUIRE_EQUAL(assignments[i], 1);
REQUIRE(assignments[i] == 1);
}
/**
* Make sure specifying initial centroids is successful for a corner case which
* doesn't usually converge otherwise.
*/
BOOST_AUTO_TEST_CASE(InitialCentroidTest)
TEST_CASE("InitialCentroidTest", "[KMeansTest]")
{
// For a better description of this dataset, see
// RandomInitialAssignmentFailureTest.
@@ -365,9 +362,9 @@ BOOST_AUTO_TEST_CASE(InitialCentroidTest)
// Check results.
for (size_t i = 0; i < 10000; ++i)
BOOST_REQUIRE_EQUAL(assignments[i], 0);
REQUIRE(assignments[i] == 0);
for (size_t i = 10000; i < 10002; ++i)
BOOST_REQUIRE_EQUAL(assignments[i], 1);
REQUIRE(assignments[i] == 1);
// Now add a little noise to the initial centroids.
centroids.col(0) = arma::vec("3 4");
@@ -377,15 +374,15 @@ BOOST_AUTO_TEST_CASE(InitialCentroidTest)
// Check results.
for (size_t i = 0; i < 10000; ++i)
BOOST_REQUIRE_EQUAL(assignments[i], 0);
REQUIRE(assignments[i] == 0);
for (size_t i = 10000; i < 10002; ++i)
BOOST_REQUIRE_EQUAL(assignments[i], 1);
REQUIRE(assignments[i] == 1);
}
/**
* Ensure that initial assignments override initial centroids.
*/
BOOST_AUTO_TEST_CASE(InitialAssignmentOverrideTest)
TEST_CASE("InitialAssignmentOverrideTest", "[KMeansTest]")
{
// For a better description of this dataset, see
// RandomInitialAssignmentFailureTest.
@@ -412,22 +409,22 @@ BOOST_AUTO_TEST_CASE(InitialAssignmentOverrideTest)
// Because the initial assignments guess should take priority, we should get
// those same results back.
for (size_t i = 0; i < 10000; ++i)
BOOST_REQUIRE_EQUAL(assignments[i], 0);
REQUIRE(assignments[i] == 0);
for (size_t i = 10000; i < 10002; ++i)
BOOST_REQUIRE_EQUAL(assignments[i], 1);
REQUIRE(assignments[i] == 1);
// Make sure the centroids are about right too.
BOOST_REQUIRE_LT(centroids(0, 0), 10.0);
BOOST_REQUIRE_LT(centroids(1, 0), 10.0);
BOOST_REQUIRE_GT(centroids(0, 1), 40.0);
BOOST_REQUIRE_GT(centroids(1, 1), 40.0);
REQUIRE(centroids(0, 0) < 10.0);
REQUIRE(centroids(1, 0) < 10.0);
REQUIRE(centroids(0, 1) > 40.0);
REQUIRE(centroids(1, 1) > 40.0);
}
/**
* Test that the refined starting policy returns decent initial cluster
* estimates.
*/
BOOST_AUTO_TEST_CASE(RefinedStartTest)
TEST_CASE("RefinedStartTest", "[KMeansTest]")
{
// Our dataset will be five Gaussians of largely varying numbers of points and
// we expect that the refined starting policy should return good guesses at
@@ -486,14 +483,14 @@ BOOST_AUTO_TEST_CASE(RefinedStartTest)
// figure is a corner case which actually does not give good clusters), and
// random initial starts give distortion around 22000. So we'll require that
// our distortion is less than 14000.
BOOST_REQUIRE_LT(distortion, 14000.0);
REQUIRE(distortion < 14000.0);
}
#ifdef ARMA_HAS_SPMAT
/**
* Make sure sparse k-means works okay.
*/
BOOST_AUTO_TEST_CASE(SparseKMeansTest)
TEST_CASE("SparseKMeansTest", "[KMeansTest]")
{
// Huge dimensionality, few points.
arma::SpMat<double> data(5000, 12);
@@ -520,23 +517,23 @@ BOOST_AUTO_TEST_CASE(SparseKMeansTest)
size_t clusterOne = assignments[0];
size_t clusterTwo = assignments[6];
BOOST_REQUIRE_EQUAL(assignments[0], clusterOne);
BOOST_REQUIRE_EQUAL(assignments[1], clusterOne);
BOOST_REQUIRE_EQUAL(assignments[2], clusterOne);
BOOST_REQUIRE_EQUAL(assignments[3], clusterOne);
BOOST_REQUIRE_EQUAL(assignments[4], clusterOne);
BOOST_REQUIRE_EQUAL(assignments[5], clusterOne);
BOOST_REQUIRE_EQUAL(assignments[6], clusterTwo);
BOOST_REQUIRE_EQUAL(assignments[7], clusterTwo);
BOOST_REQUIRE_EQUAL(assignments[8], clusterTwo);
BOOST_REQUIRE_EQUAL(assignments[9], clusterTwo);
BOOST_REQUIRE_EQUAL(assignments[10], clusterTwo);
BOOST_REQUIRE_EQUAL(assignments[11], clusterTwo);
REQUIRE(assignments[0] == clusterOne);
REQUIRE(assignments[1] == clusterOne);
REQUIRE(assignments[2] == clusterOne);
REQUIRE(assignments[3] == clusterOne);
REQUIRE(assignments[4] == clusterOne);
REQUIRE(assignments[5] == clusterOne);
REQUIRE(assignments[6] == clusterTwo);
REQUIRE(assignments[7] == clusterTwo);
REQUIRE(assignments[8] == clusterTwo);
REQUIRE(assignments[9] == clusterTwo);
REQUIRE(assignments[10] == clusterTwo);
REQUIRE(assignments[11] == clusterTwo);
}
#endif // ARMA_HAS_SPMAT
BOOST_AUTO_TEST_CASE(ElkanTest)
TEST_CASE("ElkanTest", "[KMeansTest]")
{
const size_t trials = 5;
@@ -563,14 +560,14 @@ BOOST_AUTO_TEST_CASE(ElkanTest)
elkan.Cluster(dataset, k, elkanAssignments, elkanCentroids, false, true);
for (size_t i = 0; i < dataset.n_cols; ++i)
BOOST_REQUIRE_EQUAL(assignments[i], elkanAssignments[i]);
REQUIRE(assignments[i] == elkanAssignments[i]);
for (size_t i = 0; i < centroids.n_elem; ++i)
BOOST_REQUIRE_CLOSE(naiveCentroids[i], elkanCentroids[i], 1e-5);
REQUIRE(naiveCentroids[i] == Approx(elkanCentroids[i]).epsilon(1e-7));
}
}
BOOST_AUTO_TEST_CASE(HamerlyTest)
TEST_CASE("HamerlyTest", "[KMeansTest]")
{
const size_t trials = 5;
@@ -598,14 +595,14 @@ BOOST_AUTO_TEST_CASE(HamerlyTest)
true);
for (size_t i = 0; i < dataset.n_cols; ++i)
BOOST_REQUIRE_EQUAL(assignments[i], hamerlyAssignments[i]);
REQUIRE(assignments[i] == hamerlyAssignments[i]);
for (size_t i = 0; i < centroids.n_elem; ++i)
BOOST_REQUIRE_CLOSE(naiveCentroids[i], hamerlyCentroids[i], 1e-5);
REQUIRE(naiveCentroids[i] == Approx(hamerlyCentroids[i]).epsilon(1e-7));
}
}
BOOST_AUTO_TEST_CASE(PellegMooreTest)
TEST_CASE("PellegMooreTest", "[KMeansTest]")
{
const size_t trials = 5;
@@ -632,14 +629,14 @@ BOOST_AUTO_TEST_CASE(PellegMooreTest)
pellegMoore.Cluster(dataset, k, pmAssignments, pmCentroids, false, true);
for (size_t i = 0; i < dataset.n_cols; ++i)
BOOST_REQUIRE_EQUAL(assignments[i], pmAssignments[i]);
REQUIRE(assignments[i] == pmAssignments[i]);
for (size_t i = 0; i < centroids.n_elem; ++i)
BOOST_REQUIRE_CLOSE(naiveCentroids[i], pmCentroids[i], 1e-5);
REQUIRE(naiveCentroids[i] == Approx(pmCentroids[i]).epsilon(1e-7));
}
}
BOOST_AUTO_TEST_CASE(DTNNTest)
TEST_CASE("DTNNTest", "[KMeansTest]")
{
const size_t trials = 5;
@@ -664,14 +661,14 @@ BOOST_AUTO_TEST_CASE(DTNNTest)
dtnn.Cluster(dataset, k, dtnnAssignments, dtnnCentroids, false, true);
for (size_t i = 0; i < dataset.n_cols; ++i)
BOOST_REQUIRE_EQUAL(assignments[i], dtnnAssignments[i]);
REQUIRE(assignments[i] == dtnnAssignments[i]);
for (size_t i = 0; i < centroids.n_elem; ++i)
BOOST_REQUIRE_CLOSE(naiveCentroids[i], dtnnCentroids[i], 1e-5);
REQUIRE(naiveCentroids[i] == Approx(dtnnCentroids[i]).epsilon(1e-7));
}
}
BOOST_AUTO_TEST_CASE(DTNNCoverTreeTest)
TEST_CASE("DTNNCoverTreeTest", "[KMeansTest]")
{
const size_t trials = 5;
@@ -696,10 +693,10 @@ BOOST_AUTO_TEST_CASE(DTNNCoverTreeTest)
dtnn.Cluster(dataset, k, dtnnAssignments, dtnnCentroids, false, true);
for (size_t i = 0; i < dataset.n_cols; ++i)
BOOST_REQUIRE_EQUAL(assignments[i], dtnnAssignments[i]);
REQUIRE(assignments[i] == dtnnAssignments[i]);
for (size_t i = 0; i < centroids.n_elem; ++i)
BOOST_REQUIRE_CLOSE(naiveCentroids[i], dtnnCentroids[i], 1e-5);
REQUIRE(naiveCentroids[i] == Approx(dtnnCentroids[i]).epsilon(1e-7));
}
}
@@ -707,7 +704,7 @@ BOOST_AUTO_TEST_CASE(DTNNCoverTreeTest)
* Make sure that the sample initialization strategy successfully samples points
* from the dataset.
*/
BOOST_AUTO_TEST_CASE(SampleInitializationTest)
TEST_CASE("SampleInitializationTest", "[KMeansTest]")
{
arma::mat dataset = arma::randu<arma::mat>(5, 100);
const size_t clusters = 10;
@@ -716,8 +713,8 @@ BOOST_AUTO_TEST_CASE(SampleInitializationTest)
SampleInitialization::Cluster(dataset, clusters, centroids);
// Check that the size of the matrix is correct.
BOOST_REQUIRE_EQUAL(centroids.n_cols, 10);
BOOST_REQUIRE_EQUAL(centroids.n_rows, 5);
REQUIRE(centroids.n_cols == 10);
REQUIRE(centroids.n_rows == 5);
// Check that each entry in the matrix is some sample from the dataset.
for (size_t i = 0; i < clusters; ++i)
@@ -733,8 +730,6 @@ BOOST_AUTO_TEST_CASE(SampleInitializationTest)
break;
}
BOOST_REQUIRE_LT(j, dataset.n_cols);
REQUIRE(j < dataset.n_cols);
}
}
BOOST_AUTO_TEST_SUITE_END();
+102
View File
@@ -48,6 +48,56 @@ TEST_CASE("NotExistLoad", "[LoadSaveTest]")
REQUIRE(data::Load("nonexistentfile_______________.csv", out) == false);
}
/**
* Make sure load fails if the file extension is wrong in automatic detection mode.
*/
TEST_CASE("WrongExtensionWrongLoad", "[LoadSaveTest]")
{
// Try to load arma::arma_binary file with ".csv" extension
arma::mat test = "1 5;"
"2 6;"
"3 7;"
"4 8;";
arma::mat testTrans = trans(test);
REQUIRE(testTrans.quiet_save("test_file.csv", arma::arma_binary) == true);
// Now reload through our interface.
REQUIRE(data::Load("test_file.csv", test) == false);
// Remove the file.
remove("test_file.csv");
}
/**
* Make sure load is successful even if the file extension is wrong when file type is specified.
*/
TEST_CASE("WrongExtensionCorrectLoad", "[LoadSaveTest]")
{
// Try to load arma::arma_binary file with ".csv" extension
arma::mat test = "1 5;"
"2 6;"
"3 7;"
"4 8;";
arma::mat testTrans = trans(test);
REQUIRE(testTrans.quiet_save("test_file.csv", arma::arma_binary) == true);
// Now reload through our interface.
REQUIRE(
data::Load("test_file.csv", test, false, true, arma::arma_binary)
== true);
REQUIRE(test.n_rows == 4);
REQUIRE(test.n_cols == 2);
for (size_t i = 0; i < 8; i++)
REQUIRE(test[i] == Approx((double) (i + 1)).epsilon(1e-3));
// Remove the file.
remove("test_file.csv");
}
/**
* Make sure a CSV is loaded correctly.
*/
@@ -205,6 +255,32 @@ TEST_CASE("LoadTSVExtensionTest", "[LoadSaveTest]")
remove("test_file.tsv");
}
/**
* Test that we can manually specify the format for loading.
*/
TEST_CASE("LoadAnyExtensionFileTest", "[LoadSaveTest]")
{
fstream f;
f.open("test_file.blah", fstream::out);
f << "1\t2\t3\t4" << endl;
f << "5\t6\t7\t8" << endl;
f.close();
arma::mat test;
REQUIRE(data::Load("test_file.blah", test, false, true, arma::raw_ascii));
REQUIRE(test.n_rows == 4);
REQUIRE(test.n_cols == 2);
for (size_t i = 0; i < 8; ++i)
REQUIRE(test[i] == Approx((double) (i + 1)).epsilon(1e-7));
// Remove the file.
remove("test_file.blah");
}
/**
* Make sure a CSV is saved correctly.
*/
@@ -892,6 +968,32 @@ TEST_CASE("SaveArmaBinaryTest", "[LoadSaveTest]")
remove("test_file.bin");
}
/**
* Make sure that we can manually specify the format.
*/
TEST_CASE("SaveArmaBinaryArbitraryExtensionTest", "[LoadSaveTest]")
{
arma::mat test = "1 5;"
"2 6;"
"3 7;"
"4 8;";
REQUIRE(data::Save("test_file.blerp.blah", test, false, true,
arma::arma_binary) == true);
REQUIRE(data::Load("test_file.blerp.blah", test, false, true,
arma::arma_binary) == true);
REQUIRE(test.n_rows == 4);
REQUIRE(test.n_cols == 2);
for (size_t i = 0; i < 8; ++i)
REQUIRE(test[i] == Approx((double) (i + 1)).epsilon(1e-7));
// Remove the file.
remove("test_file.blerp.blah");
}
/**
* Make sure raw_binary is loaded correctly.
*/
+48 -42
View File
@@ -19,8 +19,8 @@ static const std::string testName = "Kmeans";
#include "test_helper.hpp"
#include <mlpack/methods/kmeans/kmeans_main.cpp>
#include <boost/test/unit_test.hpp>
#include "../test_tools.hpp"
#include "../catch.hpp"
#include "../test_catch_tools.hpp"
using namespace mlpack;
@@ -46,22 +46,21 @@ void ResetKmSettings()
IO::RestoreSettings(testName);
}
BOOST_FIXTURE_TEST_SUITE(KmeansMainTest, KmTestFixture);
/**
* Checking that number of Clusters are non negative
*/
BOOST_AUTO_TEST_CASE(NonNegativeClustersTest)
TEST_CASE_METHOD(KmTestFixture, "NonNegativeClustersTest",
"[KmeansMainTest][BindingTests]")
{
arma::mat inputData;
if (!data::Load("vc2.csv", inputData))
BOOST_FAIL("Unable to load train dataset vc2.csv!");
FAIL("Unable to load train dataset vc2.csv!");
SetInputParam("input", std::move(inputData));
SetInputParam("clusters", (int) -1); // Invalid
Log::Fatal.ignoreInput = true;
BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error);
Log::Fatal.ignoreInput = false;
}
@@ -69,7 +68,8 @@ BOOST_AUTO_TEST_CASE(NonNegativeClustersTest)
/**
* Checking that initial centroids are provided if clusters are to be auto detected
*/
BOOST_AUTO_TEST_CASE(AutoDetectClusterTest)
TEST_CASE_METHOD(KmTestFixture, "AutoDetectClusterTest",
"[KmeansMainTest][BindingTests]")
{
constexpr int N = 10;
constexpr int D = 4;
@@ -80,7 +80,7 @@ BOOST_AUTO_TEST_CASE(AutoDetectClusterTest)
SetInputParam("clusters", (int) 0); // Invalid
Log::Fatal.ignoreInput = true;
BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error);
Log::Fatal.ignoreInput = false;
}
@@ -88,13 +88,14 @@ BOOST_AUTO_TEST_CASE(AutoDetectClusterTest)
/**
* Checking that percentage is between 0 and 1 when --refined_start is specified
*/
BOOST_AUTO_TEST_CASE(RefinedStartPercentageTest)
TEST_CASE_METHOD(KmTestFixture, "RefinedStartPercentageTest",
"[KmeansMainTest][BindingTests]")
{
int c = 2;
double P = 2.0;
arma::mat inputData;
if (!data::Load("vc2.csv", inputData))
BOOST_FAIL("Unable to load train dataset vc2.csv!");
FAIL("Unable to load train dataset vc2.csv!");
SetInputParam("input", std::move(inputData));
SetInputParam("refined_start", true);
@@ -102,7 +103,7 @@ BOOST_AUTO_TEST_CASE(RefinedStartPercentageTest)
SetInputParam("percentage", std::move(P)); // Invalid
Log::Fatal.ignoreInput = true;
BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error);
Log::Fatal.ignoreInput = false;
}
@@ -110,13 +111,14 @@ BOOST_AUTO_TEST_CASE(RefinedStartPercentageTest)
/**
* Checking percentage is non-negative when --refined_start is specified
*/
BOOST_AUTO_TEST_CASE(NonNegativePercentageTest)
TEST_CASE_METHOD(KmTestFixture, "NonNegativePercentageTest",
"[KmeansMainTest][BindingTests]")
{
int c = 2;
double P = -1.0;
arma::mat inputData;
if (!data::Load("vc2.csv", inputData))
BOOST_FAIL("Unable to load train dataset vc2.csv!");
FAIL("Unable to load train dataset vc2.csv!");
SetInputParam("input", std::move(inputData));
SetInputParam("refined_start", true);
@@ -124,7 +126,7 @@ BOOST_AUTO_TEST_CASE(NonNegativePercentageTest)
SetInputParam("percentage", P); // Invalid
Log::Fatal.ignoreInput = true;
BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error);
Log::Fatal.ignoreInput = false;
}
@@ -132,12 +134,13 @@ BOOST_AUTO_TEST_CASE(NonNegativePercentageTest)
/**
* Checking that size and dimensionality of prediction is correct.
*/
BOOST_AUTO_TEST_CASE(KmClusteringSizeCheck)
TEST_CASE_METHOD(KmTestFixture, "KmClusteringSizeCheck",
"[KmeansMainTest][BindingTests]")
{
int c = 2;
arma::mat inputData;
if (!data::Load("vc2.csv", inputData))
BOOST_FAIL("Unable to load train dataset vc2.csv!");
FAIL("Unable to load train dataset vc2.csv!");
size_t col = inputData.n_cols;
size_t row = inputData.n_rows;
@@ -147,22 +150,23 @@ BOOST_AUTO_TEST_CASE(KmClusteringSizeCheck)
mlpackMain();
BOOST_REQUIRE_EQUAL(IO::GetParam<arma::mat>("output").n_rows, row+1);
BOOST_REQUIRE_EQUAL(IO::GetParam<arma::mat>("output").n_cols, col);
BOOST_REQUIRE_EQUAL(IO::GetParam<arma::mat>("centroid").n_rows, row);
BOOST_REQUIRE_EQUAL(IO::GetParam<arma::mat>("centroid").n_cols, c);
REQUIRE(IO::GetParam<arma::mat>("output").n_rows == row+1);
REQUIRE(IO::GetParam<arma::mat>("output").n_cols == col);
REQUIRE(IO::GetParam<arma::mat>("centroid").n_rows == row);
REQUIRE(IO::GetParam<arma::mat>("centroid").n_cols == c);
}
/**
* Checking that size and dimensionality of prediction is correct when --labels_only is specified
*/
BOOST_AUTO_TEST_CASE(KmClusteringSizeCheckLabelOnly)
TEST_CASE_METHOD(KmTestFixture, "KmClusteringSizeCheckLabelOnly",
"[KmeansMainTest][BindingTests]")
{
int c = 2;
arma::mat inputData;
if (!data::Load("vc2.csv", inputData))
BOOST_FAIL("Unable to load train dataset vc2.csv!");
FAIL("Unable to load train dataset vc2.csv!");
size_t col = inputData.n_cols;
size_t row = inputData.n_rows;
@@ -172,24 +176,25 @@ BOOST_AUTO_TEST_CASE(KmClusteringSizeCheckLabelOnly)
mlpackMain();
BOOST_REQUIRE_EQUAL(IO::GetParam<arma::mat>("output").n_rows, 1);
BOOST_REQUIRE_EQUAL(IO::GetParam<arma::mat>("output").n_cols, col);
BOOST_REQUIRE_EQUAL(IO::GetParam<arma::mat>("centroid").n_rows, row);
BOOST_REQUIRE_EQUAL(IO::GetParam<arma::mat>("centroid").n_cols, c);
REQUIRE(IO::GetParam<arma::mat>("output").n_rows == 1);
REQUIRE(IO::GetParam<arma::mat>("output").n_cols == col);
REQUIRE(IO::GetParam<arma::mat>("centroid").n_rows == row);
REQUIRE(IO::GetParam<arma::mat>("centroid").n_cols == c);
}
/**
* Checking that predictions are not same when --allow_empty_clusters or kill_empty_clusters are specified
*/
BOOST_AUTO_TEST_CASE(KmClusteringEmptyClustersCheck)
TEST_CASE_METHOD(KmTestFixture, "KmClusteringEmptyClustersCheck",
"[KmeansMainTest][BindingTests]")
{
int c = 400;
int iterations = 100;
arma::mat inputData;
if (!data::Load("test_data_3_1000.csv", inputData))
BOOST_FAIL("Unable to load train dataset test_data_3_1000.csv!");
FAIL("Unable to load train dataset test_data_3_1000.csv!");
arma::mat initCentroid = arma::randu<arma::mat>(inputData.n_rows, c);
SetInputParam("input", inputData);
@@ -235,23 +240,24 @@ BOOST_AUTO_TEST_CASE(KmClusteringEmptyClustersCheck)
if (killEmptyOutput.n_elem == allowEmptyOutput.n_elem)
{
BOOST_REQUIRE_GT(arma::accu(killEmptyOutput != allowEmptyOutput), 1);
BOOST_REQUIRE_GT(arma::accu(killEmptyOutput != normalOutput), 1);
REQUIRE(arma::accu(killEmptyOutput != allowEmptyOutput) > 1);
REQUIRE(arma::accu(killEmptyOutput != normalOutput) > 1);
}
BOOST_REQUIRE_GT(arma::accu(normalOutput != allowEmptyOutput), 1);
REQUIRE(arma::accu(normalOutput != allowEmptyOutput) > 1);
}
/**
* Checking that that size and dimensionality of Final Input File is correct
* when flag --in_place is specified
*/
BOOST_AUTO_TEST_CASE(KmClusteringResultSizeCheck)
TEST_CASE_METHOD(KmTestFixture, "KmClusteringResultSizeCheck",
"[KmeansMainTest][BindingTests]")
{
int c = 2;
arma::mat inputData;
if (!data::Load("vc2.csv", inputData))
BOOST_FAIL("Unable to load train dataset vc2.csv!");
FAIL("Unable to load train dataset vc2.csv!");
size_t row = inputData.n_rows;
size_t col = inputData.n_cols;
@@ -265,30 +271,32 @@ BOOST_AUTO_TEST_CASE(KmClusteringResultSizeCheck)
// here input is actually accessed through output
// due to a little trick in kmeans_main
BOOST_REQUIRE_EQUAL(processedInput.n_cols, col);
BOOST_REQUIRE_EQUAL(processedInput.n_rows, row+1);
REQUIRE(processedInput.n_cols == col);
REQUIRE(processedInput.n_rows == row+1);
}
/**
* Ensuring that absence of Number of Clusters is checked.
*/
BOOST_AUTO_TEST_CASE(KmClustersNotDefined)
TEST_CASE_METHOD(KmTestFixture, "KmClustersNotDefined",
"[KmeansMainTest][BindingTests]")
{
arma::mat inputData;
if (!data::Load("vc2.csv", inputData))
BOOST_FAIL("Unable to load train dataset vc2.csv!");
FAIL("Unable to load train dataset vc2.csv!");
SetInputParam("input", std::move(inputData));
Log::Fatal.ignoreInput = true;
BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error);
Log::Fatal.ignoreInput = false;
}
/**
* Checking that all the algorithms yield same results
*/
BOOST_AUTO_TEST_CASE(AlgorithmsSimilarTest)
TEST_CASE_METHOD(KmTestFixture, "AlgorithmsSimilarTest",
"[KmeansMainTest][BindingTests]")
{
int c = 5;
arma::mat inputData(10, 1000);
@@ -393,5 +401,3 @@ BOOST_AUTO_TEST_CASE(AlgorithmsSimilarTest)
CheckMatrices(naiveCentroid, dualTreeCentroid);
CheckMatrices(naiveCentroid, dualCoverTreeCentroid);
}
BOOST_AUTO_TEST_SUITE_END();
+9 -14
View File
@@ -26,20 +26,17 @@
#include <mlpack/methods/softmax_regression/softmax_regression.hpp>
#include <ensmallen.hpp>
#include <boost/test/unit_test.hpp>
#include "test_tools.hpp"
#include "catch.hpp"
using namespace mlpack;
using namespace mlpack::ann;
using namespace ens;
using namespace mlpack::regression;
BOOST_AUTO_TEST_SUITE(RBMNetworkTest);
/*
* Tests the BinaryRBM implementation on the Digits dataset.
*/
BOOST_AUTO_TEST_CASE(BinaryRBMClassificationTest)
TEST_CASE("BinaryRBMClassificationTest", "[RBMNetworkTest]")
{
// Normalised dataset.
int hiddenLayerSize = 100;
@@ -84,7 +81,7 @@ BOOST_AUTO_TEST_CASE(BinaryRBMClassificationTest)
double objVal = model.Train(msgd);
// Test that objective value returned by RBM::Train() is finite.
BOOST_REQUIRE_EQUAL(std::isfinite(objVal), true);
REQUIRE(std::isfinite(objVal) == true);
for (size_t i = 0; i < trainData.n_cols; ++i)
{
@@ -117,13 +114,13 @@ BOOST_AUTO_TEST_CASE(BinaryRBMClassificationTest)
// We allow a 6% tolerance because the RBM may not reconstruct samples as
// well. (Typically it does, but we have no guarantee.)
BOOST_REQUIRE_GE(rbmClassificationAccuracy, classificationAccuracy - 6.0);
REQUIRE(rbmClassificationAccuracy >= classificationAccuracy - 6.0);
}
/*
* Tests the SpikeSlabRBM implementation on the Digits dataset.
*/
BOOST_AUTO_TEST_CASE(ssRBMClassificationTest)
TEST_CASE("ssRBMClassificationTest", "[RBMNetworkTest]")
{
size_t batchSize = 10;
size_t numEpoches = 3;
@@ -184,7 +181,7 @@ BOOST_AUTO_TEST_CASE(ssRBMClassificationTest)
double objVal = modelssRBM.Train(msgd);
// Test that objective value returned by RBM::Train() is finite.
BOOST_REQUIRE_EQUAL(std::isfinite(objVal), true);
REQUIRE(std::isfinite(objVal) == true);
for (size_t i = 0; i < trainData.n_cols; ++i)
{
@@ -211,7 +208,7 @@ BOOST_AUTO_TEST_CASE(ssRBMClassificationTest)
// omitted here for speed. We add a margin of 3% since ssRBM isn't guaranteed
// to give us better results (we just generally expect it to be about as good
// or better).
BOOST_REQUIRE_GE(ssRbmClassificationAccuracy, 76.18 - 3.0);
REQUIRE(ssRbmClassificationAccuracy >= 76.18 - 3.0);
}
template<typename MatType = arma::mat>
@@ -239,13 +236,13 @@ void BuildVanillaNetwork(MatType& trainData,
}
for (size_t i = 0; i < freeEnergy.n_elem; ++i)
BOOST_REQUIRE_CLOSE(calculatedFreeEnergy(i), freeEnergy(i), 1e-3);
REQUIRE(calculatedFreeEnergy(i) == Approx(freeEnergy(i)).epsilon(1e-5));
}
/*
* Train and evaluate a Vanilla network with the specified structure.
*/
BOOST_AUTO_TEST_CASE(MiscTest)
TEST_CASE("MiscTest", "[RBMNetworkTest]")
{
arma::Mat<float> X = arma::Mat<float>("0.0, 0.0, 0.0;"
"0.0, 1.0, 1.0;"
@@ -254,5 +251,3 @@ BOOST_AUTO_TEST_CASE(MiscTest)
X = X.t();
BuildVanillaNetwork<arma::Mat<float>>(X, 2);
}
BOOST_AUTO_TEST_SUITE_END();
+33 -38
View File
@@ -19,9 +19,8 @@
#include <mlpack/core/data/binarize.hpp>
#include <mlpack/core/math/random.hpp>
#include <boost/test/unit_test.hpp>
#include "test_tools.hpp"
#include "serialization.hpp"
#include "catch.hpp"
#include "serialization_catch.hpp"
#include "custom_layer.hpp"
using namespace mlpack;
@@ -29,8 +28,6 @@ using namespace mlpack::ann;
using namespace ens;
using namespace mlpack::math;
BOOST_AUTO_TEST_SUITE(RecurrentNetworkTest);
/**
* Construct a 2-class dataset out of noisy sines.
*
@@ -75,7 +72,7 @@ void GenerateNoisySines(arma::cube& data,
/**
* Train the BRNN on a larger dataset.
*/
BOOST_AUTO_TEST_CASE(SequenceClassificationBRNNTest)
TEST_CASE("SequenceClassificationBRNNTest", "[RecurrentNetworkTest]")
{
// Using same test for RNN below.
size_t successes = 0;
@@ -111,10 +108,10 @@ BOOST_AUTO_TEST_CASE(SequenceClassificationBRNNTest)
StandardSGD opt(0.1, 1, 500 * input.n_cols, -100);
model.Train(input, labels, opt);
BOOST_TEST_CHECKPOINT("Training over");
INFO("Training over");
arma::cube prediction;
model.Predict(input, prediction);
BOOST_TEST_CHECKPOINT("Prediction over");
INFO("Prediction over");
size_t error = 0;
for (size_t i = 0; i < prediction.n_cols; ++i)
@@ -133,7 +130,7 @@ BOOST_AUTO_TEST_CASE(SequenceClassificationBRNNTest)
}
double classificationError = 1 - double(error) / prediction.n_cols;
BOOST_TEST_CHECKPOINT(classificationError);
INFO(classificationError);
if (classificationError <= 0.2)
{
++successes;
@@ -141,13 +138,13 @@ BOOST_AUTO_TEST_CASE(SequenceClassificationBRNNTest)
}
}
BOOST_REQUIRE_GE(successes, 1);
REQUIRE(successes >= 1);
}
/**
* Train the vanilla network on a larger dataset.
*/
BOOST_AUTO_TEST_CASE(SequenceClassificationTest)
TEST_CASE("SequenceClassificationTest", "[RecurrentNetworkTest]")
{
// It isn't guaranteed that the recurrent network will converge in the
// specified number of iterations using random weights. If this works 1 of 6
@@ -231,7 +228,7 @@ BOOST_AUTO_TEST_CASE(SequenceClassificationTest)
}
}
BOOST_REQUIRE_GE(successes, 1);
REQUIRE(successes >= 1);
}
/**
@@ -645,13 +642,13 @@ void ReberGrammarTestNetwork(ModelType& model,
offset += 3;
}
BOOST_REQUIRE_GE(successes, 1);
REQUIRE(successes >= 1);
}
/**
* Train the specified networks on an embedded Reber grammar dataset.
*/
BOOST_AUTO_TEST_CASE(LSTMReberGrammarTest)
TEST_CASE("LSTMReberGrammarTest", "[RecurrentNetworkTest]")
{
RNN<MeanSquaredError<> > model(5);
model.Add<Linear<> >(7, 10);
@@ -664,7 +661,7 @@ BOOST_AUTO_TEST_CASE(LSTMReberGrammarTest)
/**
* Train the specified networks on an embedded Reber grammar dataset.
*/
BOOST_AUTO_TEST_CASE(FastLSTMReberGrammarTest)
TEST_CASE("FastLSTMReberGrammarTest", "[RecurrentNetworkTest]")
{
RNN<MeanSquaredError<> > model(5);
model.Add<Linear<> >(7, 8);
@@ -677,7 +674,7 @@ BOOST_AUTO_TEST_CASE(FastLSTMReberGrammarTest)
/**
* Train the specified networks on an embedded Reber grammar dataset.
*/
BOOST_AUTO_TEST_CASE(GRURecursiveReberGrammarTest)
TEST_CASE("GRURecursiveReberGrammarTest", "[RecurrentNetworkTest]")
{
RNN<MeanSquaredError<> > model(5);
model.Add<Linear<> >(7, 16);
@@ -690,7 +687,7 @@ BOOST_AUTO_TEST_CASE(GRURecursiveReberGrammarTest)
/**
* Train BLSTM on an embedded Reber grammar dataset.
*/
BOOST_AUTO_TEST_CASE(BRNNReberGrammarTest)
TEST_CASE("BRNNReberGrammarTest", "[RecurrentNetworkTest]")
{
BRNN<MeanSquaredError<>, AddMerge<>, SigmoidLayer<> > model(5);
model.Add<Linear<> >(7, 10);
@@ -869,14 +866,14 @@ void DistractedSequenceRecallTestNetwork(
offset += 2;
}
BOOST_REQUIRE_GE(successes, 1);
REQUIRE(successes >= 1);
}
/**
* Train the specified networks on the Derek D. Monner's distracted sequence
* recall task.
*/
BOOST_AUTO_TEST_CASE(LSTMDistractedSequenceRecallTest)
TEST_CASE("LSTMDistractedSequenceRecallTest", "[RecurrentNetworkTest]")
{
DistractedSequenceRecallTestNetwork<LSTM<> >(4, 8);
}
@@ -885,7 +882,7 @@ BOOST_AUTO_TEST_CASE(LSTMDistractedSequenceRecallTest)
* Train the specified networks on the Derek D. Monner's distracted sequence
* recall task.
*/
BOOST_AUTO_TEST_CASE(FastLSTMDistractedSequenceRecallTest)
TEST_CASE("FastLSTMDistractedSequenceRecallTest", "[RecurrentNetworkTest]")
{
DistractedSequenceRecallTestNetwork<FastLSTM<> >(4, 8);
}
@@ -894,7 +891,7 @@ BOOST_AUTO_TEST_CASE(FastLSTMDistractedSequenceRecallTest)
* Train the specified networks on the Derek D. Monner's distracted sequence
* recall task.
*/
BOOST_AUTO_TEST_CASE(GRUDistractedSequenceRecallTest)
TEST_CASE("GRUDistractedSequenceRecallTest", "[RecurrentNetworkTest]")
{
DistractedSequenceRecallTestNetwork<GRU<> >(4, 8);
}
@@ -956,7 +953,7 @@ void BatchSizeTest()
/**
* Ensure LSTMs work with larger batch sizes.
*/
BOOST_AUTO_TEST_CASE(LSTMBatchSizeTest)
TEST_CASE("LSTMBatchSizeTest", "[RecurrentNetworkTest]")
{
BatchSizeTest<LSTM<>>();
}
@@ -964,7 +961,7 @@ BOOST_AUTO_TEST_CASE(LSTMBatchSizeTest)
/**
* Ensure fast LSTMs work with larger batch sizes.
*/
BOOST_AUTO_TEST_CASE(FastLSTMBatchSizeTest)
TEST_CASE("FastLSTMBatchSizeTest", "[RecurrentNetworkTest]")
{
BatchSizeTest<FastLSTM<>>();
}
@@ -972,7 +969,7 @@ BOOST_AUTO_TEST_CASE(FastLSTMBatchSizeTest)
/**
* Ensure GRUs work with larger batch sizes.
*/
BOOST_AUTO_TEST_CASE(GRUBatchSizeTest)
TEST_CASE("GRUBatchSizeTest", "[RecurrentNetworkTest]")
{
BatchSizeTest<GRU<>>();
}
@@ -980,7 +977,7 @@ BOOST_AUTO_TEST_CASE(GRUBatchSizeTest)
/**
* Make sure the RNN can be properly serialized.
*/
BOOST_AUTO_TEST_CASE(SerializationTest)
TEST_CASE("RNNSerializationTest", "[RecurrentNetworkTest]")
{
const size_t rho = 10;
@@ -1172,13 +1169,13 @@ void ReberGrammarTestCustomNetwork(const size_t hiddenSize = 4,
offset += 3;
}
BOOST_REQUIRE_GE(successes, 1);
REQUIRE(successes >= 1);
}
/**
* Train the specified networks on an embedded Reber grammar dataset.
*/
BOOST_AUTO_TEST_CASE(CustomRecursiveReberGrammarTest)
TEST_CASE("CustomRecursiveReberGrammarTest", "[RecurrentNetworkTest]")
{
ReberGrammarTestCustomNetwork(16, true);
}
@@ -1312,16 +1309,16 @@ double RNNSineTest(size_t hiddenUnits, size_t rho, size_t numEpochs = 100)
/**
* Test RNN using multiple timestep input and single output.
*/
BOOST_AUTO_TEST_CASE(MultiTimestepTest)
TEST_CASE("MultiTimestepTest", "[RecurrentNetworkTest]")
{
double err = RNNSineTest(4, 10, 20);
BOOST_REQUIRE_LE(err, 0.025);
REQUIRE(err <= 0.025);
}
/**
* Test that RNN::Train() returns finite objective value.
*/
BOOST_AUTO_TEST_CASE(RNNTrainReturnObjective)
TEST_CASE("RNNTrainReturnObjective", "[RecurrentNetworkTest]")
{
const size_t rho = 10;
@@ -1371,13 +1368,13 @@ BOOST_AUTO_TEST_CASE(RNNTrainReturnObjective)
StandardSGD opt(0.1, 1, input.n_cols /* 1 epoch */, -100);
double objVal = model.Train(input, labels, opt);
BOOST_REQUIRE_EQUAL(std::isfinite(objVal), true);
REQUIRE(std::isfinite(objVal) == true);
}
/**
* Test that BRNN::Train() returns finite objective value.
*/
BOOST_AUTO_TEST_CASE(BRNNTrainReturnObjective)
TEST_CASE("BRNNTrainReturnObjective", "[RecurrentNetworkTest]")
{
const size_t rho = 10;
@@ -1407,16 +1404,16 @@ BOOST_AUTO_TEST_CASE(BRNNTrainReturnObjective)
StandardSGD opt(0.1, 1, 500 * input.n_cols, -100);
double objVal = model.Train(input, labels, opt);
BOOST_TEST_CHECKPOINT("Training over");
INFO("Training over");
// Test that BRNN::Train() returns finite objective value.
BOOST_REQUIRE_EQUAL(std::isfinite(objVal), true);
REQUIRE(std::isfinite(objVal) == true);
}
/**
* Test that RNN::Train() does not give an error for large rho.
*/
BOOST_AUTO_TEST_CASE(LargeRhoValueRnnTest)
TEST_CASE("LargeRhoValueRnnTest", "[RecurrentNetworkTest]")
{
// Setting rho value greater than sequence length which is 17.
const size_t rho = 100;
@@ -1473,7 +1470,5 @@ BOOST_AUTO_TEST_CASE(LargeRhoValueRnnTest)
}
ens::SGD<> opt(0.01, 1, 100);
model.Train(inputs[0], targets[0], opt);
BOOST_TEST_CHECKPOINT("Training over");
INFO("Training over");
}
BOOST_AUTO_TEST_SUITE_END();