/*============================================================================= Copyright (c) 2011-2016 Bolero MURAKAMI https://github.com/bolero-MURAKAMI/Sprout Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) =============================================================================*/ #include #include #include #include #include #include #include #include #include #include // // perceptron // template class perceptron { public: typedef FloatType value_type; private: struct worker { public: // 入力 sprout::array xi1; sprout::array xi2; sprout::array xi3; // 出力 sprout::array o1; sprout::array o2; sprout::array o3; }; private: // 誤差 sprout::array d2; sprout::array d3; // 重み sprout::array w1; sprout::array w2; private: // 順伝播 template SPROUT_CXX14_CONSTEXPR void forward_propagation(ForwardIterator in_first, ForwardIterator in_last, worker& work) const { // 入力層の順伝播 sprout::copy(in_first, in_last, sprout::begin(work.xi1)); work.xi1[In] = 1; sprout::copy(sprout::begin(work.xi1), sprout::end(work.xi1), sprout::begin(work.o1)); // 隠れ層の順伝播 for (std::size_t i = 0; i != Hid; ++i) { work.xi2[i] = 0; for (std::size_t j = 0; j != In + 1; ++j) { work.xi2[i] += w1[j * Hid + i] * work.o1[j]; } work.o2[i] = sprout::math::sigmoid(work.xi2[i]); } work.o2[Hid] = 1; // 出力層の順伝播 for (std::size_t i = 0; i != Hid; ++i) { work.xi3[i] = 0; for (std::size_t j = 0; j != In + 1; ++j) { work.xi3[i] += w2[j * Out + i] * work.o2[j]; } work.o3[i] = work.xi3[i]; } } public: template explicit SPROUT_CXX14_CONSTEXPR perceptron(RandomNumberGenerator& rng) : d2{{}}, d3{{}} , w1(sprout::random::generate_array<(In + 1) * Hid>(rng, sprout::random::uniform_01())) , w2(sprout::random::generate_array<(Hid + 1) * Out>(rng, sprout::random::uniform_01())) {} // ニューラルネットの訓練 // [in_first, in_last) : 訓練データ (N*In 個) // [t_first, t_last) : 教師データ (N 個) template SPROUT_CXX14_CONSTEXPR void train( ForwardIterator1 in_first, ForwardIterator1 in_last, ForwardIterator2 t_first, ForwardIterator2 t_last, std::size_t repeat = 1000, value_type eta = value_type(0.1) ) { SPROUT_ASSERT(sprout::distance(in_first, in_last) % In == 0); SPROUT_ASSERT(sprout::distance(in_first, in_last) / In == sprout::distance(t_first, t_last)); worker work{}; for (std::size_t times = 0; times != repeat; ++times) { ForwardIterator1 in_it = in_first; ForwardIterator2 t_it = t_first; for (; in_it != in_last; sprout::advance(in_it, In), ++t_it) { // 順伝播 forward_propagation(in_it, sprout::next(in_it, In), work); // 出力層の誤差計算 for (std::size_t i = 0; i != Out; ++i) { d3[i] = *t_it == i ? work.o3[i] - 1 : work.o3[i] ; } // 出力層の重み更新 for (std::size_t i = 0; i != Hid + 1; ++i) { for (std::size_t j = 0; j != Out; ++j) { w2[i * Out + j] -= eta * d3[j] * work.o2[i]; } } // 隠れ層の誤差計算 for (std::size_t i = 0; i != Hid + 1; ++i) { d2[i] = 0; for (std::size_t j = 0; j != Out; ++j) { d2[i] += w2[i * Out + j] * d3[j]; } d2[i] *= sprout::math::d_sigmoid(work.xi2[i]); } // 隠れ層の重み更新 for (std::size_t i = 0; i != In + 1; ++i) { for (std::size_t j = 0; j != Hid; ++j) { w1[i * Hid + j] -= eta * d2[j] * work.o1[i]; } } } } } // 与えられたデータに対して最も可能性の高いクラスを返す template SPROUT_CXX14_CONSTEXPR std::size_t predict(ForwardIterator in_first, ForwardIterator in_last) const { SPROUT_ASSERT(sprout::distance(in_first, in_last) == In); worker work{}; // 順伝播による予測 forward_propagation(in_first, in_last, work); // 出力が最大になるクラスを判定 return sprout::distance( sprout::begin(work.o3), sprout::max_element(sprout::begin(work.o3), sprout::end(work.o3)) ); } }; #include #include #include #include #include #include // 訓練データ SPROUT_CONSTEXPR auto train_data = sprout::make_array( # include "g3_train.csv" ); // 教師データ SPROUT_CONSTEXPR auto teach_data = sprout::make_array( # include "g3_teach.csv" ); SPROUT_STATIC_ASSERT(train_data.size() % 2 == 0); SPROUT_STATIC_ASSERT(train_data.size() / 2 == teach_data.size()); // 訓練済みパーセプトロンを生成 template SPROUT_CXX14_CONSTEXPR ::perceptron make_trained_perceptron() { // 乱数生成器 sprout::random::default_random_engine rng(SPROUT_UNIQUE_SEED); // パーセプトロン ::perceptron per(rng); // 訓練 per.train( train_data.begin(), train_data.end(), teach_data.begin(), teach_data.end(), 500, 0.1 ); return per; } int main() { // パーセプトロンを生成(入力2 隠れ3 出力3) SPROUT_CXX14_CONSTEXPR auto per = ::make_trained_perceptron(); // 結果の表示 for (auto it = train_data.begin(), last = train_data.end(); it != last; it += 2) { std::cout << per.predict(it, it + 2) << std::endl; } }