Данная статья продемонстрирует возможность легко написать свою нейронную сеть на языке Javа. Дабы не изобретать велосипед, возьмем уже хорошо проработанную библиотеку Fast Artificial Neural Network. Использование нейронных сетей в своих Java-проектах — реально. Часто можно услышать упреки в адрес Java касательно скорости выполнения. Хотя разница не так велика — подробно об этом можно узнать в публикации «Производительность C++ vs. Java vs. PHP vs. Python. Тест «в лоб»». Мы будем использовать обертку вокруг библиотеки FANN.
Необходимо написать систему, которая сможет принимать решения за персонажа, который может встретить одного или несколько врагов. Системе может быть известно:
Ответ должен быть в виде одного из действий:
Для обучения составим таблицу «уроков»:
Первое, что нужно сделать — собрать и установить libfann.
Затем скачать fannj и jna.
Сделаем файл, который будет содержать набор «уроков»:
Теперь обучим нашу ИНС и сохраним ее в файл:
ИНС состоит из слоев нейронов. Первый слой — это нейроны «рецепторы» или нейроны входных данных. Последний слой нейронов выходных данных. Все остальные — это скрытые слои. В нашем случае первый слой имеет 3 нейрона:
уровень здоровья (0.1-1.0);
наличие оружия (1-есть, 0-нету);
количество врагов.
Объект класса 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)
Remper
07.04.2015 13:37+7Всё хорошо, только не называйте, пожалуйста, обучающую выборку «уроками», всё-таки есть терминология и ей уже лет 50. Плюс соглашусь с afiskon: задача очень тривиальная.
Не знаю как там люди упрекают яву в производительности, но огромный кусок машинного обучения делается именно на яве, в том числе и знаменитый IBM Watson.
Обязательно продолжайте, нейронные сети — вещь очень интересная.
afiskon
Спасибо за интересную статью. Следует однако отметить, что в ней вы рассмотрели довольно простую задачу. Попробуйте, например, задачу распознавания образов, и все сразу станет намного интереснее. Плюс Fann насколько я понимаю не параллелится, а жаль, потому что обучение нейронных сетей можно существенно ускорить на многоядерных процессорах.
arsen_gl Автор
Спасибо. Обязательно попробую. После чего поделюсь результатами. FANN мне понравилась тем что ее очень легко использовать. Есть еще интересный проект OpenANN. Но пока руки не дошли попробовать ее вставить в java проект.
igor_suhorukov
Лет 6 назад использовал joone framework для распознавания капчи — java библиотека без нативного кода. У нее был простой api, много типов поддерживаемых типов сетей, визуальный редактор для конструирования и обучения искусственной нейронной сети. Но он давно не поддерживается.
Более новая и библиотека Encog, поддерживала в том числе работу на GPGPU
gurinderu
А чем закончилось все? Каков был процент распознавания?
igor_suhorukov
На тот момент в связи с глюкавостью сервиса, при перезапросе URL с капчей он перегенерировал картинку с теми же цифрами, но с другой деформацией. Благодаря этой оплошности разработчиков, я не помню чтобы у меня была хоть одна ошибка при распознавании из 15 разных картинок с одним и тем же фактическим содержимим капчи