Данная статья продемонстрирует возможность легко написать свою нейронную сеть на языке Javа. Дабы не изобретать велосипед, возьмем уже хорошо проработанную библиотеку Fast Artificial Neural Network. Использование нейронных сетей в своих Java-проектах — реально. Часто можно услышать упреки в адрес Java касательно скорости выполнения. Хотя разница не так велика — подробно об этом можно узнать в публикации «Производительность C++ vs. Java vs. PHP vs. Python. Тест «в лоб»». Мы будем использовать обертку вокруг библиотеки FANN.

Задача


Необходимо написать систему, которая сможет принимать решения за персонажа, который может встретить одного или несколько врагов. Системе может быть известно:
  • здоровье персонажа в процентах;
  • наличие пистолета;
  • количество врагов.

Ответ должен быть в виде одного из действий:
  • атаковать;
  • бежать;
  • прятаться (для внезапной атаки);
  • ничего не делать.

Для обучения составим таблицу «уроков»:
Здоровье пистолет Враги Действие
50% 1 1 Атаковать
90% 1 2 Атаковать
80% 0 1 Атаковать
30% 1 1 Прятаться
60% 1 2 Прятаться
40% 0 1 Прятаться
90% 1 7 Бежать
60% 1 4 Бежать
10% 0 1 Бежать
60% 1 0 Ничего
100% 0 0 Ничего

Подготовка


Первое, что нужно сделать — собрать и установить libfann.
Затем скачать fannj и jna.

Сделаем файл, который будет содержать набор «уроков»:

11 3 4
0.5 1 1
1 0 0 0
0.9 1 2
1 0 0 0
0.8 0 1
1 0 0 0
0.3 1 1
0 1 0 0
0.6 1 2
0 1 0 0
0.4 0 1
0 1 0 0
0.9 1 7
0 0 1 0
0.5 1 4
0 0 1 0
0.1 0 1
0 0 1 0
0.6 1 0
0 0 0 1
1.0 0 0
0 0 0 1

Теперь обучим нашу ИНС и сохраним ее в файл:

   public static void main(String[] args) {
        //Для сборки новой ИНС необходимо создасть список слоев
        List<Layer> layerList = new ArrayList<Layer>();
        layerList.add(Layer.create(3, ActivationFunction.FANN_SIGMOID_SYMMETRIC, 0.01f));
        layerList.add(Layer.create(16, ActivationFunction.FANN_SIGMOID_SYMMETRIC, 0.01f));
        layerList.add(Layer.create(4, ActivationFunction.FANN_SIGMOID_SYMMETRIC, 0.01f));
        Fann fann = new Fann(layerList);
        //Создаем тренера и определяем алгоритм обучения
        Trainer trainer = new Trainer(fann);
        trainer.setTrainingAlgorithm(TrainingAlgorithm.FANN_TRAIN_RPROP);
        /* Проведем обучение взяв уроки из файла, с максимальным колличеством
           циклов 100000, показывая отчет каждую 100ю итерацию и добиваемся
        ошибки меньше 0.0001 */
        trainer.train(new File("train.data").getAbsolutePath(), 100000, 100, 0.0001f);
        fann.save("ann");
    }

Пояснение


Layer


ИНС состоит из слоев нейронов. Первый слой — это нейроны «рецепторы» или нейроны входных данных. Последний слой нейронов выходных данных. Все остальные — это скрытые слои. В нашем случае первый слой имеет 3 нейрона:

уровень здоровья (0.1-1.0);
наличие оружия (1-есть, 0-нету);
количество врагов.

Fann


Объект класса Fann это и есть нейронная сеть, которая создается на основе созданных ранее слоев.

Trainer


Объект класса тренер инкапсулирует алгоритмы обучения нейронной сети переданной при создании тренера. После обучения не забываем сохранить ее в файл.

Проверка результатов


Для проверки нашего обучения воспользуемся следующим кодом:

   public static void main(String[] args) {
        Fann fann = new Fann("ann");
        float[][] tests = {
                {1.0f, 0, 1},
                {0.9f, 1, 3},
                {0.3f, 0, 8},
                {1, 1, 8},
                {0.1f, 0, 0},
        };
        for (float[] test:tests){
            System.out.println(getAction(fann.run(test)));
        }
    }
    
    private static String getAction(float[] out){
        int i = 0;
        for (int j = 1; j < 4; j++) {
            if(out[i]<out[j]){
                i = j;
            }
        }
        switch (i){
            case 0:return "атаковать";
            case 1:return "прятаться";
            case 2:return "бежать";
            case 3:return "ничего не делать";
        }
        return "";
    }

У меня получились такие результаты:
Здоровье пистолет Враги Действие
100% Нет 1 Атаковать
90% Есть 3 Прятаться
30% нет 8 Бежать
100% Есть 8 Бежать
10% Нет 0 Ничего не делать

Буду рад услышать конструктивную критику.

Комментарии (8)


  1. afiskon
    07.04.2015 11:23
    +3

    Спасибо за интересную статью. Следует однако отметить, что в ней вы рассмотрели довольно простую задачу. Попробуйте, например, задачу распознавания образов, и все сразу станет намного интереснее. Плюс Fann насколько я понимаю не параллелится, а жаль, потому что обучение нейронных сетей можно существенно ускорить на многоядерных процессорах.


    1. arsen_gl Автор
      07.04.2015 14:33

      Спасибо. Обязательно попробую. После чего поделюсь результатами. FANN мне понравилась тем что ее очень легко использовать. Есть еще интересный проект OpenANN. Но пока руки не дошли попробовать ее вставить в java проект.


      1. igor_suhorukov
        07.04.2015 22:25
        +1

        Лет 6 назад использовал joone framework для распознавания капчи — java библиотека без нативного кода. У нее был простой api, много типов поддерживаемых типов сетей, визуальный редактор для конструирования и обучения искусственной нейронной сети. Но он давно не поддерживается.
        Более новая и библиотека Encog, поддерживала в том числе работу на GPGPU


        1. gurinderu
          08.04.2015 10:34

          А чем закончилось все? Каков был процент распознавания?


          1. igor_suhorukov
            08.04.2015 21:19

            На тот момент в связи с глюкавостью сервиса, при перезапросе URL с капчей он перегенерировал картинку с теми же цифрами, но с другой деформацией. Благодаря этой оплошности разработчиков, я не помню чтобы у меня была хоть одна ошибка при распознавании из 15 разных картинок с одним и тем же фактическим содержимим капчи


  1. SONce
    07.04.2015 13:30
    +3

    не совсем понял зачем тут нейронная сеть для элементарной задачи. Уверен что для данной задачей можно обойтись пучком if-ов


    1. arsen_gl Автор
      07.04.2015 14:26

      Это простой пример для демонстрации возможностей ИНН и библиотеки.


  1. Remper
    07.04.2015 13:37
    +7

    Всё хорошо, только не называйте, пожалуйста, обучающую выборку «уроками», всё-таки есть терминология и ей уже лет 50. Плюс соглашусь с afiskon: задача очень тривиальная.
    Не знаю как там люди упрекают яву в производительности, но огромный кусок машинного обучения делается именно на яве, в том числе и знаменитый IBM Watson.
    Обязательно продолжайте, нейронные сети — вещь очень интересная.