В настоящее время я создаю библиотеку машинного обучения.
Суть проблемы: когда я добавляю слишком много (и слишком больших) скрытых слоев в NN, он выводит NAN или -NAN. Почему это происходит? Могу ли я сделать так, чтобы этого не произошло? Если я не могу, что я могу / должен сделать, чтобы библиотека профессионально с этим справилась?
Один из модульных тестов библиотеки (полная шкала) выглядит следующим образом:
struct testTrainWithMultipleLayers : public ZNN::NeuralNetwork<double>
{
ZNN::NeuralNetwork<double> b;
std::vector<std::vector<double>> input{{1, 0}, {0, 1}, {0, 0}, {1, 1}};
std::vector<std::vector<double>> target{{1}, {1}, {0}, {0}};
testTrainWithMultipleLayers()
{
withNeuralNetwork();
trainForNIterations(1000);
requireCorrectOutputs();
}
void withNeuralNetwork()
{
b.setInputLayerSize(2);
b.addHiddenLayer(50);
b.setOutputLayerSize(1);
b.setLearningRate(0.7);
b.setNormalization(ZNN::Fermi<double>());
}
void trainForNIterations(size_t iterations)
{
/////train the neural networks for so and so many iterations
}
void requireCorrectOutputs()
{
///check the expected values were correctly approximated
}
};
Тест проходит хорошо!
Но когда я изменяю withNeuralNetwork
на это:
void withNeuralNetwork()
{
b.setInputLayerSize(2);
b.addHiddenLayer(50);
b.addHiddenLayer(50);
b.addHiddenLayer(50);
b.addHiddenLayer(50);
b.addHiddenLayer(50);
b.addHiddenLayer(50);
b.addHiddenLayer(50);
b.addHiddenLayer(50);
b.addHiddenLayer(50);
b.addHiddenLayer(50);
b.addHiddenLayer(50);
b.setOutputLayerSize(1);
b.setLearningRate(0.7);
b.setNormalization(ZNN::Fermi<double>());
}
Вывод моего модульного теста выглядит следующим образом:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
test is a Catch v2.3.0 host application.
Run with -? for options
-------------------------------------------------------------------------------
Neural Network
-------------------------------------------------------------------------------
test_NN.hpp:9
...............................................................................
test_NN.hpp:263: FAILED:
CHECK( Disabled by CATCH_CONFIG_DISABLE_STRINGIFICATION )
with expansion:
Approx( nan ) == 2.0
test_NN.hpp:264: FAILED:
CHECK( Disabled by CATCH_CONFIG_DISABLE_STRINGIFICATION )
with expansion:
Approx( nan ) == 2.0
test_NN.hpp:265: FAILED:
CHECK( Disabled by CATCH_CONFIG_DISABLE_STRINGIFICATION )
with expansion:
Approx( nan ) == 1.0
test_NN.hpp:266: FAILED:
CHECK( Disabled by CATCH_CONFIG_DISABLE_STRINGIFICATION )
with expansion:
Approx( nan ) == 1.0
===============================================================================
test cases: 5 | 4 passed | 1 failed
assertions: 50 | 46 passed | 4 failed
NN выводит NAN или -NAN (в зависимости от настройки)
Возможно, стоит отметить, что это происходит не только с моим конкретным модульным тестом, но и с каждым NN-приложением, которое я создал с использованием этой библиотеки (что до сих пор не было слишком большим делом, как я мог уменьшить размер NN, пока он не заработает).
Я обнаружил, где это происходит в первый раз: это происходит в функции, которая изменяет веса нейрона, алгоритм получает производную, равную nan, что превращает весь NN-каскад в выходной NAN.
Я убедился, что деление на 0 не производится. Единственное деление во всем коде NN - это 1/2 * error
, используемое для вычисления ошибки NN и деления в нормализации, но я убедился, что там тоже нет деления на 0. Или скорее: при решении для exp (x) = 0
, х не определено
Код юнит теста здесь: https://github.com/Wittmaxi/ZENeural/blob/master/library/tests/test_NN.cpp#L220
Редактировать
Это также происходит, когда я изменяю withNeuralNetwork
на это:
void withNeuralNetwork()
{
b.setInputLayerSize(2);
b.addHiddenLayer(5000);
b.setOutputLayerSize(1);
b.setLearningRate(0.7);
b.setNormalization(ZNN::Fermi<double>());
}