Как PyReason помогает парадигме NeSy?

В этом посте я расскажу о нашей недавней работе над программным обеспечением под названием PyReason. Подробное описание и репозиторий Github см. по ссылкам ниже.

Статья: https://arxiv.org/abs/2302.13482

Код: https://github.com/lab-v2/pyreason

Содержание

  1. Фон
    а. Нейросимволические рамки
    б. Предикаты, атомы, аннотации и интерпретации в графическом случае
    c. Рассуждения о графических структурах
  2. PyReason
    а. Функции
  3. Использование PyReason на примере
    а. Входные файлы для PyReason
    б. Создание графика
    c. Создание ярлыков
    d. Создание фактов
    e. Создание правил
    f. Запуск программы
  4. Заключение

Фон

Этот пост содержит концепции из логики предикатов и логики первого порядка — если вам нужно освежить в памяти эти темы, эта публикация в блоге охватывает некоторые основы.

Нейросимволические рамки

Глубокие нейронные сети были основной частью некоторых из крупнейших прорывов в области искусственного интеллекта за последние годы. Однако есть несколько критических проблем с глубокими нейронными сетями, таких как отсутствие интерпретируемости, неспособность рассуждать на основе здравого смысла и больших объемов данных, необходимых для обучения.

Нейро-символический ИИ направлен на устранение этих пробелов в глубоком обучении путем интеграции символической логики с нейронными сетями. В таких системах обычно есть, как вы могли догадаться, два основных компонента:

  1. Логический компонент/фреймворк
  2. Нейронный компонент/каркас

Недавно было представлено несколько нейросимволических систем, таких как: логические нейронные сети [1] (LNN) и логические тензорные сети [2] (LTN). Каждая из этих систем имеет свою собственную логическую основу для дедукции и рассуждений; при этом все они используют различные функции и функции. Например, логическая структура в LNN использует рассуждения открытого мира (предположение, что логические утверждения начинаются как неопределенные, а не ложные), а логическая структура в LTN использует нечеткую логику с действительными значениями.

В большинстве случаев необходимо создавать новое программное обеспечение на заказ для конкретной используемой логики.

Предикаты, атомы, аннотации и интерпретации в графическом случае

Для иллюстрации рассмотрим следующий график:

Предикат – это выражение с одной или двумя переменными (в данном случае). Приведенный выше граф содержит как унарные (метки узлов), так и бинарные (метки ребер) предикаты.

Pet(x) — пример унарного предиката
Friends(x1, x2) — пример бинарного предиката

x, x1 и x2 — это переменные, которые можно заменить отдельными узлами.

Как только переменные в предикатах заменяются определенными узлами, они называются атомами. Этот процесс называется заземлением. Например: Pet(Dog) и Friends(John, Mary) — это атомы земли.

Аннотации — это реальные значения или интервалы. Например, для представления действительного числа 0,2 аннотация будет [0,2, 0,2], а для представления интервала между 0,2 и 1 аннотация будет [0,2, 1].

Интерпретации — это сопоставления атомов с аннотациями в определенный момент времени. Например, если I интерпретация, t момент времени, представленный на графике выше, тогда: I(Друзья(Джон, Мэри), t) = [1,1].

Рассуждения о графических структурах

Рассуждения по графам очень похожи на обычный вывод по базам знаний.

  1. У нас есть набор фактов или начальных условий, которые можно представить на графике.
  2. У нас есть набор Правил, которые определяют динамику системы и то, как все будет меняться.
  3. Мы заземляем переменные в правиле, чтобы проверить, выполняются ли условия.

Основное отличие состоит в том, что привязка переменных к константам производится только к соседям рассматриваемой нами цели. Например, если мы проверяем, применяется ли правило к определенному узлу, скажем, Джон,то выполнение пунктов правила определяется соседями Джона , особенно Мэри и Джастин.

PyReason

PyReason — это реализация Python с открытым исходным кодом для рассуждений и дедукции в логическом программировании.

Он основан на концепции аннотированной логики [3], которая оказалась общей структурой, которую можно использовать для захвата нескольких нечетких, вещественных и других логик. Другими словами, аннотированная логика подобна расширенному набору логики, используемой в нейросимволических системах. Поэтому вместо того, чтобы изобретать новую логику для каждого нейросимволического фреймворка, почему бы не использовать аннотированную логику?

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

PyReason разработан как современная масштабируемая реализация. Он использует библиотеку numba для перевода большей части кода Python в машинный код, что значительно ускоряет время выполнения, одновременно сохраняя модульность и простоту Python.

Функции

Это некоторые из ключевых функций, которые предлагает PyReason.

  1. Объяснимость: эта ключевая функция позволяет пользователям точно понять, что произошло и почему это произошло в процессе рассуждений. Результатом PyReason является файл CSV, который предоставляет пользователю подробную информацию о процессе рассуждения.
  2. Поддержка рассуждений по графам знаний. Графические структуры являются одним из наиболее часто используемых представлений данных. PyReason принимает на вход граф знаний в формате GraphML и выполняет рассуждения и дедукции, используя данные из этого графа.
  3. Поддержка аннотаций. Предыдущие реализации логики, такие как Prolog и Epilog, не поддерживали аннотации. PyReason поддерживает аннотации, а также функции над этими аннотациями, которые можно использовать в логических правилах.
  4. Временные расширения: PyReason поддерживает рассуждения во времени с интегрированным компонентом времени. Программное обеспечение использует интерпретации как карты от атомов и временных точек до аннотаций. I(предикат(х), t) = [l, u].
  5. Проверка типов: графические структуры по своей природе разрежены, а предикаты связаны с определенными узлами/ребрами. Например, на приведенном выше графике мы не должны рассматривать такие атомы, как Pet(John). Это должно быть ограничено узлами, которые являются только животными. PyReason может обрабатывать такие случаи и в результате сокращать пространство поиска при оценке приемлемости правила.
  6. Способность обнаруживать и устранять несоответствия: если в процессе рассуждений мы обнаружим, например, что I(Pet(Dog), t) = [1,1] иI(Human(Dog), t) = [1,1],PyReason предупредит пользователя об этом, установит аннотации на [0,1] и сделает интерпретацию неизменной во избежание распространения ошибки.
  7. Обработка неопределенности: используя аннотации, Pyreason может обрабатывать неопределенность через интервалы. Он также может представлять пропозициональные случаи (Истина/Ложь), используя [0,0] и [1,1]

Использование PyReason на примере

Давайте посмотрим на пример, где мы можем запустить PyReason. Используя тот же график выше, давайте определим факты и правила в YAML — формате, поддерживаемом PyReason.

Давайте предположим, что популярность человека (для иллюстрации 😄) определяется тем, есть ли у него ПО КРАЙНЕЙ МЕРЕ ОДИН популярный друг И у которого такой же питомец, как и у них. Если это правда, то они считаются популярными. Мы хотим изучить распространение популярности с учетом некоторых начальных условий и приведенного ниже графика.

Если бы мы записали это как логическое правило, это было бы

Зададим Марии начальное условие, чтобы она была популярна. На следующих шагах вывода, основанных на только что сформулированном правиле:

  1. Джастин становится популярным, потому что он дружит с популярной Мэри, и у них обоих есть кошка.
  2. Джон становится популярным, потому что он дружит с Джастином, который только что стал популярным на предыдущем шаге, и у них обоих есть собака.

Входные файлы для PyReason

PyReason может принимать на вход 5 файлов

  1. Файл GraphMl, содержащий график (обязательно)
  2. Файл YAML, содержащий правила пиреона (обязательно)
  3. Файл YAML, содержащий информацию о пожаре (необязательно, но рекомендуется)
  4. Файл YAML, содержащий метки pyreason (необязательно, но рекомендуется)
  5. Файл YAML, содержащий pyreason ipl (несогласованный список предикатов) (необязательно)

В этом примере мы не будем использовать ipl (несогласованный список предикатов), но это способ иметь два предиката, дополняющих друг друга. Обновление до одного приведет к обновлению дополнения. Если есть какие-либо несоответствия, они будут обнаружены и устранены. Это удобный способ представления отрицаний.

Генерация графика

На приведенном выше графике представлены 3 человека по имени Мэри, Джон, Джастин и их домашние животные. Давайте посмотрим, как мы можем сгенерировать такой график, используя библиотеку Python networkx.

import networkx as nx

# Create a Directed graph
g = nx.DiGraph()

# Add the nodes
g.add_nodes_from(['John', 'Mary', 'Justin'])
g.add_nodes_from(['Dog', 'Cat'])

# Add the edges and their attributes. When an attribute = x which is <= 1, the annotation
# associated with it will be [x,1]. NOTE: These attributes are immutable
# Friend edges
g.add_edge('Justin', 'Mary', Friends=1)
g.add_edge('John', 'Mary', Friends=1)
g.add_edge('John', 'Justin', Friends=1)

# Pet edges
g.add_edge('Mary', 'Cat', owns=1)
g.add_edge('Justin', 'Cat', owns=1)
g.add_edge('Justin', 'Dog', owns=1)
g.add_edge('John', 'Dog', owns=1)

# Save the graph to GraphML format to input into PyReason
nx.write_graphml_lxml(g, 'friends_graph.graphml', named_key_ids=True)

Создание этикеток

В этот файл мы помещаем любую метку, которую мы хотим связать с узлами или ребрами. Это формат файла

---
# Labels that apply to all nodes
node_labels:
    - popular

# Labels that apply to all edges (none in this case)
edge_labels:

# Labels that apply to specific nodes. In this case nothing (none in this case)
node_specific_labels:

# Labels that apply to specific edges. In this case nothing (none in this case)
edge_specific_labels:

Создание фактов

Теперь, когда граф создан в формате GraphML, а метка Popular связана с узлами, давайте посмотрим, как мы можем установить начальное условие. В этом случае мы собираемся установить метку «популярный», принадлежащую Марии, как [1,1]. Это статический факт, другими словами, он не изменится, когда мы перейдем к следующему шагу времени/шагу вывода.

---
# List all facts below
nodes:
    fact_1:
        node: Mary          # Name of the node
        label: popular      # Name of the label of the node
        bound: [1, 1]       # Bound of the label
        static: True        # Whether it applies to all timesteps and cannot change
        t_lower: 0          # Starting time
        t_upper: 2          # Ending time. In this case it will be active for the first timestep t=0

# Nothing here, we have no edge facts
edges:

Создание правил

Последний шаг — создать правило, о котором мы говорили ранее. Это говорит нам о том, как будет распространяться популярность. Ниже приведен формат правил:

---
# All Rules come under here
rule_1:
    target: popular        # Target label

    target_criteria:       # List of all target criteria
                           # All criteria come here in the form [label, lower_bound, upper_bound]
    delta_t: 1             # Delta t, time after which this rule is applied

    # The following are the 4 clauses for the rule
    neigh_criteria:        # List of all neighbour criteria in the form [criteria on node/edge, variable, label, [lower_bound, upper_bound], [equal/greater/less/greater_equal/less_equal, number/[percent, total/available], value]]
        - [node, [x1], popular, [1,1]]
        - [edge, [x1, target], Friends, [1,1]]
        - [edge, [x2, x1], owns, [1,1]]
        - [edge, [x2, target], owns, [1,1]]

    ann_fn: [1,1]          # Annotation function name or bound. See annotation_functions.py for list of available functions. The name of that function comes here
                           # Could be func_name or [l, u]

Это правило изменяет границу метки популярности узла с [0,1] на [1,1] на следующем временном шаге, если выполняются 4 пункта (neigh_criteria).

Запуск программы

Теперь давайте запустим PyReason с этими файлами! Есть два способа использовать PyReason: как инструмент командной строки или как библиотеку Python. Мы будем использовать последний метод из-за его простоты.

Чтобы установить PyReason как библиотеку Python, следуйте инструкциям здесь.

import pyreason as pr

# Modify the paths based on where you've stored the files we made above
graph_path = 'friends_graph.graphml'
labels_path = 'labels.yaml'
facts_path = 'facts.yaml'
rules_path = 'rules.yaml'

# Modify pyreason settings to make verbose and to save the rule trace to a file
pr.settings.verbose = True    # Print info to screen
pr.settings.atom_trace = True # This allows us to view all the atoms that have made a certain rule fire

# Load all the files into pyreason
pr.load_graph(graph_path)
pr.load_labels(labels_path)
pr.load_facts(facts_path)
pr.load_rules(rules_path)

# Run the program for two timesteps to see the diffusion take place
interpretation = pr.reason(timesteps=2)

# Display the changes in the interpretation for each timestep
dataframes = pr.filter_and_sort(interpretation, ['popular'])
for t, df in enumerate(dataframes):
    print(f'TIMESTEP - {t}')
    print(df)
    print()

# Save all changes made to the interpretations a file. This is the explainability component
pr.save_rule_trace(interpretation)

Вывод на экран должен показать следующий вывод, который соответствует тому, что мы ожидали:

Timestep: 0
Timestep: 1
Timestep: 2

Converged at time: 2
Fixed Point iterations: 3

TIMESTEP - 0
  component     popular
0      Mary  [1.0, 1.0]

TIMESTEP - 1
  component     popular
0      Mary  [1.0, 1.0]
1    Justin  [1.0, 1.0]

TIMESTEP - 2
  component     popular
0      Mary  [1.0, 1.0]
1      John  [1.0, 1.0]
2    Justin  [1.0, 1.0]

Вы также должны найти файл CSV в той же папке, что и ваш скрипт Python, который дает вам объяснимую трассировку всех изменений, которые произошли во время работы программы, и из-за каких узлов или ребер произошли правила. Для каждого предложения есть столбец, содержащий узлы или ребра, удовлетворяющие этому предложению. Это может быть чрезвычайно полезно для отладки и делает систему объяснимой!

Запустить PyReason очень просто. Чтобы начать запускать свои собственные программы логического вывода, перейдите в репозиторий GitHub и проверьте формат примеров файлов YAML, чтобы понять, как писать входные файлы.

Заключение

Как мы видели, PyReason — чрезвычайно универсальная, масштабируемая, современная программа для анализа графических структур. Поскольку он включает в себя несколько логик и обладает многочисленными желаемыми функциями, он потенциально может быть интегрирован в логический компонент любой (настоящей и будущей) нейросимволической структуры.

В настоящее время в программное обеспечение вносится несколько улучшений, одно из которых включает использование синтаксического анализатора, чтобы пользователь мог вводить факты и правила в стиле Prolog/Datalog, а не в YAML.

Об авторе

Дьюман Адитья в настоящее время является стажером-исследователем в Университете штата Аризона. Его интересы лежат в области машинного обучения, нейросимволического ИИ и робототехники. Ранее он работал в стартапе по робототехнике и искусственному интеллекту под названием Telekinesis в Техническом университете Дармштадта в Германии и в качестве стажера-исследователя в Университете Карнеги-Меллона. Он с отличием окончил Международный образовательный центр Шри Ауробиндо со степенью бакалавра компьютерных наук и математики.

Рекомендации

[1] Ригель, Райан и др. «Логические нейронные сети». Препринт arXiv arXiv: 2006.13155 (2020).

[2] Бадреддин, Сэми и др. «Логические тензорные сети». Искусственный интеллект 303 (2022): 103649.

[3] Кифер, Майкл и др. «Теория обобщенного аннотированного логического программирования и ее приложения». Журнал логического программирования 12 (1992): 335–367.