Приближение синусоидальной функции с нейронной сетью

В целях обучения я реализовал простую структуру нейронной сети, которая поддерживает только многослойные персептроны и простое обратное распространение. Он работает нормально для линейной классификации и обычной задачи XOR, но для приближения синусоидальной функции результаты не такие удовлетворительные.

Я в основном пытаюсь приблизить один период синусоидальной функции одним скрытым слоем, состоящим из 6-10 нейронов. Сеть использует гиперболический тангенс в качестве функции активации для скрытого слоя и линейную функцию для вывода. Результат остается довольно грубой оценкой синусоиды и требует много времени для расчета.

Я посмотрел на encog для справки, но даже при этом мне не удается заставить его работать с простым обратным распространением (при переключении на устойчивое распространение оно начинает улучшаться, но все еще намного хуже, чем сценарий super slick R, представленный в этом похожем вопросе). Так я на самом деле пытаюсь сделать что-то, что невозможно? Разве невозможно аппроксимировать синус простым обратным распространением (без импульса, без динамической скорости обучения)? Какой метод используется библиотекой нейронных сетей в R?

РЕДАКТИРОВАТЬ: Я знаю, что определенно возможно найти достаточно хорошее приближение даже с простым обратным распространением (если вам невероятно повезло с вашими начальными весами), но на самом деле мне было более интересно узнать, является ли это осуществимым подходом. Сценарий R, с которым я связан, кажется, сходится так невероятно быстро и надежно (в 40 эпохах с небольшим количеством обучающих примеров) по сравнению с моей реализацией или даже поддерживает устойчивое распространение. Мне просто интересно, могу ли я что-то сделать, чтобы улучшить алгоритм обратного распространения, чтобы добиться такой же производительности, или мне нужно искать какой-нибудь более продвинутый метод обучения?

Ответ 1

Это может быть довольно легко реализовано с использованием современных сред для нейронных сетей, таких как TensorFlow.

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

enter image description here

Код также довольно прост:

import tensorflow as tf
import numpy as np

with tf.name_scope('placeholders'):
    x = tf.placeholder('float', [None, 1])
    y = tf.placeholder('float', [None, 1])

with tf.name_scope('neural_network'):
    x1 = tf.contrib.layers.fully_connected(x, 100)
    x2 = tf.contrib.layers.fully_connected(x1, 100)
    result = tf.contrib.layers.fully_connected(x2, 1,
                                               activation_fn=None)

    loss = tf.nn.l2_loss(result - y)

with tf.name_scope('optimizer'):
    train_op = tf.train.AdamOptimizer().minimize(loss)

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())

    # Train the network
    for i in range(10000):
        xpts = np.random.rand(100) * 10
        ypts = np.sin(xpts)

        _, loss_result = sess.run([train_op, loss],
                                  feed_dict={x: xpts[:, None],
                                             y: ypts[:, None]})

        print('iteration {}, loss={}'.format(i, loss_result))

Ответ 2

Ты определенно не пытаешься сделать невозможное. Нейронные сети универсальные аппроксиматоры - это означает, что для любой функции F и ошибки E существует некоторая нейронная сеть (требуется только один скрытый слой), который может приблизительный F с ошибкой меньше E.

Конечно, обнаружение того, что (те) сеть (сети) - совершенно другое дело. И самое лучшее, что я могу вам сказать, это проб и ошибок... Вот основная процедура:

  • Разделите свои данные на две части: обучающий набор (~ 2/3) и набор тестов (~ 1/3).
  • Обучите свою сеть всем элементам учебного набора.
  • Протестируйте (но не тренируйте) свою сеть по всем элементам набора тестов и запишите среднюю ошибку.
  • Повторяйте шаги 2 и 3 до тех пор, пока вы не достигнете минимальной ошибки тестирования (это происходит при "переобучении", когда ваша сеть начинает получать хорошие результаты обучения в ущерб всему остальному) или до тех пор, пока ваша общая ошибка не прекратится заметно уменьшая (подразумевая, что сеть так же хороша, как и она).
  • Если ошибка на этом этапе приемлемо низкая, все готово. Если нет, ваша сеть не является достаточно сложной для обработки функции, для которой вы ее тренируете; добавьте более скрытые нейроны и вернитесь к началу...

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

Надеюсь, что это поможет (и жаль, что я не могу быть более полезным)!

PS: Я также знаю, что это возможно, так как я видел, что кто-то приблизился к сети с сетью. Я хочу сказать, что она не использовала функцию активации сигмоида, но я не могу гарантировать свою память на этом счету...

Ответ 3

Один очень важный шаг, это рандомизировать данные обучения. Если вы тренируете его последовательно, то сетка забудет верхнюю часть кривой к тому времени, как она достигнет дна, и наоборот.