Пролог и нейронные сети(Prolog
and Neural Network).
Попробуем сравнить Пролог – язык использующий логику и нейронные сети. Интерес заключается в том, что пролог, сам по себе создавался как язык максимально отражающий суть искусственного интеллекта. Можно также сказать, что программирование на прологе – нейропрограммирование. Нейронные сети – дальнейший этап развития ИИ. Интересно посмотреть, в чем отличия и сходства этих подходов.
Для этого рассмотрим простой пример классификации или распознавания.
Примечание – для данного примера используется SWI – Prolog. Для реализации в виде нейронной сети – Matlab.
1. Пролог(Prolog).
Пусть мы хотим распознать животных – bear (Медведь), elephant (Слон), cat (Кот). Эти животные представляют из себя некоторое множество.
Распознавание – попытка разбить множество на классы по некоторым признакам.
Что их отличает в первую очередь? Если Вы задумаетесь, то человеческий мозг вначале пытается разбить «образы» по размеру. Действительно, что вы обычно говорите о малознакомом предмете?
«….это небольшого размера…. », «…. он большой …» и т.д.
Поэтому разобьем множество на два класса большие и маленькие. Теперь мы можем точно определить, что увиденное нами животное (из имеющегося множества) – кот. Но не сможем определить кто слон, а кто медведь – они оба большие. Подобное разбиение записывается с помощью фактов, или мы сами вручную, аналитически разбиваем множество на классы.
big(bear).
big(elephant).
small(cat).
В нейросетях, как будет показано далее это происходит иначе.
Так как разделение множества на два класса не помогло нам опознать всех животных, продолжим разбиение на классы. Пусть мы смотрим на животных издалека – то есть пытаемся распознать малознакомые предметы. На первом этапе человеческий мозг выделяет наиболее общие признаки. Поэтому «смотреть издалека» - точная аналогия. Итак, что помимо размера, мы можем увидеть издалека? Очевидно цвет. Издалека мы не увидим особенностей некоторого предмета.
Пусть в нашем случае медведь бурый, кот черный, ну а слоны все серые. Дополнительно вводим еще три факта – класса.
brown(bear).
black(cat).
grey(elephant).
Как видно из рис. 1 множество big включает множество brown.
То есть из того что brown, следует, что big.
Но так же из того что.
И это никак не поможет нам разобраться в животных.
Рассмотрим черного кота.
Так как «смотрим издалека», то бурый и черный будут малоотличимы, но они будут темнее серого.
Отсюда следует некоторый класс «темнее» или просто темный.
Который будет представлять
объединение множеств
Или – «для того чтобы быть темным достаточно быть бурым или черным».
Для пролога этот факт записывается в виде.
dark(Z):-black(Z). % из того что черный следует, что темный
dark(Z):-brown(Z). % из того что бурый следует, что темный
Полный код пролог программы.
big(bear). % задание фактов или классов
big(elephant).
small(cat).
brown(bear).
black(cat).
grey(elephant).
dark(Z):-black(Z). % из того что черный следует, что темный
dark(Z):-brown(Z). % из того что бурый следует, что темный
Рис. 1.
Наше множество разбито на четыре класса.
Зададим вопрос.
Ответом будет – bear.
Проанализируем вопрос.
«темный и большой».
Операция and означает, что множества пересекаются, т.е. bear принадлежит обоим множествам.
Или.
Как видно из рисунка 1, в множество истинности данного высказывания попадает только медведь(bear). Конечно больших (относительно) и темных (относительно) животных много, и для их распознавания потребуется дополнительная классификация. Данный пример позволяет хорошо понять как работает мозг. Или принципы классификации.
Необходимо заметить, что в данном случае опущен один наиважнейший момент - обучение. Наша сеть уже знает, кто к какому классу принадлежит, потому что классификацию мы произвели сами. Прологу осталось выполнить процедуру бектрекинга - просто выбрать элементы отвечающие условию.
рис 2.
Следует сразу заметить, что в нейросети классы создает сама сеть в процессе обучения. Аналитическая задача сводится к правильному построению сети.
Рассмотрим наше множество.
Как видно из рис. 1., пустым у нас оказалось множество маленьких и не темных.
Введем новый элемент в множество - пусть это будет мышь. Маленькая и белая..
Окончательный вид программы.
big(bear).
big(elephant).
small(cat).
small(mouse).
brown(bear).
black(cat).
grey(elephant).
white(mouse).
dark(Z):-black(Z). % из того что черный следует, что темный
dark(Z):-brown(Z). % из того что бурый следует, что темный
not_dark(Z):-grey(Z). % из того что серый следует, что не темный
not_dark(Z):-white(Z). % из того что серый следует, что не темный
Зададим вопрос.
С точки зрения нейросети - "вопрос", сигналы поступающие на вход. Ответ - выход сети.
Основная сложность при логическом программировании в стиле Пролог, является аналитическое задание классов. Это имеет и плюсы и минусы. Если множество слишком велико, то подобный подход становится сложным или невыполнимым.
Но для небольших конечных множеств (комбинаторика - теория конечных множеств), такой подход имеет значительные преимущества. Если мы решаем комбинаторную задачу, то проще, а часто единственно возможно использовать такой подход. Спроектировать и обучить сеть или крайне сложно или невозможно.
Но верно и обратное - когда мы работаем с неограниченным множеством, аналитическое задание классов либо малоэффективно либо также невозможно.
2. Нейронные сети (Neural Network).
Придется расстаться с Прологом и перейти к самой мощной среде для технических расчетов и моделирования - Matlab.
Для наших целей идеально подходит линейная сеть, с функцией активации hardlim.
Подобная сеть представляет собой систему линейных уравнений (возможно одно уравнение), которая ограничена либо 0 либо 1.
Алгоритм обучения основан на минимизации среднеквадратической ошибки.
На первом шаге нам необходимо создать сеть.
Но архитектура сети напрямую зависит от множества. Пусть у нас те же множества. Только обозначим животных и признаки числовыми значениями.
[bear [big brown]] = [1 1 1].
[elephant [big grey]] - [2 1 0]
[cat [small black]] - [3 0 1]
[mouse [small white]] - [4 0 0]
Как видим, нумерацию животных можно опустить, их вполне описывают соответствующие признаки (в данном случае мы приняли черный = бурому =1, белый = серому = 0). Входное множество примет вид.
P=[1 1 0 0;
1 0 1 0];
Выходное (целевое) множество будет аналогичным.
Посмотрим как это выглядит на графике.
Соответствующий код.
P=[1 1 0 0;
1 0 1 0];
T= [1 1 0 0;
1 0 1 0];
plotpv(P,T);
text(1.1,1,'bear')
text(1.1,0,'elephant')
text(0.1,1,'cat')
text(0.1,0,'mouse')
Теперь создадим сеть которая имеет два нейрона - из количество в данном случае определяется множеством.
И адаптируем ее к данному множеству.
net = newp([0
1;0 1],2);
net.adaptParam.passes = 10;
net = adapt(net,P,T);
plotpc(net.IW{1},net.b{1});
Посмотрим на результат.
Как видим, множество успешно разбито на классы, и для этого понадобилось всего 10 "проходов".
Теперь зададим сети вопрос - относительно маленький и относительно белый.
Похож на мышь - относится к классу относительно маленьких и белых. Соответствующий "вопрос" к сети.
p = [0.1; 0.2]; %
a = sim(net,p); % получаем отклик сети.
Очень просто и гораздо эффективнее. Но у вас возникнет вопрос - кто это? Ответ - похож на мышь.
Это ограничение нашей сети - она может разбить двумерное пространство только на четыре класса (что отвечает принятому нами условию - "смотрим издалека"). Так же эту сеть еще называют однослойным персептроном (one lauer perceptrons )
Этот пример демонстрирует и сложности. Чтобы получить более точную классификацию - сеть нужно изменить. Или изначально закладывать запас возможностей, что конечно негативно скажется на быстродействии.
Приведенная сеть может ответить на вопрос - медведь, похож на медведя, слон, похож на слона и т.д.
В прологе мы можем дополнять базу, вводить новые факты(классы), но вручную. Что ограничивает область применения такого подхода, но во многих, например комбинаторных задачах делает их решение более эффективным и точным.
Но подобный подход реализуется и по другому. Например используем Maple.
> |
big
:={bear, elephant}:# ~big(bear). |
> |
small:={cat,mouse}:# ~big(elephant). |
> |
brown:={bear}: |
> |
black:={cat}: |
> |
grey:={elephant}: |
> |
white:={mouse}: |
> |
dark:=black
union brown: #~dark(Z):-black(Z).dark(Z):-brown(Z). |
> |
not_dark:=grey
union white: |
Зададим вопрос.
Преимущество - соответствие правил записи в математике и кода. Если рассматривать обучение студентов, то это преимущество сложно переоценить.
При практической работе - это также огромное преимущество, потому что отпадает необходимость переводить математические выкладки на яхык пролога и наооборот.
То что логическое программирование актуально как никогда - факт. Но отвечает ли Пролог требованиям времени?
Vsoft(c).