Не могу разобраться с teach_php
1.
Валерий (14.04.2012 / 18:51)
Задача:
Есть 4 папки (0, 1, 2, 3), в которых фото разных людей. В 0 - фото плохого человека, в 1 - хороший1, 2 - хороший2, 3 - хороший3. Не получается обучить сеть, чтоб выдавала 000 на плохого, 100 на хор.1, 010 на хор.2 и 001 на хор.3. Не совсем понимаю принцип работы и логику нейросети.
Вот мой скрипт:
<?php
$j = 0;
$my_example = array();
for ( $i = 1; $i < 4; $i++ )
{
$l = $i;
$l--;
$index = array(0, 0, 0);
$index[$l] = 1;
$d = dir("teach/$i");
while($entry = $d->read())
{
if ( preg_match("/jpg/", $entry) )
{
$im = imagecreatefromjpeg("teach/$i/$entry");
$cur_array = array();
$cnt = 0;
for($y=0; $y<200; $y++)
{
for($x=0; $x < 200; $x++)
{
$rgb = imagecolorat($im, $x, $y) / 16777215;
$cur_array[$cnt] = $rgb;
$cnt++;
}
}
imagedestroy($im);
$my_example[$j] = array($cur_array, array($index));
$j++;
}
}
}
$ann = fann_create(array(40000, 200, 3), 1.0, 0.7);
if ( fann_train($ann, $my_example, 1000, 0.001, 100) == FALSE)
exit('Could not train $ann.');
fann_save($ann, "my3.ann");
?>
2.
Александр (15.04.2012 / 00:54)
<?php
$j = 0;
$my_example = array();
for ( $i = 1; $i < 4; $i++ )
{
$l = $i;
$l--;
$index = array(0, 0, 0);
$index[$l] = 1;
$d = dir("teach/$i");
while($entry = $d->read())
{
if ( preg_match("/jpg/", $entry) )
{
$im = imagecreatefromjpeg("teach/$i/$entry");
$cur_array = array();
$cnt = 0;
for($y=0; $y<200; $y++)
{
for($x=0; $x < 200; $x++)
{
$rgb = imagecolorat($im, $x, $y) / 16777215;
$cur_array[$cnt] = $rgb;
$cnt++;
}
}
imagedestroy($im);
$my_example[$j] = array($cur_array, array($index));
$j++;
}
}
}
$ann = fann_create(array(40000, 200, 3), 1.0, 0.7);
if ( fann_train($ann, $my_example, 1000, 0.001, 100) == FALSE)
exit('Could not train $ann.');
fann_save($ann, "my3.ann");
?>
Добавлено через 03:43 сек.
мб мало примеров? хочешь хороший результат - готовь много примеров, нет смысла учить много раз одним и тем же, эти скорее переучишь и будут проблемы с распознаванием.
p.s существует сборка под php 5.2.1 версии fann 2, на форуме fann'a можно отыскать.
Добавлено через 08:00 сек.
$rgb = imagecolorat($im, $x, $y) / 16777215; - это ты чб делаешь? попробуй сохранить их и посмотреть после такой обработки их вообще реально ли распознать. Вообще напиши подробнее, что выдаёт, примеры картинок которыми учишь.
3.
Николай (16.04.2012 / 06:35)
а можно в двух словах для чего это нужно?
4.
Валерий (17.04.2012 / 16:02)
Есть
такая статья. Я решил попробовать у себя дома, но при этом расширить функционал. По этому мануалу вроде как заработало, а вот мой обучающий скрипт мне кажется неправильно работает - не просто ошибки потом, а полностью одинаковый ответ при любых фотках на входе.
Картинки с обычной вебкамеры пока делаю, кропаю до 200*200. Качество вроде ничего.
Какое количество фото достаточно для обучения (понятно, что чем больше тем лучше
)?
Интересует
очень как же работает функция train_php и какая логика, т.е. обязательны ли только 2 папки, или можно к примеру 4, как у меня. И как она работает с массивом который создает, как он создается...
5.
Александр (17.04.2012 / 17:02)
4, лучше поискать другую статью.
как минимум сводить изображение к чб это бред, можно будет даже не быть похожем на этого человека, а просто подобрать освещение что бы нейросеть пустила, лучше было бы использовать фильтр gd оставляющий только контур предметов в чб. Автор зачем то загнал код в цикл вместо того чтобы просто увеличить скорость обучения. Автор не знает что $a[]=1; запишет элемент в конец массива. И вопрос чему он может научить. Способ не годится для распознавания не известных для сети фоток. в комментариях тоже кстати написано "2012-01-04 19:23:27 | pk
при использовании такого примитивного алгоритма сеть надлежащим образом работать не будет."
Добавлено через 01:20 сек.
При таком алгоритме сеть может пустить и утюг вместо человека=)
Добавлено через 09:47 сек.
одинаковый ответ при любых фотках на входе
потому что все фотки преобразуются скорее всего в просто чёрные или только белые.
6.
Александр (17.04.2012 / 17:15)
2 папки, или можно к примеру 4
можно.
7.
Валерий (17.04.2012 / 21:58)
Как бы так сказать... я в программировании в общем и в нейронных сетях в частности ***ок
. Но наткнулся на вышеуказанную статью в которой был описан достаточно нехитрый алгоритм распознавания. Вот я и решился сделать по статье. Заработало. Захотел чуть улучшить (с пхп кстати и нейронными сетями столкнулся впервые на практике), но дело не пошло. Тем не менее есть такое ощущение, что смогу заставить это работать
- мне главное понять принцип обучения и работу этой технологии.
Вот автор статьи на которую я ссылался делал по схеме: обрезать и перегнать в ч/б цвет и далее в цикле каждый пиксель определять насколько он максимально черный/белый со значением от 0 до 1. Все работает при достаточном к-ве материала и простой схеме свой/чужой.
По вашему совету попробую использовать вместо qrayscale - EDGEDETECT. Может быть вы знаете лучший метод для распознавания лиц, чем описанный? Я бы с удовольствием с ним ознакомился
. Работаю с тем, что нашел - более подходящего ничего пока не встретил.
Автор зачем то загнал код в цикл вместо того чтобы просто увеличить скорость обучения.
Не совсем понял, о каком именно цикле идет речь - мне по крайней мере все кажутся понятными: 1 цикл - проверка наличия фото в каждой папке, 2-й цикл - в нем вычисляется значение каждого пикселя (от 0 до 1 как уже говорилось), и заносится в соотв. элемент массива... Как увеличить скорость обучения за 20 мин не нашел.. буду искать, но скорость в обучении пока не главное.
Автор не знает что $a[]=1; запишет элемент в конец массива.
Это я недопонял про какой момент
потому что все фотки преобразуются скорее всего в просто чёрные или только белые.
Как так может быть?? Как я понимаю, они преобразуются в ч/б, вырезается лицо и потом каждый пиксель из 40000 проверяется, насколько черный и получает свое значение от 0 до 1.
8.
Александр (17.04.2012 / 22:23)
с циклом ошибся, всё верно.
каждый пиксель из 40000 проверяется, насколько черный и получает свое значение от 0 до 1.
после преобразования в чб теряется очень много информации, лучше напиши перед imagedestroy($im); такой код imagejpeg($im, rand(10000,999999).'.jpg'); будет ясно что происходит после преобразования.
http://rusnauka.narod.ru/lib/author/briluk_d_b/1/ вот и ответ как лучше сделать, сделай для каждого изображения разную яркость, потом каждое в чб, и сразу все в 1 массив и обучай. Ещё можно скачать 2 версию fann, там можно выбирать тип сети одной строчкой, мб некоторые сети дадут лучший результат, но алгоритм всё равно меняй.
9.
Валерий (19.04.2012 / 18:56)
Так, если я правильно понимаю, то после
$im = imagecreatefromjpeg("teach/$i/$entry"); я вставляю
imagejpeg($im, rand(10000,999999).'.jpg'); (не совсем понял, что тут происходит, вероятно произвольная яркость для картинки, которую мы запихнули в $im). цикл с разложением на пиксели вообще убрать? Теперь делаю ее ч/б и просто запихиваю в массив?
Я объясню, что мне не понятно: в примере, по которому я делал принцип как я уже говорил простой - разбить на пиксели, из каждого сделать число от 0 до 1 и запихнуть в свою ячейку массива. А если это исключить, то каким образом обработать картинку??
Статью по типам сетей почитал. Можно было бы попробовать сверточную сеть, или хопфилда+многослойную... Но вот как реализовать эти сети я пока затрудняюсь понять.. Кстати я даже не в курсе какая сеть используется в моем примере
(предполагаю, что сверточная).
10.
Александр (19.04.2012 / 19:38)
imagejpeg($im, rand(10000,999999).'.jpg'); сохраняет картинку в папку со случайным именем, что бы можно было посмотреть пригодна ли она после фильтров для обучения.
цикл с разложением на пиксели вообще убрать?
нет, просто с начало в цикле сделай один раз как в статье(просто в чб), потом увеличь яркость например на 20% и опять в чб, увеличь ещё на 20% и опять как в статье, соедини все результаты, при меньшей яркости будет больше 1 (серый стал 1(потеря полезной инфы)), потом например увеличил яркость получилось(тот серый цвет стал 0), теперь инфы потерялось меньше, вот зачем это надо. кстати а почему бы не отставит грации серого и переводить каждый цвет в двоичную систему, тогда проблемы как запихнуть картинку внутрь отпадают. (256 > 11111111 и в сеть) 256*200*200=10 240 000, многовато, лучше ещё уменьшить количество цветов (хотя тоже должно работать довольно быстро). Если так сделаешь то можно не менять тип сети, но куда лучше будет использовать предназначенную для этого нейросеть(лучше пожалуй сверточную).
Кстати я даже не в курсе какая сеть
У тебя скорее всего обычная однослойная нейросеть. Ещё пожалуй стоит поменять тип обучения
http://leenissen.dk/fann/fann_1_2_0/r1996.html
11.
Валерий (24.04.2012 / 11:19)
Так, сделал 2 скрипта. 1-й берет фотку из папки 0, 1 или 2 и копирует его в папку temp/0, 1, 2. Далее делает 13 копий с различной яркостью. В результате имею ~ 1000 фото в сумме по 3-м папкам.
<?php
for ( $i = 0; $i < 3; $i++ )
{
$d = dir("$i/");
while($entry = $d->read())
{
if ( preg_match("/jpg/", $entry) )
{
$image = "$i/$entry";
$dir = "/opt/work/new_way/temp";
$new_image = "$dir/$image";
if (!copy($image, $new_image)) {
echo "не удалось скопировать $file...\n";
}
chdir("$dir/$i");
$input_image = $new_image;
$l = -90;
for ($l; $l <= 150; $l = $l+20) {
$image = imagecreatefromjpeg($input_image);
//третий параметр устанавливает уровень яркости изображения.
imagefilter($image, IMG_FILTER_BRIGHTNESS, $l);
//imagefilter($image, IMG_FILTER_MEAN_REMOVAL);
//imagefilter($image, IMG_FILTER_CONTRAST, -25);
imagejpeg($image, rand(10000,999999).'.jpg', 100);
imagedestroy($image);
}
chdir("/opt/work/new_way/");
}
}
}
?>
12.
Валерий (24.04.2012 / 11:20)
Запускаю второй скрипт, который как обычно перебирает фотки с разложением на пиксели и запихивает в массив.
<?php
$j = 0;
$my_example = array();
for ( $i = 0; $i < 3; $i++ )
{
$index = array(0, 0, 0);
$l = $i;
$index[$l] = 1;
$d = dir("/opt/work/new_way/temp/$i");
while($entry = $d->read())
{
if ( preg_match("/jpg/", $entry) )
{
$im = imagecreatefromjpeg("/opt/work/new_way/temp/$i/$entry");
$cur_array = array();
$cnt = 0;
for($y=0; $y<200; $y++)
{
for($x=0; $x < 200; $x++)
{
$rgb = imagecolorat($im, $x, $y) / 16777215;
$cur_array[$cnt] = $rgb;
$cnt++;
}
}
imagedestroy($im);
$my_example[$j] = array($cur_array, array($index));
$j++;
}
}
}
$ann = fann_create(array(40000, 200, 3), 1.0, 0.7);
if ( fann_train($ann, $my_example, 1000, 0.001, 1000) == FALSE)
exit('Could not train $ann.');
fann_save($ann, "my.ann");
?>
И тут столкнулся с проблемой - после того как скрипт висит пару минут (всмысле запущен и чего-то делает) выдает следующее:
php teach.php
Убито
Уменьшил к-во фото до 100-150-ти - все работает. Сначала подумал, что может что-то с "железом" (компьютер староват, если честно (х-ки: проц Pentium(R) Dual CPU E2200 @ 2.20GHz, память 4Гб, система Ubuntu 11.10 x64, винт IDE 40Gb)), ЖД, например или память. Решил протестировать, сделал MHDD - все норм. Память не проверял, так как сейчас пришла мысль, что может дело в том, что превышается какое-то значение времени на выполнение операции при выполнении скрипта, или ограничевается выделение ресурсов... В общем сейчас хочу копнуть в эту сторону, а то не могу даже затестить то что сделал теперь
.
13.
Валерий (24.04.2012 / 11:45)
Вот заценил выделение ресурсов:
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1161 user 20 0 5160m 3.7g 1432 R 28 94.8 0:35.21 php
А вот как выглядит при обучении на 20-ти фото:
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1266 user 20 0 639m 380m 9480 R 100 9.6 1:05.10 php
Отличия: проц при малом к-ве фото загружен на 100% (1 ядро), память 10% (когда было чуть больше (около 100) фото - памяти до 30% выделялось). Теперь же проц на 80-100% загружен только первые секунд 10, пока память растет до 95%, после нагрузка падает до 20-30%. Постоянно растет параметр "VIRT", где-то когда он доходит до 6000+ выполнение скрипта и прерывается (если я правильно понимаю заканчивается и своп). Предполагаю 2 варианта решения: китайское и нормальное. Первое - сделать побольше своп (у меня 2Гб вроде, не помню). Ну а нормальное решение: это оптимизировать использование ресурсов (пока правда не особо представляю как это реализовать, т.к. с проблемой столкнулся впервые).
14.
Александр (24.04.2012 / 11:52)
попробуй в начале написать
set_time_limit(0);
ini_set('memory_limit','1G');
15.
Александр (24.04.2012 / 12:03)
для оптимизации процессора можно заменить preg_match("/jpg/", $entry) на strpos($entry, 'jpg')!==false т.к во вложеном цикле же находится. попробуй записать полученный массив сначала в file_put_contents('filename', serialize($my_example)); а потом в другом отдельном скрипте обучить из ($my_example = unserialize(file_get_contents())
16.
Валерий (24.04.2012 / 13:51)
Вставил/заменил:
set_time_limit(0);
ini_set('memory_limit','1G');
// if ( preg_match("/jpg/", $entry) )
if ( strpos($entry, 'jpg')!==false )
file_put_contents('filename', serialize($my_example));
if ( fann_train($ann, ($my_example = unserialize(file_get_contents('filename'))), 1000, 0.001, 100) == FALSE)
Результат:
От ограничения памяти пока пришлось отказаться - когда файл достигал 136 мегабайт выдавало следующее сообщение:
PHP Fatal error: Allowed memory size of 1073741824 bytes exhausted (tried to allocate 137971915 bytes) in /opt/work/new_way/teach.php on line 36
Строка 36
file_put_contents('filename', serialize($my_example));
Без ограничения памяти работает уже более получаса, но ее выделение растет! Думаю, когда файл дорастет до примерно 500 Мб память кончится, а работает так долго сейчас из-за того, что выполнение операции гораздо медленнее, так как постоянно идет загрузка этого файла массива в память и выгрузка.
17.
Александр (24.04.2012 / 14:04)
Там же вообще можно учить понемногу, "If fann_create is called with a sole string argument, it will attempt to load an ANN created with fann_save from the file at filename."(http://leenissen.dk/fann/fann_1_2_0/r2555.html ) если у fann_create первый параметр будет строкой, то она откроет файл сети после сохранения из fann_save. пожалуй самый нормальный вариант учить по пару десятков фоток за 1 раз.
18.
Валерий (24.04.2012 / 14:14)
Вроде как доучивать... Сейчас почитаю, попробую.
19.
Валерий (25.04.2012 / 16:56)
В общем оптимизировать работу с мегамассивом мне не удалось и я решил разбить обучающий скрипт на 2 скрипта. Первый будет обрабатывать все фото, загонять их в
my_example по сто штук и сохранять массив с сотней фоток в файлы именем filename"НОМЕРпоследнегоЭЛЕМЕНТАмассива". Нагрузка следующая: проц на 100% одно ядро, память 25-30% (1Gb-1,5Gb). время на почти 1000 фото - 3-4 минуты.
Получаю несколько файлов:
Скрытый контент: Для выполнения действия необходимо авторизоваться!
Вот такой скрипт:
cat get_array.php
<?
set_time_limit(0);
//ini_set('memory_limit','1G');
$j = 0;
$c = 0;
$my_example = array();
for ( $i = 0; $i < 3; $i++ )
{
$index = array(0, 0, 0);
$l = $i;
$index[$l] = 1;
$d = dir("/opt/work/new_way/temp/$i");
while($entry = $d->read())
{
if ( strpos($entry, 'jpg')!==false )
{
$im = imagecreatefromjpeg("/opt/work/new_way/temp/$i/$entry");
$cur_array = array();
$cnt = 0;
for($y=0; $y<200; $y++)
{
for($x=0; $x < 200; $x++)
{
$rgb = imagecolorat($im, $x, $y) / 16777215;
$cur_array[$cnt] = $rgb;
$cnt++;
}
}
imagedestroy($im);
$my_example[$j] = array($cur_array, array($index));
$c++;
if ( $c == 100)
{
file_put_contents("filename$j", serialize($my_example));
unset($my_example);
$c=0;
$j++;
}
else {$j++;}
}
}
}
$j--;
file_put_contents("filename$j", serialize($my_example));
unset($my_example);
?>
Второй скрипт будет обучать/дообучать сеть на основании этих файлов или же восстановленных из них массивов..... Или даже так! - я могу собрать 1 массив из этих файлов и использовать его для обучения. Нужно подумать, какой вариант лучше (учитывая, что в дообучение я пока еще не вникал
).
20.
Валерий (25.04.2012 / 19:58)
Набросал второй скрипт. Все ли я правильно понял в плане работы fann_train, fann_save ?
<?
set_time_limit(0);
//ini_set('memory_limit','1G');
$j = 1;
$my_example = array();
// Китайская переменная
$array1 = array('filename99', 'filename199', 'filename299', 'filename399', 'filename499', 'filename599', 'filename699', 'filename799', 'filename899', 'filename923');
$ann = fann_create(array(40000, 200, 3), 1.0, 0.7);
//if ( fann_train($ann, $my_example, 1000, 0.001, 1000) == FALSE)
if ( fann_train($ann, ($my_example = unserialize(file_get_contents('filename99'))), 1000, 0.001, 100) == FALSE)
exit('Could not train $ann.');
fann_save($ann, "my.ann");
unset($my_example);
while ( $j <= count ($array1))
{
$ann = fann_create("my.ann");
if ( fann_train($ann, ($my_example = unserialize(file_get_contents($array1[$j]))), 1000, 0.001, 100) == FALSE)
exit('Could not train $ann.');
fann_save($ann, "my.ann");
unset($my_example);
$j++;
}
?>
Запустил. Предположительно будет выполняться чуть более 100 минут (много времени занимает загрузка в массив данных из файлов filename).
В общем завтра посмотрю, что получилось.
21.
Александр (25.04.2012 / 20:58)
судя по коду фотки с разной яркостью обрабатываются как отдельные, надо вместе, либо соедини их в 1 фотку либо читай все одинаковые фото но с разной яркостью в 1 массив, если так сделаешь не забудь поправить 40000, умножив на количество фоток с яркостью.
Набросал второй скрипт. Все ли я правильно понял в плане работы fann_train, fann_save ?
работать будет.
и код можно проще написать, примерно так.
<?
set_time_limit(0);
//ini_set('memory_limit','1G');
//если переменные из папки то можно использовать glob("*.txt") он умеет искать по шаблону что то вроде
$array1 = glob('foto/filename*');//всё что начинается с filename
// Китайская переменная
//$array1 = array('filename99', 'filename199', 'filename299', 'filename399', 'filename499', 'filename599', 'filename699', 'filename799', 'filename899', 'filename923');
$ann = fann_create(array(40000, 200, 3), 1.0, 0.7);
//if ( fann_train($ann, $my_example, 1000, 0.001, 1000) == FALSE)
fann_train($ann, unserialize(file_get_contents('filename99')), 1000, 0.001, 100) or exit('Could not train $ann.');
fann_save($ann, "my.ann");
foreach($array1 as $val) //или с китайской переменной и так => ($c = count ($array1), $j = 1; $j <= $c; $j++){
$ann = fann_create("my.ann");
fann_train($ann, unserialize(file_get_contents( $val)), 1000, 0.001, 100) or exit('Could not train $ann.');
fann_save($ann, "my.ann");
}
?>
22.
Валерий (25.04.2012 / 22:27)
Ну пока дообучалась моя сеть, проверил. Не работает нормально: на все три типа фото из обучающего материала примерно одно и то же говорит:
php ran.php
Array
(
[0] => 1
[1] => 0
[2] => 0.022985305637121
)
Так что даже не знаю... идея в этот раз была такая: 3 папки, и сеть должна была понимать, на фото из какой папки входящее фото похоже, если ничего похожего нет, то грубо говоря 0 0 0. В исходном скрипте, по которому я начинал, было только 2 папки - свои и чужие. Не знаю как, но вроде как работало.. А тут ни в какую
. Может я все таки ошибочно понимаю логику этого всего?
Не совсем понял, для чего одинаковые фото, различающиеся по яркости запихивать в 1 массив.. И если так, то у меня в каждой папке получится примерно по 40 массивов. И еще не понял, зачем 40000 умножать на к-во фото, мне что, надо в my_array запихивать эти 3*40 массивов?
23.
Александр (25.04.2012 / 23:13)
Не совсем понял, для чего одинаковые фото, различающиеся по яркости запихивать в 1 массив.
если А - это фотка без обработки, а а1-а10 это фотки полученные после обработки А с яркостью от -100% до +100%, после обработки и чб, получились разные данные. если а1-а10 в разных массивах то сеть будет ставить вероятность для каждой не зная что это от одной фотки данные, из-за этого сильно снизится распознаваемость т.к при определённой яркости фотки разных людей станут одинаковыми(получается что то в виде if(a1 || a2 || a3) истина то всё - это этот человек), а если их объединить то таких ошибок будет намного меньше(тогда будет "и" а не "или"), а умножать 40000 надо будет если запихнешь а1-а10 в массив, пикселей то увеличится, вот и умножить не забудь.
Добавлено через 01:02 сек.
собственно наверняка из-за этого и не работает.
Добавлено через 06:46 сек.
и ещё некоторые вещи подбираются экспериментальным путём, тут $ann = fann_create(array(40000, 200, 3), 1.0, 0.7); вместо 200 попробуй больше(раз в 10) поставить, будет хуже меньше. тут , 1000, 0.001, 100) вместо 0.001(попробуй сначала 0.01 и 0.0001) тоже попробуй поэкспериментировать, и количество фоток с яркостью лучше не больше 10 делай сначала, если будет плохо работать, тоже поэкспериментируй.
24.
Валерий (26.04.2012 / 00:43)
Мысль понял. Я правда думал, что так как массив двумерный, то как раз благодаря второму элементу сеть и понимала бы, к какой папке относится данный элемент (я про array($index)). Буду пробовать.
URL:
https://visavi.net/topics/31269