2016-02-29 3 views
-1

Я немного новичок в родовом программировании с шаблонами в C++ и задаю вопрос о том, как вернуть объект из шаблонной функции. Это часть модуля нейронной сети библиотеки mlpack. Это из файла feedforward_network_test.cpp, который можно найти here. Если я это правильно понимаю, то, как настроена функция BuildVanillaNetwork, можно передать различные типы сетевых параметров для построения нейронной сети. Я бы хотел, чтобы эта функция возвращала объект FFN, который он строит, чтобы я мог получить доступ к нему из того места, где я его называю. Я сделал некоторые небольшие изменения в код там же:C++ return from template

template <typename PerformanceFunction, 
     typename OutputLayerType, 
     typename PerformanceFunctionType, 
     typename MatType = arma::mat 
     > 
mlpack::ann::FFN<> BuildVanillaNetwork(MatType& trainData, 
     MatType& trainLabels, 
     MatType& testData, 
     MatType& testLabels, 
     const size_t hiddenLayerSize, 
     const size_t maxEpochs, 
     const double classificationErrorThreshold) 
{ 
    // input layer 
    mlpack::ann::LinearLayer<> inputLayer(trainData.n_rows, hiddenLayerSize); 
    mlpack::ann::BiasLayer<> inputBiasLayer(hiddenLayerSize); 
    mlpack::ann::BaseLayer<PerformanceFunction> inputBaseLayer; 

    // hidden layer 
    mlpack::ann::LinearLayer<> hiddenLayer1(hiddenLayerSize, trainLabels.n_rows); 
    mlpack::ann::BiasLayer<> hiddenBiasLayer1(trainLabels.n_rows); 
    mlpack::ann::BaseLayer<PerformanceFunction> outputLayer; 

    // output layer 
    OutputLayerType classOutputLayer; 

    auto modules = std::tie(inputLayer, inputBiasLayer, inputBaseLayer, hiddenLayer1, hiddenBiasLayer1, outputLayer); 
    mlpack::ann::FFN<decltype(modules), decltype(classOutputLayer), mlpack::ann::RandomInitialization, PerformanceFunctionType> net(modules, classOutputLayer); 
    net.Train(trainData, trainLabels); 
    MatType prediction; 
    net.Predict(testData, prediction); 

    double classificationError; 
    for (size_t i = 0; i < testData.n_cols; i++) 
    { 
     if (arma::sum(arma::sum(arma::abs(prediction.col(i) - testLabels.col(i)))) != 0) 
     { 
      classificationError++; 
     } 
    } 

    classificationError = double(classificationError)/testData.n_cols; 

    std::cout << "Classification Error = " << classificationError * 100 << "%" << std::endl; 

    return net; 
} 

И вот главная функция:

int main(int argc, char** argv) 
{ 
    arma::mat dataset; 
    mlpack::data::Load("../data/thyroid_train.csv", dataset, true); 
    arma::mat trainData = dataset.submat(0, 0, dataset.n_rows - 4, dataset.n_cols - 1); 
    arma::mat trainLabels = dataset.submat(dataset.n_rows - 3, 0, dataset.n_rows - 1, dataset.n_cols - 1); 

    mlpack::data::Load("../data/thyroid_test.csv", dataset, true); 
    arma::mat testData = dataset.submat(0, 0, dataset.n_rows - 4, dataset.n_cols - 1); 
    arma::mat testLabels = dataset.submat(dataset.n_rows - 3, 0, dataset.n_rows - 1, dataset.n_cols - 1); 

    const size_t hiddenLayerSize = 8; 
    const size_t maxEpochs = 200; 
    const double classificationErrorThreshold = 0.1; 

    auto myFFN = BuildVanillaNetwork<mlpack::ann::LogisticFunction, mlpack::ann::BinaryClassificationLayer, mlpack::ann::MeanSquaredErrorFunction> 
     (trainData, trainLabels, testData, testLabels, hiddenLayerSize, maxEpochs, classificationErrorThreshold); 

    return 0; 
} 

Когда я компилирую это, я получаю следующее сообщение об ошибке:

[100%] Building CXX object CMakeFiles/ff_nn.dir/src/ff_nn.cpp.o /home/username/project-yanack/mlpack_nn/src/ff_nn.cpp:24:18: error: wrong number of template arguments (0, should be 4) mlpack::ann::FFN<> BuildVanillaNetwork(MatType& trainData, 
       ^In file included from /home/username/project-yanack/mlpack_nn/src/ff_nn.cpp:16:0: /usr/local/include/mlpack/methods/ann/ffn.hpp:35:7: error: provided for ‘template<class LayerTypes, class OutputLayerType, class InitializationRuleType, class PerformanceFunction> class mlpack::ann::FFN’ class FFN 
    ^/home/username/project-yanack/mlpack_nn/src/ff_nn.cpp: In instantiation of ‘int BuildVanillaNetwork(MatType&, MatType&, MatType&, MatType&, size_t, size_t, double) [with PerformanceFunction 
= mlpack::ann::LogisticFunction; OutputLayerType = mlpack::ann::BinaryClassificationLayer; PerformanceFunctionType = mlpack::ann::MeanSquaredErrorFunction; MatType = arma::Mat<double>; size_t = long unsigned int]’: /home/username/project-yanack/mlpack_nn/src/ff_nn.cpp:83:112: required from here /home/username/project-yanack/mlpack_nn/src/ff_nn.cpp:64:12: error: cannot convert ‘mlpack::ann::FFN<std::tuple<mlpack::ann::LinearLayer<arma::Mat<double>, arma::Mat<double> >&, mlpack::ann::BiasLayer<arma::Mat<double>, arma::Mat<double> >&, mlpack::ann::BaseLayer<mlpack::ann::LogisticFunction, arma::Mat<double>, arma::Mat<double> >&, mlpack::ann::LinearLayer<arma::Mat<double>, arma::Mat<double> >&, mlpack::ann::BiasLayer<arma::Mat<double>, arma::Mat<double> >&, mlpack::ann::BaseLayer<mlpack::ann::LogisticFunction, arma::Mat<double>, arma::Mat<double> >&>, mlpack::ann::BinaryClassificationLayer, mlpack::ann::RandomInitialization, mlpack::ann::MeanSquaredErrorFunction>’ to ‘int’ in return 
    return net; 
      ^make[2]: *** [CMakeFiles/ff_nn.dir/src/ff_nn.cpp.o] Error 1 make[1]: *** [CMakeFiles/ff_nn.dir/all] Error 2 make: *** [all] Error 2 

Любая помощь в исправлении этого оценивается. Кроме того, будет здорово, если я смогу получить ссылки на учебник, в котором объясняются различные понятия, используемые в этом коде.

EDIT-1

Я изменил заголовок функции к следующему:

template <typename PerformanceFunction, 
     typename OutputLayerType, 
     typename PerformanceFunctionType, 
     typename MatType = arma::mat 
     > 
mlpack::ann::FFN<PerformanceFunction, OutputLayerType, PerformanceFunctionType, MatType> BuildVanillaNetwork(MatType& trainData, 
     MatType& trainLabels, 
     MatType& testData, 
     MatType& testLabels, 
     const size_t hiddenLayerSize, 
     const size_t maxEpochs, 
     const double classificationErrorThreshold) 

Но я все еще получаю ошибку при компиляции:

[100%] Building CXX object CMakeFiles/ff_nn.dir/src/ff_nn.cpp.o 
In file included from /home/username/project-yanack/mlpack_nn/src/ff_nn.cpp:16:0: 
/usr/local/include/mlpack/methods/ann/ffn.hpp: In instantiation of ‘class mlpack::ann::FFN<mlpack::ann::LogisticFunction, mlpack::ann::BinaryClassificationLayer, mlpack::ann::MeanSquaredErrorFunction, arma::Mat<double> >’: 
/home/username/project-yanack/mlpack_nn/src/ff_nn.cpp:83:112: required from here 
/usr/local/include/mlpack/methods/ann/ffn.hpp:361:55: error: incomplete type ‘std::tuple_size<mlpack::ann::LogisticFunction>’ used in nested name specifier 
     size_t Max = std::tuple_size<LayerTypes>::value - 1, 
                ^
/usr/local/include/mlpack/methods/ann/ffn.hpp:369:55: error: incomplete type ‘std::tuple_size<mlpack::ann::LogisticFunction>’ used in nested name specifier 
     size_t Max = std::tuple_size<LayerTypes>::value - 1, 
                ^
/home/username/project-yanack/mlpack_nn/src/ff_nn.cpp: In instantiation of ‘mlpack::ann::FFN<PerformanceFunction, OutputLayerType, PerformanceFunctionType, MatType> BuildVanillaNetwork(MatType&, MatType&, MatType&, MatType&, size_t, size_t, double) [with PerformanceFunction = mlpack::ann::LogisticFunction; OutputLayerType = mlpack::ann::BinaryClassificationLayer; PerformanceFunctionType = mlpack::ann::MeanSquaredErrorFunction; MatType = arma::Mat<double>; size_t = long unsigned int]’: 
/home/username/project-yanack/mlpack_nn/src/ff_nn.cpp:83:112: required from here 
/home/username/project-yanack/mlpack_nn/src/ff_nn.cpp:64:12: error: could not convert ‘net’ from ‘mlpack::ann::FFN<std::tuple<mlpack::ann::LinearLayer<arma::Mat<double>, arma::Mat<double> >&, mlpack::ann::BiasLayer<arma::Mat<double>, arma::Mat<double> >&, mlpack::ann::BaseLayer<mlpack::ann::LogisticFunction, arma::Mat<double>, arma::Mat<double> >&, mlpack::ann::LinearLayer<arma::Mat<double>, arma::Mat<double> >&, mlpack::ann::BiasLayer<arma::Mat<double>, arma::Mat<double> >&, mlpack::ann::BaseLayer<mlpack::ann::LogisticFunction, arma::Mat<double>, arma::Mat<double> >&>, mlpack::ann::BinaryClassificationLayer, mlpack::ann::RandomInitialization, mlpack::ann::MeanSquaredErrorFunction>’ to ‘mlpack::ann::FFN<mlpack::ann::LogisticFunction, mlpack::ann::BinaryClassificationLayer, mlpack::ann::MeanSquaredErrorFunction, arma::Mat<double> >’ 
    return net; 
      ^
make[2]: *** [CMakeFiles/ff_nn.dir/src/ff_nn.cpp.o] Error 1 
make[1]: *** [CMakeFiles/ff_nn.dir/all] Error 2 
make: *** [all] Error 2 

Кроме того, подпись класс FFN (here), кажется, отличается от того, что у меня есть в этой функции. Это может быть проблема? Если это так, как я могу это исправить, так как эти типы имен на самом деле не являются «типами», насколько я понимаю.

Спасибо.

+0

Какого C++ стандарт? 11? 14? –

+0

@Joel: C++ 11 asaik. Потому что я установил CMAKE_CXX_FLAGS в -std = C++ 11. – shaun

+0

На моем телефоне, поэтому я не могу найти решение, но вам нужно как-то указать правильный тип возврата. Чтобы сделать его более приемлемым, вы можете разбить его на куски, используя объявления псевдонима. Кроме того, если вы захотите переключиться на C++ 14, вы можете избежать всей этой глупости и заменить тип возврата на «auto». –

ответ

0

mlpack::ann::FFN<> BuildVanillaNetwork(MatType& trainData,

Изменить его к чему-то, что включает в себя параметры из шаблона, Somthing как:

mlpack::ann::FFN< 
    PerformanceFunction, 
    OutputLayerType, 
    PerformanceFunctionType, 
    MatType 
> BuildVanillaNetwork(MatType& trainData,... 

Или попробовать decltype(auto), если ваш компилятор поддерживает его:

auto BuildVanillaNetwork(MatType& trainData,`...) -> decltype(auto) {... 
+0

Я не уверен, что это проблема. Потому что, даже если я просто позвоню BuildVanillaNetwork, не сохранив его возвращения нигде, я получаю ту же ошибку во время компиляции. Кроме того, я не уверен, как определить фактический тип, поскольку первым параметром шаблона FFN является тип decltype (modules), который, как я понимаю, определяет тип во время выполнения. – shaun

+0

Хорошо, извините, первая ошибка жалуется на отсутствие аргументов шаблона. Сделал изменения в ответе. – wally

+0

Так что эта ошибка возникает из-за 'decltype (net)! = Mlpack :: ann :: FFN <>'. Неважно, сохраняете ли вы результат или нет, вы все еще говорите компилятору, что функция возвращает последний, когда на самом деле он возвращает прежний. Параметры шаблона должны совпадать, чтобы типы были одинаковыми. –

0

Проблема заключается в том ваше определение BuildVanillaNetwork функционирует как:

mlpack::ann::FFN<> BuildVanillaNetwork(...) 

Ошибка сообщения обычно трудно читать человеком, когда они связаны с шаблонами, но чтение через линии дает вам что-то вроде этого:

error: wrong number of template arguments (0, should be 4) ... provided for ‘template class mlpack::ann::FFN’

Остальные ошибки вызваны этим один (в основном, потому что он не понимает тип возврата этой функции, компилятор предполагает, что он равен int, тогда он жалуется, что он не может преобразовать net в int).

Итак, вы должны указать аргументы шаблона для возвращаемого типа. Вы используете decltype в теле функции, чтобы вывести их (что происходит во время компиляции, а не во время выполнения), но в прототипе это будет не так просто.Существует способ использовать decltype, чтобы объявить возвращаемый тип функции, но в этом случае вам это не поможет. Таким образом, вы можете продолжать и писать их явно.

+0

@ lonut: Я вижу. Если я напишу их явно, тогда мне придется писать несколько функций для FFN с разными параметрами, правильно? Кроме того, первым параметром шаблона является decltype (modules), который является std :: tie из группы вещей (количество аргументов будет варьироваться). Поэтому я не уверен, как вывести сам тип, чтобы написать их явно. – shaun

+0

Параметры шаблона для FFN, вероятно, зависят от параметров шаблона для функции, правильно? В этом случае вам не придется писать несколько функций, и вы не можете писать несколько функций, которые отличаются только типом возврата. – Ionut

+0

Параметры для std :: tie могут отличаться, но это класс шаблона, поэтому параметры шаблона будут полностью решены во время компиляции. – Ionut

0

Вы можете использовать следующий шаблон для нескольких упростить вывод типа возвращаемого значения:

template<typename PerformanceFunction, typename OutputLayerType, 
    typename PerformanceFunctionType, typename MatType> 
struct BuildVanillaNetworkHelper 
{ 
    using LinearLayer = mlpack::ann::LinearLayer<>; 
    using BiasLayer = mlpack::ann::BiasLayer<>; 
    using BaseLayer = mlpack::ann::BaseLayer<PerformanceFunction>; 
    using ModulesType = std::tuple<LinearLayer, BiasLayer, BaseLayer, 
     LinearLayer, BiasLayer, BaseLayer>; 
    using FFNType = mlpack::ann::FFN<ModulesType, OutputLayerType, 
     mlpack::ann::RandomInitialization, PerformanceFunctionType>; 
}; 

template <typename PerformanceFunction, 
     typename OutputLayerType, 
     typename PerformanceFunctionType, 
     typename MatType = arma::mat, 
     typename Helper = BuildVanillaNetworkHelper< 
      PerformanceFunction, OutputLayerType, 
      PerformanceFunctionType, MatType> 
     > 
typename Helper::FFNType BuildVanillaNetwork(...);