#include #include #include #include #include #include #include #include #include using namespace psemek::ml; using namespace psemek::random; using namespace psemek::math; using namespace psemek::log; namespace { double learn_batch(neural_net & nn, std::vector, std::vector>> const & batch, double mu, std::size_t iterations) { neural_net_learner learner; std::size_t const debug_report_frequency = iterations / 8; double error = 0.0; for (std::size_t iteration = 0; iteration < iterations; ++iteration) { learner.clear(); error = 0.0; for (auto const & data : batch) { learner.apply(nn, data.first); error += l2_loss(data.second, learner.result()) / batch.size(); learner.backpropagate_l2(nn, data.second); } if ((iteration % debug_report_frequency) == 0) debug() << "Iteration " << iteration << " error: " << error; learner.descend(nn, mu); } return error; } } test_case(ml_neural__net_learn_not__2__layers) { generator rng; neural_net nn({1, 1}, activation_type::sigmoid); randomize_normal(nn, rng); std::vector, std::vector>> dataset; dataset.push_back({{0.0}, {1.0}}); dataset.push_back({{1.0}, {0.0}}); double error = learn_batch(nn, dataset, 16.0, 1024); expect_less(error, 1e-3); info() << "Error: " << error; } test_case(ml_neural__net_learn_and__2__layers) { generator rng; neural_net nn({2, 1}, activation_type::sigmoid); randomize_normal(nn, rng); std::vector, std::vector>> dataset; dataset.push_back({{0.0, 0.0}, {0.0}}); dataset.push_back({{1.0, 0.0}, {0.0}}); dataset.push_back({{0.0, 1.0}, {0.0}}); dataset.push_back({{1.0, 1.0}, {1.0}}); double error = learn_batch(nn, dataset, 16.0, 1024); expect_less(error, 1e-3); info() << "Error: " << error; } test_case(ml_neural__net_learn_and__3__layers) { generator rng; neural_net nn({2, 2, 1}, activation_type::sigmoid); randomize_normal(nn, rng); std::vector, std::vector>> dataset; dataset.push_back({{0.0, 0.0}, {0.0}}); dataset.push_back({{1.0, 0.0}, {0.0}}); dataset.push_back({{0.0, 1.0}, {0.0}}); dataset.push_back({{1.0, 1.0}, {1.0}}); double error = learn_batch(nn, dataset, 1.0, 1024); expect_less(error, 1e-3); info() << "Error: " << error; } test_case(ml_neural__net_learn_or__2__layers) { generator rng; neural_net nn({2, 1}, activation_type::sigmoid); randomize_normal(nn, rng); std::vector, std::vector>> dataset; dataset.push_back({{0.0, 0.0}, {0.0}}); dataset.push_back({{1.0, 0.0}, {1.0}}); dataset.push_back({{0.0, 1.0}, {1.0}}); dataset.push_back({{1.0, 1.0}, {1.0}}); double error = learn_batch(nn, dataset, 16.0, 1024); expect_less(error, 1e-3); info() << "Error: " << error; } test_case(ml_neural__net_learn_or__3__layers) { generator rng; neural_net nn({2, 2, 1}, activation_type::sigmoid); randomize_normal(nn, rng); std::vector, std::vector>> dataset; dataset.push_back({{0.0, 0.0}, {0.0}}); dataset.push_back({{1.0, 0.0}, {1.0}}); dataset.push_back({{0.0, 1.0}, {1.0}}); dataset.push_back({{1.0, 1.0}, {1.0}}); double error = learn_batch(nn, dataset, 1.0, 1024); expect_less(error, 1e-3); info() << "Error: " << error; } test_case(ml_neural__net_learn_xor__3__layers) { generator rng; neural_net nn({2, 2, 1}, activation_type::sigmoid); randomize_normal(nn, rng); std::vector, std::vector>> dataset; dataset.push_back({{0.0, 0.0}, {1.0}}); dataset.push_back({{1.0, 0.0}, {0.0}}); dataset.push_back({{0.0, 1.0}, {0.0}}); dataset.push_back({{1.0, 1.0}, {1.0}}); double error = learn_batch(nn, dataset, 1.0, 2048); expect_less(error, 1e-3); info() << "Error: " << error; }