diff --git a/src/mlpack/methods/ann/augmented/tasks/add_impl.hpp b/src/mlpack/methods/ann/augmented/tasks/add_impl.hpp index 6d11a8c192..c1b3e70807 100644 --- a/src/mlpack/methods/ann/augmented/tasks/add_impl.hpp +++ b/src/mlpack/methods/ann/augmented/tasks/add_impl.hpp @@ -22,7 +22,8 @@ namespace tasks /* Task utilities for augmented */ { AddTask::AddTask(const size_t bitLen) : bitLen(bitLen) { - if (bitLen <= 0) { + if (bitLen <= 0) + { std::ostringstream oss; oss << "AddTask::AddTask(): binary length (" << bitLen << ") " << "is not positive!" @@ -36,8 +37,8 @@ const void AddTask::Generate(arma::field& input, const size_t batchSize, bool fixedLength) { - arma::field vecInput = arma::field(batchSize); - arma::field vecLabels = arma::field(batchSize); + input = arma::field(batchSize); + labels = arma::field(batchSize); size_t sizeA = bitLen, sizeB = bitLen; for (size_t i = 0; i < batchSize; ++i) { @@ -50,21 +51,23 @@ const void AddTask::Generate(arma::field& input, // Construct sequence of the form // (binary number with sizeA bits) + '+' // + (binary number with sizeB bits). - vecInput(i) = arma::randi( - sizeA + sizeB + 1, arma::distr_param(0, 1)); + input(i) = arma::randi(sizeA + sizeB + 1, + 1, + arma::distr_param(0, 1)); // Insert special value for '+' delimiter. - vecInput(i).at(sizeA) = 0.5; - + labels(i) = arma::zeros(sizeA + sizeB + 1, 1); + input(i).at(sizeA, 0) = 0.5; + int valA = 0; for (size_t k = 0; k < sizeA; ++k) { - valA += static_cast(vecInput(i).at(k)) << k; + valA += static_cast(input(i).at(k, 0)) << k; } int valB = 0; for (size_t k = sizeA + 1; k < sizeA + 1 + sizeB; ++k) { - valB += static_cast(vecInput(i).at(k)) << (k - sizeA - 1); + valB += static_cast(input(i).at(k, 0)) << (k - sizeA - 1); } int tot = valA + valB; @@ -85,27 +88,11 @@ const void AddTask::Generate(arma::field& input, } binarySeq.push_back(0); } - size_t totLen = binarySeq.size(); - vecLabels(i) = arma::colvec(totLen); - for (size_t j = 0; j < totLen; ++j) + for (size_t j = 0; j < binarySeq.size(); ++j) { - vecLabels(i).at(j) = binarySeq[j]; + labels(i).at(j, 0) = binarySeq[j]; } } - Binarize(vecInput, input); - Binarize(vecLabels, labels); - if (input.n_rows != labels.n_rows) { - std::ostringstream oss; - oss << "AddTask::Generate(): sequences after application of " - << "Binarize() are not aligned (" - << input.n_rows << " and " << labels.n_rows << ")" - << std::endl; - throw std::logic_error(oss.str()); - } - for (size_t i = 0; i < input.n_rows; ++i) - { - labels.at(i).reshape(input.at(i).n_elem, 1); - } } const void AddTask::Generate(arma::mat& input, @@ -129,13 +116,6 @@ const void AddTask::Binarize(const arma::field& input, output = arma::field(input.n_elem); for (size_t i = 0; i < input.n_elem; ++i) { - /*output.at(i) = arma::zeros(3, input.at(i).n_elem); - for (size_t j = 0; j < input.at(i).n_elem; ++j) - { - size_t val = input.at(i).at(j); - output.at(i).at(val, j) = 1; - } - output.at(i).reshape(output.at(i).n_elem, 1);*/ output.at(i) = arma::conv_to::from(input.at(i)); } } diff --git a/src/mlpack/methods/ann/augmented/tasks/copy.hpp b/src/mlpack/methods/ann/augmented/tasks/copy.hpp index b73f8acba0..5088414fae 100644 --- a/src/mlpack/methods/ann/augmented/tasks/copy.hpp +++ b/src/mlpack/methods/ann/augmented/tasks/copy.hpp @@ -54,11 +54,11 @@ class CopyTask * that has to be repeated by model. * @param nRepeats Number of repeates required to solve the task. * @param addSeparator Flag indicating whether generator - * should emit separating symbol after input sequence + * should emit separating symbol after input sequence. */ CopyTask(const size_t maxLength, const size_t nRepeats, - bool addSeparator = false); + const bool addSeparator = false); /** * Generate dataset of a given size. * diff --git a/src/mlpack/methods/ann/augmented/tasks/copy_impl.hpp b/src/mlpack/methods/ann/augmented/tasks/copy_impl.hpp index 2ba5bb0325..b511a74d12 100644 --- a/src/mlpack/methods/ann/augmented/tasks/copy_impl.hpp +++ b/src/mlpack/methods/ann/augmented/tasks/copy_impl.hpp @@ -22,7 +22,7 @@ namespace tasks /* Task utilities for augmented */ { CopyTask::CopyTask(const size_t maxLength, const size_t nRepeats, - bool addSeparator) : + const bool addSeparator) : maxLength(maxLength), nRepeats(nRepeats), addSeparator(addSeparator) @@ -72,13 +72,13 @@ const void CopyTask::Generate(arma::field& input, vecInput; if (addSeparator) input(i).at(vecInput.n_elem, 0) = 0.5; - input(i).col(1).rows(addSeparator+vecInput.n_elem, totSize-1) = - arma::ones(totSize-vecInput.n_elem-addSeparator); + input(i).col(1).rows(addSeparator + vecInput.n_elem, totSize - 1) = + arma::ones(totSize-vecInput.n_elem - addSeparator); input(i) = input(i).t(); input(i).reshape(input(i).n_elem, 1); labels(i) = arma::zeros(totSize, 1); - labels(i).col(0).rows(addSeparator+vecInput.n_elem, totSize-1) = - vecLabel; + labels(i).col(0).rows(addSeparator + vecInput.n_elem, totSize - 1) = + vecLabel; } } diff --git a/src/mlpack/methods/ann/augmented/tasks/score.hpp b/src/mlpack/methods/ann/augmented/tasks/score.hpp index 2b3c892c9b..d0b8e5cb2d 100644 --- a/src/mlpack/methods/ann/augmented/tasks/score.hpp +++ b/src/mlpack/methods/ann/augmented/tasks/score.hpp @@ -27,11 +27,13 @@ namespace scorers /* Scoring utilities for augmented */ { * * @param trueOutputs Ground truth sequences. * @param predOutputs Sequences predicted by model. +* @param tol Minimum absolute difference value +* which is considered as a model failure. */ template -double SequencePrecision(arma::field trueOutputs, - arma::field predOutputs, - double tol = 1e-4); +const double SequencePrecision(arma::field trueOutputs, + arma::field predOutputs, + double tol = 1e-4); } // namespace scorers } // namespace augmented } // namespace ann diff --git a/src/mlpack/methods/ann/augmented/tasks/score_impl.hpp b/src/mlpack/methods/ann/augmented/tasks/score_impl.hpp index 236bc082d3..cee5faba4b 100644 --- a/src/mlpack/methods/ann/augmented/tasks/score_impl.hpp +++ b/src/mlpack/methods/ann/augmented/tasks/score_impl.hpp @@ -21,9 +21,9 @@ namespace augmented /* Augmented neural network */ { namespace scorers /* Scoring utilities for augmented */ { template -double SequencePrecision(arma::field trueOutputs, - arma::field predOutputs, - double tol) +const double SequencePrecision(arma::field trueOutputs, + arma::field predOutputs, + double tol) { double score = 0; size_t testSize = trueOutputs.n_elem; @@ -42,8 +42,7 @@ double SequencePrecision(arma::field trueOutputs, arma::vec delta = arma::vectorise(arma::abs( trueOutputs.at(i) - predOutputs.at(i))); double maxDelta = arma::max(delta); - double eps = tol; - if (maxDelta < eps) + if (maxDelta < tol) { score++; } diff --git a/src/mlpack/methods/ann/augmented/tasks/sort.hpp b/src/mlpack/methods/ann/augmented/tasks/sort.hpp index 58b60755ec..877fbb21d5 100644 --- a/src/mlpack/methods/ann/augmented/tasks/sort.hpp +++ b/src/mlpack/methods/ann/augmented/tasks/sort.hpp @@ -44,6 +44,8 @@ class SortTask * * @param maxLength Maximum length of the number sequence. * @param bitLen Binary length of sorted numbers. + * @param addSeparator Flag indicating whether generator + * should emit separating symbol after input sequence. */ SortTask(const size_t maxLength, const size_t bitLen, @@ -54,6 +56,8 @@ class SortTask * @param input The variable to store input sequences. * @param labels The variable to store output sequences. * @param batchSize The dataset size. + * @param fixedLength Flag indicating whether generator + * should emit sequences of pairwise equal length. */ const void Generate(arma::field& input, arma::field& labels, diff --git a/src/mlpack/methods/ann/augmented/tasks/sort_impl.hpp b/src/mlpack/methods/ann/augmented/tasks/sort_impl.hpp index 0c7c208710..311afcb797 100644 --- a/src/mlpack/methods/ann/augmented/tasks/sort_impl.hpp +++ b/src/mlpack/methods/ann/augmented/tasks/sort_impl.hpp @@ -2,7 +2,7 @@ * @file sort_impl.hpp * @author Konstantin Sidorov * - * Implementation of SortTask class + * Implementation of SortTask 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 diff --git a/src/mlpack/tests/augmented_rnns_tasks_test.cpp b/src/mlpack/tests/augmented_rnns_tasks_test.cpp index 9d77b77f61..89c7ed2a2a 100644 --- a/src/mlpack/tests/augmented_rnns_tasks_test.cpp +++ b/src/mlpack/tests/augmented_rnns_tasks_test.cpp @@ -46,39 +46,43 @@ using mlpack::data::Binarize; // The dummy model that simply copies the sequence // the required number of times // (yes, no ML here, we're unit testing :) -class HardCodedCopyModel { +class HardCodedCopyModel +{ public: HardCodedCopyModel() : nRepeats(1) {} - void Train( - arma::field& predictors, - arma::field& labels) { + void Train(arma::field& predictors, + arma::field& labels) + { arma::mat input = predictors.at(0); arma::mat output = labels.at(0); size_t zeroCnt = 0, oneCnt = 0; - for (size_t i = 1; i < input.n_rows; i += 2) { + for (size_t i = 1; i < input.n_rows; i += 2) + { size_t& addVar = (input.at(i, 0) == 0) ? zeroCnt : oneCnt; ++addVar; } assert(oneCnt % zeroCnt == 0); nRepeats = oneCnt / zeroCnt; } - void Predict( - arma::mat& predictors, - arma::mat& labels) { + void Predict(arma::mat& predictors, + arma::mat& labels) + { size_t seqLen = (predictors.n_rows / 2) / (nRepeats + 1); size_t outputLen = nRepeats * seqLen; assert(2 * (seqLen + outputLen) == predictors.n_rows); labels.zeros(predictors.n_rows / 2, 1); - for (size_t i = 0; i < outputLen; ++i) { + for (size_t i = 0; i < outputLen; ++i) + { labels.at(seqLen+i) = predictors.at(2 * (i % seqLen)); } } - void Predict( - arma::field& predictors, - arma::field& labels) { + void Predict(arma::field& predictors, + arma::field& labels) + { size_t sz = predictors.n_elem; labels = arma::field(sz); - for (size_t i = 0; i < sz; ++i) { + for (size_t i = 0; i < sz; ++i) + { Predict(predictors.at(i), labels.at(i)); } } @@ -87,6 +91,7 @@ class HardCodedCopyModel { size_t nRepeats; }; +// The dummy model that simply sorts the sequence. class HardCodedSortModel { public: HardCodedSortModel(size_t bitLen) : bitLen(bitLen) {} @@ -95,34 +100,38 @@ class HardCodedSortModel { { assert(predictors.n_elem == labels.n_elem); } - void Predict( - arma::mat& predictors, - arma::mat& labels) + void Predict(arma::mat& predictors, + arma::mat& labels) { predictors = predictors.t(); predictors.reshape(bitLen, predictors.n_elem / bitLen); size_t len = predictors.n_cols; labels.zeros(bitLen, len); vector> vals(len); - for (size_t j = 0; j < len; ++j) { + for (size_t j = 0; j < len; ++j) + { int val = 0; - for (size_t k = 0; k < bitLen; ++k) { + for (size_t k = 0; k < bitLen; ++k) + { val <<= 1; val += predictors.at(k, j); } vals[j] = make_pair(val, j); } sort(vals.begin(), vals.end()); - for (size_t j = 0; j < len; ++j) { + for (size_t j = 0; j < len; ++j) + { labels.col(j) = predictors.col(vals[j].second); } labels.reshape(predictors.n_elem, 1); } void Predict(arma::field& predictors, - arma::field& labels) { + arma::field& labels) + { auto sz = predictors.n_elem; labels = arma::field(sz); - for (size_t i = 0; i < sz; ++i) { + for (size_t i = 0; i < sz; ++i) + { Predict(predictors.at(i), labels.at(i)); } } @@ -131,22 +140,24 @@ class HardCodedSortModel { size_t bitLen; }; +// The dummy model that simply add two binary numbers. class HardCodedAddModel { public: HardCodedAddModel() {} void Train(arma::field& predictors, arma::field& labels) { - return; + // Nothing to do here. } void Predict(arma::mat& predictors, arma::mat& labels) { - int num_A = 0, num_B = 0; + int numA = 0, numB = 0; bool num = false; // true iff we have already seen the separating symbol size_t len = predictors.n_elem; size_t cnt = 0; - for (size_t i = 0; i < len; ++i) { + for (size_t i = 0; i < len; ++i) + { double digit = predictors.at(i); if (digit != 0 && digit != 1) { @@ -160,28 +171,31 @@ class HardCodedAddModel { { if (num) { - num_B += static_cast(digit) << cnt; + numB += static_cast(digit) << cnt; } else { - num_A += static_cast(digit) << cnt; + numA += static_cast(digit) << cnt; } ++cnt; } } - int total = num_A + num_B; + int total = numA + numB; vector binary_seq; - while (total > 0) { + while (total > 0) + { binary_seq.push_back(total & 1); total >>= 1; } - if (binary_seq.empty()) { - assert(num_A + num_B == 0); + if (binary_seq.empty()) + { + assert(numA + numB == 0); binary_seq.push_back(0); } - size_t tot_len = binary_seq.size(); - labels = arma::zeros(tot_len); - for (size_t j = 0; j < tot_len; ++j) { + size_t totLen = binary_seq.size(); + labels = arma::zeros(totLen); + for (size_t j = 0; j < totLen; ++j) + { labels.at(j) = binary_seq[j]; } labels.reshape(predictors.n_elem, 1); @@ -191,7 +205,8 @@ class HardCodedAddModel { arma::field& labels) { size_t sz = predictors.n_elem; labels = arma::field(sz); - for (size_t i = 0; i < sz; ++i) { + for (size_t i = 0; i < sz; ++i) + { Predict(predictors.at(i), labels.at(i)); } } @@ -208,9 +223,11 @@ BOOST_AUTO_TEST_SUITE(AugmentedRNNsTasks); BOOST_AUTO_TEST_CASE(CopyTaskTest) { // Check the setup on various lengths... - for (size_t maxLen = 2; maxLen <= 16; ++maxLen) { + for (size_t maxLen = 2; maxLen <= 16; ++maxLen) + { // .. and various numbers of repetitions. - for (size_t nRepeats = 1; nRepeats <= 10; ++nRepeats) { + for (size_t nRepeats = 1; nRepeats <= 10; ++nRepeats) + { CopyTask task(maxLen, nRepeats); arma::field trainPredictor, trainResponse; task.Generate(trainPredictor, trainResponse, 8); @@ -230,9 +247,11 @@ BOOST_AUTO_TEST_CASE(CopyTaskTest) // Test of SortTask instance generator. // The data from generator is fed to the dummy hard-coded model above // that should be able to solve the task perfectly. -BOOST_AUTO_TEST_CASE(SortTaskTest) { +BOOST_AUTO_TEST_CASE(SortTaskTest) +{ size_t bitLen = 5; - for (size_t maxLen = 2; maxLen <= 16; ++maxLen) { + for (size_t maxLen = 2; maxLen <= 16; ++maxLen) + { SortTask task(maxLen, bitLen); arma::field trainPredictor, trainResponse; task.Generate(trainPredictor, trainResponse, 8); @@ -251,8 +270,10 @@ BOOST_AUTO_TEST_CASE(SortTaskTest) { // Test of AddTask instance generator. // The data from generator is fed to the dummy hard-coded model above // that should be able to solve the task perfectly. -BOOST_AUTO_TEST_CASE(AddTaskTest) { - for (size_t bitLen = 2; bitLen <= 16; ++bitLen) { +BOOST_AUTO_TEST_CASE(AddTaskTest) +{ + for (size_t bitLen = 2; bitLen <= 16; ++bitLen) + { AddTask task(bitLen); arma::field trainPredictor, trainResponse; task.Generate(trainPredictor, trainResponse, 8);