(проект в разработке)
Цель данного проекта - создание нейросети и условий для ее самообучения. В идеале, это будет бомжовый робот минимальной комплектации (возможно даже без жесткого диска), который в зависимости от окружающих условий будет определять свою полезность. Также, он будет "программироваться" снаружи с помощью окружения оставленного другими роботами, формирующими "улей". Апогеем будет саморепликация.
Кроме достижения цели, важен и процесс. Наблюдать за самообучением и выбором действий у нейросети очень интересно.
Нейросеть изнутри:
Мигающие точки - нейроны, линии - синапсы (связи), справа эмулятор мира майнкрафт на движке Love 2d.
Нейросети устроены похожим образом. Есть входные значения, скрытые слои и выходные значения.
В моей программе робот собирает информацию вокруг себя. На вход подается:
Есть ли блоки над, под и перед ним
Насколько много клеток он "разведовал" за последнее действие
Его позиция в виде значений x,y,z от 0 до 1
Иногда я тестирую со значениями стороны куда он смотрит, возможностью двигаться, расстоянию до последней удачной копки
Нейросеть "думает" и выдает 5 значений, которые соответствуют действиям движения 1) вперед, 2) вниз, 3) вверх, 4) вправо, 5) влево. Робот выполняет большее из этих значений.
Далее, после действия, я вычисляю коэффициент полезности r [0..1] для этого действия.
-- swingSucces: количество вскопанных блоков за действие [0..3]
-- input.exploreSucces: коэффициент разведки [0..1], где 0 - уже разводовал все 3 блока, 1 - впервые проверил эти 3 блока
-- logic(input.sweetsD < input.old.sweetsD): расстояние до последней удачной копки увеличилось 0, или уменьшилось 1
r = (swingSucces + input.exploreSucces + logic(input.sweetsD < input.old.sweetsD)) / 5
Нейросеь обучается, и в выбранное выходное значение приписывается r a остальные уменьшаются\увеличиваются на 1-r
for i=1, #output do
output[i] = switch i
when actKey
(output[i]+val^2)/2
when rndKey
(output[i]+(1-val))/2
when oppositeKey
(output[i]+(1-val))/4
else
output[i]
nn:propagate(output)
Теперь матан. В начале я использовал обычный Персептрон, найденный готовый на ЛУА, но который мне пришлось править.
Проблема в том, что он не может учитывать последние состояния. Нейросети с памятью называются "Long short-term memory" или LSTM, где каждый нейрон выглядит вот так:
Найдя библиотеку synaptic.js, хитрыми путями я извлек из нее готовую LSTM сеть, которая получилась на 53 000 строк. Но это не проблема, если зайдет, я перепрограммирую ее на LUA.
Текущее состояние сети - отстой. Я неправильно ее обучаю, так как не знаю какие значения выдавать для "обратного распространения ошибки".
Круча разные коэффициенты, у меня получилось научить ее двигаться по спирали, как карьерный робот.
Сейчас, когда я добавил во входные значения расстояние до последней удачной копки, он научился "кушать" как яблоко, но с огромный количеством лишних действий.
В самом майне блоков намного больше и это выглядит вот так.
На первом скрине работал 1 робот, на втором штук 6.
Сейчас в их действиях слишком много шума. Я специально не даю им кирки, что бы они не унеслись в бесконечность.
Фидбек
Мне нужно помощь. Подскажите, что лучше подавать на вход, и как обучать сеть.
Главная проблема, что для обучения я должен указать какие значения должны быть на выходах при текущих условиях, а я и сам не знаю. Обычно, робот теряется в пустом пространстве и я не знаю какое действие ему казать как "единственно правильное".
А так, буду сюда отписываться и отчитываться о процессе разработки.
Update 20.06.19, веб-версия эмулятора