Пользователь
0,0
рейтинг
15 ноября 2012 в 13:07

Разработка → Построение нейронных сетей в php используя FANN, пример реализации из песочницы

PHP*
Передо мной предстала задача анализа большого количества информации и выявления закономерностей. И первое, что пришло в голову — построить математическую модель с помощью нейронной сети.

Поскольку данные для анализа формируются в php и мне этот язык сейчас ближе всего, то искалась библиотека с интерфейсом для php. В связи с этим мне порекомендовали FANN (Fast Artificial Neural Network) — открытое программное обеспечение для построения сетей. У этого решения есть апи для 15 языков, так что почти каждый сможет выбрать что-то для себя.

Пример. Распознавание языка текста на странице

Для примера возьмем задачу легкую, но недалекую от нашей реальности и от серьезных задач. Допустим есть 1000 документов, на 3-х разных языках. Пусть это будут французский, английский и польский. Наша задача научить нейронную сеть распознавать язык документа. Для этого мы используем самый простой частотный механизм. Но тем не менее его результаты неплохи. Его суть в том, что у каждого языка с разной частотой в тексте встречаются одни и те же символы. Мы подготавливаем 3 больших куска текста для каждого из языков (английский, французкий, польский), посчитаем для каждого символа частоты. Эти данные мы передадим в нейронную сеть, с указанием какой набор частот принадлежит каждому из языков. Дальше нейронная сеть все сделает сама.

Начнем с установки FANN

Пример, установки привожу для Ubuntu.

1) Нужно установить пакеты libfann1 и libfann1-dev
apt-get install libfann* 


2) Добавить поддержку fann в php
У меня стоит Apache и установлен модуль php5-dev, поэтому я делаю так

# wget http://pecl.php.net/get/fann
# tar xvfz  fann
# cd fann-0.1.1
# phpize
# ./configure
# make


Если при компиляции появиться ошибки и среди них будет вот такая

fann.c:393: error: ‘zif_fannOO___set’ undeclared (first use in this function)

то следует отредактировать файл php_fann.h и за комментировать строчку 28 #define PHP_FANN_OO 1
После этого заново скомпилировать.

В итоге у нас генерируются модули которые нужно подключить к php
sudo cp -R ./modules/* /usr/lib/php5/20090626+lfs/


И в php.ini дописать
extension=fann.so


Перегрузили апач и проверили что все ок
php -m | grep fann


Решение задачи

Для этого нужно выполнить 2 шага:
1) Обучить сеть (первый листинг)
2) И использовать готовую модель для классификации (второй листинг)

Приведу пример для первого этапа и сразу укажу ссылку на документацию

Код я максимально снабдил комментариями, что бы было понятно что к чему и не разбирать его отдельно.

Файл train.php
<?php

/*
 * Задаем параметры сети. 256 - это количество входов, оно должно равняться количеству ваших параметров,
 * По хорошему в этом примере должно быть намного меньне, равно количесству букв в алфавитах.
 * 128 - это количество нейронов в промежуточном слое. Здесь нуужно экспериментальным путем подбирать это число.
 * 3 это количество выходящих сигналов. По скольку у нас 3 языка, то для каждого будет возвращена вероятность
 * 1.0 - connection_rate - его лучше не менять
 * 0.7 - learning_rate - описано здесь хорошо http://www.basegroup.ru/glossary/definitions/learning_rate/
 * */
$ann = fann_create(array(256, 128, 3), 1.0, 0.7);

/*
 * Первый параметр - указатель на нашу сеть, второй - обучающие данные.
 * Мы загружаем 3 порции данных.Каждая порция состоит их входящих показателей и эталонных результирующих.
 * В нем мы сообщаем, что при таких показателях, как мы сейчас передаем, нужно весь вес
 * отдавать на первы нейрон (array(1, 0, 0) // Outputs). при загрузке других типов данный мы смещаем вес на другой нейрон
 * generate_frequencies - просто расчитывает частоты.
 *
 * Последние 3 параметра это
 * - максимальное кол-во итераций
 * - максимальное кол-во ошибок
 * - промежуток между выводами информации 
 * 
 * В файлах en.txt, fr.txt, pl.txt хранится текс размером где-то в 10000 символов для конкретного языка
 * */
fann_train($ann,
    array(
        array(
            generate_frequencies(file_get_contents("en.txt")), // Inputs
            array(1, 0, 0) // Outputs
        ),
        array(
            generate_frequencies(file_get_contents("fr.txt")), // Inputs
            array(0, 1, 0) // Outputs
        ),
        array(
            generate_frequencies(file_get_contents("pl.txt")), // Inputs
            array(0, 0, 1) // Outputs
        ),
    ),
    100000,
    0.00001,
    1000
);

/*
 * Сохранить нашу модель в файл. в дальнейшем ее можно использовать для класификации
 * */
fann_save($ann,"classify.txt");


/*
 * Функция расчета частот
 * */
function generate_frequencies($text){
    // Удалим все кроме букв
    $text = preg_replace("/[^\p{L}]/iu", "", strtolower($text));

    // Найдем параметры для расчета частоты
    $total = strlen($text);
    $data = count_chars($text);

    // Ну и сам расчет
    array_walk($data, function (&$item, $key, $total){
        $item = round($item/$total, 3);
    }, $total);

    return array_values($data);
}

?>


В коде выше мы только сгенерили модель. А теперь проверим ее в деле, код ниже анализирует текст и выдает оценку принадлежности к тому или иному языку.

Файл run.php
<?php

/*
 * Загружаем модель из файла. Эту модель мы создали на предыдущем шаге.
 * */
$ann = fann_create("classify.txt");


/*
 * Ниже я в нашу сеть передаю 3 текста на разных языках
 * Смотрим результат
 * */

$output = fann_run($ann, generate_frequencies("ANN are slowly adjusted so as to produce the same output as in
            the examples. The hope is that when the ANN is shown a new
            X-ray images containing healthy tissues"));

var_dump($output);

$output = fann_run($ann, generate_frequencies("Voyons, Monsieur, absolument pas, les camions d’aujourd’hui ne se traînent pas, bien au contraire. Il leur arrive même de pousser les voitures. Non, croyez moi, ce qu’il vous faut, c’est un camion !
     - Vous croyez ? Si vous le dites. Est-ce que je pourrais l’avoir en rouge ?
     - Bien entendu cher Monsieur,vos désirs sont des ordres, vous l’aurez dans quinze jours clé en main. Et la maison sera heureuse de vous offrir le porte-clé. Si vous payez comptant. Cela va sans dire, ajouta Monsieur Filou.
     - Ah, si ce "));

var_dump($output);

$output = fann_run($ann, generate_frequencies("tworząc dzieło literackie, pracuje na języku. To właśnie język stanowi tworzywo, dzięki któremu powstaje tekst. Język literacki ( lub inaczej artystyczny) powstaje poprzez wybór odpowiednich środków i przy wykorzystaniu odpowiednich zabiegów technicznych.
            Kompozycja - jest to układ elementów treściowych i formalnych dzieła dokonanych według określonych zasad konstrukcyjnych.
            Kształtowanie tworzywa dzieła literackiego jest procesem skomplikowanym i przebiegającym na wielu poziomach.
            Składa się na nie:"));

var_dump($output);

?>


Результат

Наша модель сгенерировала следующие ответы по текстам.
В первом случае модель решила что ей на вход передали английский язык (98%) и она права

array(3) {
  [0]=>
  float(0.98745632171631)
  [1]=>
  float(0.0094089629128575)
  [2]=>
  float(0)
}


Во втором тексте она приняла решение в пользу французского и снова оказалась права

array(3) {
  [0]=>
  float(0)
  [1]=>
  float(0.99334162473679)
  [2]=>
  float(0)
}


Третий текст она тоже правильно распознала, как польский

array(3) {
  [0]=>
  float(0.015697015449405)
  [1]=>
  float(0)
  [2]=>
  float(1)
}


Некоторые пользователи жалуются что нейронные сети выдают вероятности, а не конкретный ответ. Для тех кто в танке добавлю, что в нашем мире все основано на вероятностях. За правильный ответ нужно считать тот который верен хотя бы на 90%, если меньше то сеть нужно до обучать, что бы улучшить классификацию.

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

Перейти на сайт FANN
Сергей @rechik
карма
11,0
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Разработка

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

  • +2
    >У меня стоит Apache и установлен модуль php5-dev, поэтому я делаю так
    а через инсталяху pecl не получится поставить из-за описанной выше ошибки в коде?

    И ещё есть вопрос: не подскажите какие виды нейронных сетей можно обучать непрерывно, а не по выборке?
    • 0
      Сети Кохонена.
      • 0
        спасибо! Похоже самоорганизующиеся сети Кохонена близко к тому, что нужно.

        Правда, не совсем понятно как проверять результат. Задача идентифицировать текстовый спам и «проблемные материалы» (например, не тот раздел) попадающие на ресурс — связи могут быть типа «заглавие содержит или не содержит слова такие-то, такие-то, текст такие слова, у пользователя имя содержит такие-то символы, а подано в таком-то регионе и в такой-то раздел». Вычислить все случаи и закономерности трудно, но при этом глянув на поданный материал я понимаю, что это нужно удалить. Поэтому пришла мысль обучить алгоритм путем постепенно добавления в него плохих (и плюс хороших материалов, если нужно) и смотреть правильно ли он распознает. Ну и по ходу добавлять проблемные материалы, которые появляются в ходе работы.
    • +1
      При попытке установить через pecl другая ошибка была и я не нашел ее решения
      Через pecl его можно установить так

      sudo pecl install channel://pecl.php.net/fann-0.1.1
      


      Вот ошибка кому интересно

      # 
      
      downloading fann-0.1.1.tgz ...
      Starting to download fann-0.1.1.tgz (9,509 bytes)
      .....done: 9,509 bytes
      3 source files, building
      running: phpize
      Cannot find config.m4.
      Make sure that you run '/usr/bin/phpize' in the top level source directory of the module
      
      ERROR: `phpize' failed
      
      
  • –1
    Извиняюсь, что не в тему, но вот конкретно эту самую задачу я бы решал гораздо проще, а именно по присутствию/отсутствию типичной для языка диакритики.

    Если же таковой нет, тогда частотный анализ незаменим.
    • 0
      В русском тексте могут быть, например, английские слова и как тогда? Считать частоты. Поэтому, я думаю, наличие/присутствие символов само по себе не годиться.
  • 0
    У меня проблема и видимо из-за ошибки компиляции, гугл молчит не подскажете в чем дело?

    /usr/sbin/apache2: symbol lookup error: /usr/lib/php5/20090626+lfs/fann.so: undefined symbol: fann_create_array

    Debian 6 php 5.3 apache 2.2
    • 0
      У тебя вроде как с модулем fann.so проблема. Скомпилируй заново модуль, да так что бы без ошибок в процессе.
      • 0
        переустановил сам fann дважды и трижды пересобрал модуль php одно и то-же все собирается без ошибок
        на

        fann_create()

        ругается что не хватает параметров, на

        $ann = fann_create(array(256, 128, 3), 1.0, 0.7);

        падает и пишет в error.log apache ту ошибку
  • –1
    Что-то половина статьи мне напоминает это :)
    • +2
      только тут чище и с примером и нас избавили от большого кол-ва вопросов собрав все в одном месте.
  • НЛО прилетело и опубликовало эту надпись здесь
    • 0
      У меня. Собственно все описанные действие в статье проводились в Ubuntu 10.04. Плюс php 5.3.
    • +1
      А что не получается? Какие ошибки выдает?
      • НЛО прилетело и опубликовало эту надпись здесь
        • +1
          У меня такая-же ерунда
        • 0
          Какая версия php, не 5.4? А то в этой версии есть такой баг bugs.php.net/bug.php?id=61479
  • 0
    Ранее тоже стояла задача для определения языка.

    Первая версия была очень простая, аналогично Вашей: используя каждые алфавиты, вычислять количество символов принадлежащих к определенному алфавиту, и у кого будет больше, тот и победитель.
    На практике эта система хорошо работала на «до 5» языках, в которых нету пересечений. Пересечений, я имею ввиду пересечений символов в алфавитах. К примеру, если посмотреть на украинский и русский языки. Разногласия в алфавитах очень маленькие. И таких алфавитов очень много (если взять европу, то там вообще почти все такие, которые используют в основном английский алфавит + некоторые свои дополнительные символы). Как пример (очень хорошо помню), это краткие фразы «привет Вася и Петя» определялись как белорусский и русский.

    Далее, когда поняли, что по частоте букв будет не очень то хорошо, пришли к другому решению. А что если загнать все слова с каждого словаря в конечный автомат? В результате, мы имели наборы множества слов для каждого отдельного языка. Точность определения кратких словосочетаний была намного выше да и текстов с большой длинной тоже. Но, есть очень большой минус для такой системы: очень много места занимают все эти словари + обработка.

    В итоге, решили использовать два подхода одновременно, но при этом, комбинировать. Если текущая буква есть в алфавите, то давать более высокий приоритет (сразу даст выше приоритет для языка, в котором есть «уникальный» буквы). А далее прогонять по словарю, и давать за каждое слово более низкий приоритет, так как слова могут встречаться.

    P.S. Пиарюсь:
    Паралельно со все этой задачей, запили пакет github.com/ZhukV/LanguageDetector
    Проверяли на прогоне текста приложений с Apple iTunes для одного из наших проектов. Точность была очень высока.

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.