11

Niedawno obejrzałem wideo, które zainspirowało mnie do napisania własnego systemu sieci neuronowej, i chciałem, aby ilość węzłów w sieci była regulowana.Klasa z typami zależnymi od szablonów variadycznych

Najpierw osiągnąłem to w czasie wykonywania, analizując tablicę liczb węzłów, ale zastanawiałem się, czy mógłbym to zrobić w czasie kompilacji. Oto przykład tego, co miałem nadzieję osiągnąć.

template<int FirstNodes, int SecondNodes, int... OtherNodes> 
class Net 
{ 
    tuple<Eigen::Matrix<float, FirstNodes, SecondNodes>, ...> m_weights; 
    // More matricies with the values from the OtherNodes 
}; 

W bardziej szczegółowym przykładzie Net<784, 16, 16, 10> n; n.m_weight powinien mieć type

tuple<Eigen::Matrix<float, 784, 16>, 
    Eigen::Matrix<float, 16, 16>, 
    Eigen::Matrix<float, 16, 10>> 

Z tego, co wiem o C++ i constexpr, powinno to być możliwe.

Dodam, że jestem w stanie zrobić

template<int FirstNodes, int SecondNodes, int... OtherNodes> 
class Net 
{ 
public: 
    Net() 
    { 
     auto nodes = {FirstNodes, SecondNodes, OtherNodes...}; 

     auto i = nodes.begin(); 
     do 
     { 
      // Eigen::Matrix<float, Dynamic, Dynamic> 
      Eigen::MatrixXf m(*(i++), *i); 
     } while (i+1 != nodes.end()); 
    } 
}; 

Ale ja po prostu ponownie stosując dynamiczne matricies i że nie jest to, co miałem nadzieję.

Wszelkie porady lub przykłady pracy byłyby mile widziane.

+0

nawiasem mówiąc, linia 'm (* (i ++), * i)' niezdefiniowanej zachowanie wywołuje aż do C++ 14, nie określone w C++ 17 –

+0

* bezwstydny samo promowanie * można wybrać [ to repo] (https://github.com/liammcinroy/MetaTemplateNeuralNet) jest interesujące –

Odpowiedz

6

Chcecie jakąś transformację typu, że daną listę N liczb zwraca tuple z matryc tuple. Oto C++ 17 Rozwiązanie:

template <int A, int B, int... Is> 
auto make_matrix_tuple() 
{ 
    if constexpr(sizeof...(Is) == 0) 
    { 
     return std::tuple<Eigen::Matrix<float, A, B>>{}; 
    } 
    else 
    { 
     return std::tuple_cat(make_matrix_tuple<A, B>(), 
          make_matrix_tuple<B, Is...>()); 
    } 
} 

live example on wandbox


w C++ 11, można wdrożyć ten typ transformacji rekurencyjnie:

template <int... Is> 
struct matrix_tuple_helper; 

template <int A, int B, int... Rest> 
struct matrix_tuple_helper<A, B, Rest...> 
{ 
    using curr_matrix = Eigen::Matrix<float, A, B>; 
    using type = 
     decltype(
      std::tuple_cat(
       std::tuple<curr_matrix>{}, 
       typename matrix_tuple_helper<B, Rest...>::type{} 
      ) 
     ); 
}; 

template <int A, int B> 
struct matrix_tuple_helper<A, B> 
{ 
    using curr_matrix = Eigen::Matrix<float, A, B>; 
    using type = std::tuple<curr_matrix>; 
}; 

template <int... Is> 
using matrix_tuple = typename matrix_tuple_helper<Is...>::type; 

C++ 14 podejście:

struct matrix_tuple_maker 
{ 
    template <int A, int B, int C, int... Is> 
    static auto get() 
    { 
     return std::tuple_cat(get<A, B>(), get<B, C, Is...>()); 
    } 

    template <int A, int B> 
    static auto get() 
    { 
     return std::tuple<Eigen::Matrix<float, A, B>>{}; 
    } 
}; 

static_assert(std::is_same_v< 
    decltype(matrix_tuple_maker::get<784, 16, 16, 10>()), 
    std::tuple<Eigen::Matrix<float, 784, 16>, 
       Eigen::Matrix<float, 16, 16>, 
       Eigen::Matrix<float, 16, 10>> 
    >); 
1

Wydaje mi się, że trzeba dwa listę liczb całkowitych, z etapu 1.

Jeżeli zdefiniowanie trywialny pojemnik szablon Integer (w C++ 14 można użyć std::integer_sequence)

template <int...> 
struct iList 
{ }; 

można zdefiniować klasę bazową następująco (przepraszam: używany foo zamiast Eigen::Matrix)

template <typename, typename, typename = std::tuple<>> 
struct NetBase; 

// avoid the first couple 
template <int ... Is, int J0, int ... Js> 
struct NetBase<iList<0, Is...>, iList<J0, Js...>, std::tuple<>> 
    : NetBase<iList<Is...>, iList<Js...>, std::tuple<>> 
{ }; 

// intermediate case 
template <int I0, int ... Is, int J0, int ... Js, typename ... Ts> 
struct NetBase<iList<I0, Is...>, iList<J0, Js...>, std::tuple<Ts...>> 
    : NetBase<iList<Is...>, iList<Js...>, 
      std::tuple<Ts..., foo<float, I0, J0>>> 
{ }; 

// avoid the last couple and terminate 
template <int I0, typename ... Ts> 
struct NetBase<iList<I0>, iList<0>, std::tuple<Ts...>> 
{ using type = std::tuple<Ts...>; }; 

i Net prostu stać (obserwować z kilku faz całkowitych list)

template <int F, int S, int... Os> 
struct Net : NetBase<iList<0, F, S, Os...>, iList<F, S, Os..., 0>> 
{ }; 

Poniżej znajduje się pełna kompilacja przykład

#include <tuple> 

template <int...> 
struct iList 
{ }; 

template <typename, int, int> 
struct foo 
{ }; 

template <typename, typename, typename = std::tuple<>> 
struct NetBase; 

// avoid the first couple 
template <int ... Is, int J0, int ... Js> 
struct NetBase<iList<0, Is...>, iList<J0, Js...>, std::tuple<>> 
    : NetBase<iList<Is...>, iList<Js...>, std::tuple<>> 
{ }; 

// intermediate case 
template <int I0, int ... Is, int J0, int ... Js, typename ... Ts> 
struct NetBase<iList<I0, Is...>, iList<J0, Js...>, std::tuple<Ts...>> 
    : NetBase<iList<Is...>, iList<Js...>, 
      std::tuple<Ts..., foo<float, I0, J0>>> 
{ }; 

// avoid the last couple and terminate 
template <int I0, typename ... Ts> 
struct NetBase<iList<I0>, iList<0>, std::tuple<Ts...>> 
{ using type = std::tuple<Ts...>; }; 

template <int F, int S, int... Os> 
struct Net : NetBase<iList<0, F, S, Os...>, iList<F, S, Os..., 0>> 
{ }; 

int main() 
{ 
    static_assert(std::is_same< 
     typename Net<784, 16, 16, 10>::type, 
     std::tuple<foo<float, 784, 16>, foo<float, 16, 16>, 
       foo<float, 16, 10>>>{}, "!"); 
} 
0

Oto kolejne rozwiązanie C++ 14. Uważam, że warto go publikować, ponieważ jest nierekurencyjny i czytelny.

#include <tuple> 
#include <utility> 

template<class, int, int> struct Matrix {}; 

template<int... matsizes, std::size_t... matinds> 
constexpr auto make_net(
    std::integer_sequence<int, matsizes...>, 
    std::index_sequence<matinds...> 
) { 
    constexpr int sizes[] = {matsizes...}; 
    return std::tuple< Matrix<float, sizes[matinds], sizes[1+matinds]>... >{}; 
} 

template<int... matsizes> 
constexpr auto make_net(
    std::integer_sequence<int, matsizes...> sizes 
) { 
    static_assert(sizes.size() >= 2, ""); 
    constexpr auto number_of_mats = sizes.size() - 1; 
    return make_net(sizes, std::make_index_sequence<number_of_mats>{}); 
} 

int main() { 
    auto net = make_net(std::integer_sequence<int, 784, 16, 16, 10>{}); 
    using Net = decltype(net); 

    static_assert(
    std::is_same< 
     std::tuple< 
     Matrix<float, 784, 16>, 
     Matrix<float, 16, 16>, 
     Matrix<float, 16, 10> 
     >, 
     Net 
    >{}, "" 
); 

    return 0; 
}