Pull to refresh

Comments 69

Все верно, я использовал тот же принцип, но задачу выбрал чуть полегче для разминки. К тому же у них используется более сильная нейронная сеть, в моем примере она попроще, но для наглядности в самый раз.
Даже не задумывался над этим, сейчас глянул, если верить описанию выходит тут тоже Q-learning. Когда писал алгоритм думал только над логикой.
ну просто странно что если

Все верно, я использовал тот же принцип


то ни разу не упомянуто не то что бы ссылка на эту статью, а понятия обучение с подкреплением или по не русски reinforcement learning

вы градиент весов как расчитываете?
Для управления нейронной сетью я использую framework Encog, насколько я помню он напрямую зависит от используемой функции активации, в данном фреймворке их 19, использовать можно любой, результаты будут различны. Для меня пока не столько важна сама сеть, сколько механизмы ее использования, поэтому я не углубляюсь пока в ее архитектуру.
я вот что то порылся в вашем коде, а так же в мануале этого Енкога, не нашел ничего про то какая там целевая функция юзается; скорее всего MSE просто; но в общем не нужно вводить в заблуждение народ, у вас не deep Q-learning, а просто нейросетка которая обучается обычным обучением с учителем
В целом соглашусь, ибо когда писал, опирался только на логику, в основе нет какой либо конкретной литературы, только то, что уже имелось в голове. Судя по описанию алгоритма Q-learning сходства у них есть, но это не тот самый алгоритм однозначно.
Шикарно, а над своим фреймворком не думали? Очевидно же, что для роботов понадобится такое…
Для роботов можно его хоть сейчас применять, нужно только решить вопрос с сенсорным восприятием и не забыть сменить «цель» с уничтожения всего живого.
Применять, можно, в частном порядке и с Вашей помощью. Но я говорил о фреймворке: наборе документированных стандартных блоков кода, с помощью которых любой программист сможет быстро создать интеллект робота, с учётом доступных сенсоров и рабочих органов.
Ясно, это будет не сложно, попробую сделать такой фрэймворк, опишу потом в формате статьи. Спасибо за идею.
Я бы выбрал такой порядок: RefreshSense → SaveToMemory → Train → Compute → Output → Move
Полностью согласен, на самом деле он такой и есть, так как весь процесс циклический то move в начале всегда проходит после output в конце, не считая момента появления на свет объекта, в первый раз он просто стоит на месте.
Было б интересно если бы было еще размножение, тогда бы эта штука могла жить долго и не заканчивались тем что остается только несколько сильных нейронов.
В начале так и сделал, но им этот процесс видимо нравится больше чем охота и все заканчивалось тем, что на экране не оставалось места, где бы не «размножались» объекты. Чуть позже выложу видео того как это выглядит.
Ну дык незачем делать этот процесс бесплатным
за деньги это было бы не этично:)
Хорошо, что в природе не всё этично, а то человечество бы (да и жизнь вообще) с такими «создателями» так и не появилась
Я имел ввиду и «охота» и «размножение» одновременно.
Добавил 4 пример, 70% вероятность размножения, 30% охоты. То есть если не перегрызут друг друга, то будет наследство.
а, сорри, не сразу понял ваш ответ, т.к. в транспорте читаю
А если генетический алгоритм им при размножении задать, определяющий фенотип, и способности, а потом оставить на несколько лет покрутиться на супер ЭВМ, то там потом и поговорить можно будет с кем нибудь?
Вспомнился рассказ Днепрова «Крабы идут по острову», как раз именно на эту тему
Это я к тому, что нет уверенности, что мы сами на такой ЭВМ не «крутимся»…
Теперь вспомнился «Тринадцатый этаж» :)

Хотел дополнить свой предыдущий комментарий, но уже поздно было, напишу тут. У Днепрова все рассказы с большим упором на технику, про инженеров. В «Крабы идут по острову» в военных целях разработали робота, который поедал металлы и делал копию себя, всегда не очень точную (со случайными отклонениями). И вот два человека высадились на пустом острове, предварительно закопали бруски из разных металлов как пищу для роботов. Выпустили похожего на краба маленького робота и стали ждать с расчётом на то, что роботы начнут войну, поедая друг друга, когда кончится весь металл. И в итоге отбора останется идеальный экземпляр.
интересная тактика, такое вполне можно добавить в модель и посмотреть, что из этого выйдет.
Похожая идея была в романе Д.Симмонса «Гиперион», в нем все разумные машины «развились» из подобных «одноклеточных»
Это можно сделать, достаточно «передать по наследству» конфигурацию сети, как раз об этом думал для следующей статьи.
Добавил пример с наследованием генов и мутацией.
Правильно ли я понял, что, фактически, все, для чего вы используете нейронную сеть — это, имея на входе набор расстояний до объекта, так подрыгать ложноножками, чтобы минимизировать (или максимизировать, в случае «угрозы») все эти расстояния?
Так и есть) У объектов ничего кроме глаз\ушей\носа и «ложноножек» нет:)
А как вы оцениваете эффективность принятого решения?
За успешное приближение к другому объекту увеличивается «счетчик силы», более сильные объекты могут пообедать более слабыми. Слабые погибают, сильные выживают. Другой оценки эффективности нет.
За успешное приближение

Что такое «успешное приближение»?

увеличивается «счетчик силы»

Он участвует в тренировке/оценке?

Слабые погибают, сильные выживают.

«выживаемость» как-то участвует в тренировке/оценке?
Приближение к другому объекту на очень маленькое расстояние,. «успешное», если при этом остался в живых.
«Счетчик силы» не участвует в тренировке, но косвенно влияет на решение, он нужен для того, чтобы оценить нужно ли приближаться к объекту или лучше от него убегать. Выживаемость она либо есть, либо ее нет (не выжил), в тренировке не участвует.
Приближение к другому объекту на очень маленькое расстояние,

Что такое «очень маленькое расстояние»?

Он не участвует в тренировке, но косвенно влияет на решение, он нужен для того, чтобы оценить нужно ли приближаться к объекту или лучше от него убегать.

Насколько я помню, у вас это решение напрямую принимается в коде if-ом, безо всякой сети.

Выживаемость она либо есть, либо ее нет (не выжил), в тренировке не участвует.

Тогда как же нейронная сеть понимает, что она успешно «убежала»?
Расстояние выбрано опытным путем, оно достаточно малое, чтобы случайно сблизиться было бы крайне сложно, в последней версии это расстояние равно 0.008, при «размере» выделенного пространства 1х1.
Насколько я помню, у вас это решение напрямую принимается в коде if-ом, безо всякой сети.

Верно, таким образом мы задаем сети цель, то есть то, что мы хотим получить. Задается это не в явно, а посредством передачи «шаблона» {0,0,0,0} — мы хотим чтобы на сенсорах были нули или шаблона {1,1,1,1} — на сенсорах единицы. Нельзя получить у сети решение не предоставив ей задачи.
Тогда как же нейронная сеть понимает, что она успешно «убежала»?

Она этого не знает, если она не убежала ее функционирование прекращается. Если же она смогла уйти это отразится на ее памяти, как это повлияет на саму сеть неизвестно. Как раз это и было интересно определить в первую очередь.
Расстояние выбрано опытным путем, оно достаточно малое, чтобы случайно сблизиться было бы крайне сложно, в последней версии это расстояние равно 0.008, при «размере» выделенного пространства 1х1.

Но как вы считаете это расстояние?

Если же она смогла уйти это отразится на ее памяти,

Каким образом?

Пока у меня создается ощущение, что «выживаемость» в вашем описании — это иллюзия. Вы оптимизируете строго один параметр (матрицу расстояний).
Но как вы считаете это расстояние?

<spoiler title="«Обычная» функция расчета расстояния, ничего особенного">
 double GetDist(double x1, double x2, double y1, double y2)
            {
                return Math.Sqrt(Math.Pow(x1 - x2, 2) + Math.Pow(y1 - y2, 2));
            }


Каким образом?

Объект все данные сенсоров, «положение» «ложноножек» в каждый ход, после производит повторное обучение сети.
Насчет выживаемости сказать трудно, с одной стороны поведение сети выглядит разумным, с другой стороны очевидно разумом там и не пахло, а значит так или иначе это просто оптимизация.
Я не ставил цели получить объект играющий в покер, было интересно проверить будут ли объекты «биться головой об стену» вести себя нерационально или же покажут признаки разумного поведения.
То есть внезапно, вы вводите в качестве оценки новую величину, которой раньше в системе не было?

Я не ставил цели получить объект играющий в покер, было интересно проверить будут ли объекты «биться головой об стену» вести себя нерационально или же покажут признаки разумного поведения.

Признаков разумного поведения они не покажут. Оптимизация параметров по заданному извне критерию — это вряд ли разум.
Поэтому я и уточнил «принимать решения, которые можно считать относительно разумными». Я не говорил что перед объектами не будет поставлена задача, если ее не ставить, им нечего будет делать и соответственно не получится за ними наблюдать.
Я прям совсем советую в качестве виртуального мира использовать unity. Я сем свою сеть, которую сейчас пишу, буду тестить на «выживание» именно там. Плюсы для вас, и для меня:
1) Готовая реализованная физика мира с правилами, настраиваемыми в широких диапазонах.
2) С# в качестве внутреннего языка.
3) Реализация множества готовых алгоритмов для виртуальности, например RayTracing
4) Хорошая и лёгкая визуализация всего происходящего в системе.
Согласен, цель этого исследования проверить в более «простых» условиях имеет ли смысл использовать нейронные сети для управления объектами. Дальше планировал как раз использовать полноценную среду и более сложные объекты.
В том то и фокус, что если бы знали Unity на уровне двухдневных курсов вам было бы проще использовать её, чем делать свою визуализацию со стеночками и точечками. Лёгкий старт можно получить в виде видеоуроков на ютубе. Так что как будете в следующий раз писать — вот вам хороший инструмент.
Согласен, с unity уже немного познакомился, там не намного сложней, но не проще рисования на bitmap:) У меня на отрисовку и запись в видео идет около 10 строк, из которых половина drawcircle. К тому же есть и другая проблема, вычисление 20 объектов с несколькими тысячами нейронов в сети (в каждом объекте) не такая тривиальная задача, поэтому «отрисовка» немного не в реальном времени, что намного красивее смотрится в видео, после генерации.
2) С# в качестве внутреннего языка.
А что, туда .NET 4.0 уже завезли?
Там дурацкий монгакомпилятор, который подтягивает библиотеки по ситуации. Не совсем то же самое, что из ВижуалСтудио, но в процессе разработки разница, по большому счёту не чувствуется, если вы не полезете байткод читать. Кроме того сейчас ВизуалСтудио стремительно интегрируется с Юнити, так что уже и нормальная отладка доступна, и скоро, я думаю, и полноценный компилятор и последний дотнет будут нативно.
Так дотнет завезли четвёртый или там всё ещё Mono 2.6 со всеми вытекающими?
Я ж говорю, что пока вытекающие, кажется. Хотя если свой считающий код писать, то дотнет не особо то упирается.
Ну и зачем такое счастье, если можно взять XNA/MonoGame и не иметь проблем с подключением библиотек и использованием свежих возможностей языка?
А зачем вам вообще нужны свежие возможности языка если вы занимаетесь не приделыванием интерфейсиков к базам данных, а научными расчётами? Со времён Фортран-77 в решение таких задач ничего принципиально не поменялось. И прочти все без исключения языковые навороты нового времени расчёт только замедляют.

И я, конечно, много чего в C# не использую, но из подключаемых библиотек в Unity проблемы до сих пор имел только с родной System.Linq которая не завелась на iOS-е.
А зачем вам вообще нужны свежие возможности языка если вы занимаетесь не приделыванием интерфейсиков к базам данных, а научными расчётами
В .NET 3.5 не было Task Parallel Library, ParallelLinq, BigInteger/Complex. В C# 3.0 не было необязательных параметров, ко/контрвариантности и разного рода сахара типа интерполяции строк, инициализаторов. Практически все библиотеки, включая используемый автором поста encog не поддерживают .NET 3.5. Этого достаточно или продолжать?
— Task Parallel Library — Можете указать научную библиотеку для которой именно TPL было бы необходимым условием? Это всё, конечно, удобно, но если вы делаете нейронную сеть со слегка небанальной архитектурой то паралелизацию вам всё равно придётся делать ручками. Потому что адский ад паралельных обращений к переменным, потому что небанальное понимание какие очереди рассчётов можно запускать после каких и потому, что накладные расходы библиотеки, скорее всего больше чем вес самой расчётной задачи, если у вас в потоках вычислений всего по несколько нейронов.
— ParallelLinq — По вполне очевидным причинам не может использоваться при написании нейронной сети, кроме как по приколу.
— BigInteger — Только для очень специфичных задач. Я в своё время написал обычную сеть с обратным распространением работающую полностью в целых числах, так мне long хватило ваще за глаза. И то это было сделано скорее по принципу, а не потому что нужно. Один раз участвовал в вычислении и распечатывании факториала 10000, но даже и там оно бы не пригодилось — мы считали сразу в десятичной системе, что бы не переводить потом из системы в систему число, которое в 64Кб памяти не помещается.
— Complex — Пффф. Все кому нужно было давно за 30 минут себе свой написали.
— C# 3.0 не было необязательных параметров — В монодевелопе совершенно замечательно работают и не пищат.
— ко/контрвариантности — Безусловно важная фича для построения красивой объектной архитектуры и исключения дублирования методов, но, блин, на кой она фиг в рассчётных задачах? Правильное ООП это не для этого случая хотя бы потому, что виртуальные методы дают дополнительные накладные расходы. asm, наверное чаще встречается.
— разного рода сахара типа интерполяции строк — Ну и на кой? Даже в анализе текста для машинного обучения и то конкатинация строк встречается только для формирования логов в консоль.
— инициализаторов — Вот это без балды полезная фича, хотя без неё можно прожить.

Этого достаточно или продолжать?
Можно не продолжать, и так понятно, что для вас все эти фичи важны как красивые примочки, но на кой они в данном случае вы ни на секунду не задумались, вам это не важно.

Единственное осмысленное возражение — то что библиотеки повадились хотеть 4.0 просто по умолчанию. Но если бы вы что-то своё писали подавляющее количество свежих вохможностей вам бы ни в пень не сдались.
библиотеки повадились хотеть 4.0
Они его «повадились» использовать по причине упрощения написания и поддержки кода.
в пень не сдались
С таким подходом можно вообще шарп не использовать, в нём же куча ненужного.
А во многих областях наук и не используют. В физике до сих пор половина лучших библиотек написана на Фортране 77. :)
Библиотекам уровень среды, очень часто ставится на один ниже последнего из соображений предельно далёких от упрощения написания и поддержки кода. Я по работе андроидные игрушки делаю, так мы тоже выпускаемся на версии на 1 ниже самой новой. Тут дело не в каком-то особо устарелом подходе. Просто ваши конкретные примеры при написании ядра библиотеки реально не только не нужны, но иногда и вредны.
Согласен, полноценный .net в unity не помешал бы. Как оказалось интегрировать в него encog задача такая уж простая, требуется полноценный 4 framework.
Как оказалось Encog весь утыкан ParallelLinq, так что видимо все таки может использоваться.
Вот сейчас реально заинтриговали. Надо слазить, посмотреть в исходный код. Может они его для сокращения записи в очень редко выполняющихся операциях используют. Сам я тоже таким грешил, пока не потребовалось оптимизировать.
Возможно, хотя к примеру в Compute она используется для параллельной обработки.
Ах, ностальгия! Четыре сенсора… четыре двигателя… как же давно это было *roll_eyes*… 2011 год. В общем, когда-то писал подобное, но только без нейронки, чистая эволюция. Летающие роботы. Почитать о сути исследования можно тут. Скачать программу-реализацию можно на моём сайте. Картинка:
image
Интересная модель получилась, залипал на кувыркающийся кубик минут 10) Можно было бы повторить с нейронной сетью, посмотреть что получится.
Как уже сказали, у вас решение принимается не с помощью нейросети, а напрямую в коде. Ради интереса убрал всю работу с нейросетью. Заменил блок принятия решения
Скрытый текст
                //thinking
                //если я тот кто ближе слабее попробовать съесть, если нет драпать
                if (nearlife!=null )
                {
                    if (nearlife.borncount > borncount)
                    {
                        double[][] SenseData = { new double[] { 0, 0, 0, 0 } };
                        trainingSet = new BasicMLDataSet(Input, SenseData);
                    }
                    else
                    {
                        double[][] SenseData = { new double[] { 1, 1, 1, 1 } };
                        trainingSet = new BasicMLDataSet(Input, SenseData);
                    }
                    IMLData output = network.Compute(trainingSet[0].Ideal);
                    if (output[0] > pL) { pL += 0.001; } else { pL -= 0.001; }
                    if (output[1] > pR) { pR += 0.001; } else { pR -= 0.001; }
                    if (output[2] > pB) { pB += 0.001; } else { pB -= 0.001; }
                    if (output[3] > pT) { pT += 0.001; } else { pT -= 0.001; }
                }


на этот
Скрытый текст
                //thinking
                //если я тот кто ближе слабее попробовать съесть, если нет драпать
                if (nearlife != null)
                {
                    double speedXDelta = Math.Abs(sB - sT); if (speedXDelta > 0.001) speedXDelta = 0.001;
                    double speedYDelta = Math.Abs(sB - sT); if (speedYDelta > 0.001) speedYDelta = 0.001;

                    if (nearlife.borncount > this.borncount)
                    {
                        // убегаем
                        // уменьшаем скорость на ближней стороне, увеличиваем на дальней

                        if (sT < sB) { pT -= speedYDelta; pB += speedYDelta; }
                        else if (sB < sT) { pB -= speedYDelta; pT += speedYDelta; }

                        if (sL < sR) { pL -= speedXDelta; pR += speedXDelta; }
                        else if (sR < sL) { pR -= speedXDelta; pL += speedXDelta; }
                    }
                    else
                    {
                        // догоняем
                        // увеличиваем скорость на ближней стороне, уменьшаем на дальней

                        if (sT < sB) { pT += speedYDelta; pB -= speedYDelta; }
                        else if (sB < sT) { pB += speedYDelta; pT -= speedYDelta; }

                        if (sL < sR) { pL += speedXDelta; pR -= speedXDelta; }
                        else if (sR < sL) { pR += speedXDelta; pL -= speedXDelta; }
                    }
                }



Ничего не изменилось.



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

кстати, у вас в коде много ошибок
Навскидку:

Метка ret1 находится до цикла, в некоторых случаях происходит зацикливание. Насколько я понял, из-за удаления элементов при параллельном доступе.
ret1:
...
foreach (Life life in World) {
...
goto ret1;
}


Неправильно переходит на другую сторону экрана, значение получается больше 1. Оно потом исправляется, но переход в эту сторону не работает.
if (x < 0)
{
    x = 1 - x;
}


Левый двигатель тянет вправо, в сторону увеличения x.
Нижний двигатель либо тянет вверх, либо неправильно определяется нижняя граница. Я считал в экранных координатах, где координата y вниз, у себя исправил границу.
x += pL - pR;
y += pB - pT;
...
sB += Math.Pow(GetDist(x, nearlife.x, y - 0.05, nearlife.y), 2) / 10;


Вы все правильно сказали, нейронная сеть в контексте «догнать»\«убежать» может быть легко заменена на пару строк кода. Но у нейронной сети даже в простейшей задаче есть преимущество, решение не зависит от числа «ног» у нашего объекта, к примеру если объект будет представлять из себя нечто сложнее чем шарик с 4 ногами, к примеру такое:
image
Написать формулы для управления всем этим добром будет на порядок сложнее.
Очевидно конечно, что правильное описанный алгоритм будет работать лучше чем абы как сформированная нейронная сеть. Если бы я выбирал самолет с автопилотом то точно не выбрал бы тот, которым управляет нейронная сеть, во всяком случае не такая как в примерах.
Ошибки в коде конечно есть, исправляю по мере их появления, этот проект является частью следующего и призван проверить возможности нейронной сети для управления объектами, конфигурация которых будет намного сложней.
Отдельно уточню, в коде не говорится напрямую какой ногой нужно шевелить для достижения результата, в коде говорится что «нужно приблизиться» и «нужно отдалиться», как именно это будет делаться (пошевелить ухом, двинуть ногой или чихнуть) мы не знаем и объекту не говорим, решение о том какой из доступных ей объектов задействовать для достижения цели принимает сеть.
Ну вообще-то говорится. Если первый(нулевой) элемент выхода сети больше, чем левый двигатель, то увеличить тягу левого двигателя. Это очень точно и очень конкретно. Это явно связывает первый элемент с левым двигателем. Вам так не кажется? Если нет, то почему?
А кто вам сказал что левый сенсор находится именно слева?) Суть как раз в том, что ничего такого мы сети не сообщили, она сама разобралась где у нее лево, где право и т.д. Потенциально, если у неё будет 472 сенсора со всех сторон и под разными углами и 243 двигателя, как попало натыканных по всей поверхности для нее не составит труда разобраться с тем какое влияние оказывает на нее каждый из них.
У меня немного другой взгляд на нейросети (и в частности на обучение с учителем), но возможно вы правы) Удачи в исследованиях
Sign up to leave a comment.

Articles