Как преобразовать любой текст в граф понятий

Мастерство преобразования текста в озаряющий граф понятий

Изображение, созданное автором с использованием проекта, представленного в этой статье.

Несколько месяцев назад основанный на знаниях вопросно-ответный сервис (KBQA) был новинкой. Теперь KBQA с Retrieval Augmented Generation (RAG) является игрушкой для любого энтузиаста искусственного интеллекта. Удивительно наблюдать, как область возможностей в компьютерной лингвистике так быстро расширяется благодаря мощности языковых моделей. И она становится все лучше с каждым днем.

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

Исследовательский агент: решение проблемы ответов на вопросы на основе большого корпуса текста

Я создал автономного исследовательского агента искусственного интеллекта, способного отвечать на сложные вопросы с использованием глубокого многошагового рассуждения

towardsdatascience.com

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

В этой статье я хочу поделиться другой идеей, которая, в комбинации с рекурсивным RAG, может помочь создать супер-исследовательского агента. Идея возникла в результате моих экспериментов с рекурсивным RAG с более маленькими языковыми моделями и несколькими другими идеями, которые я прочитал на VoAGI, а именно — Knowledge-Graph Augmented Generation.

Аннотация

Граф Знаний (Knowledge Graph), или любой другой граф, состоит из узлов и ребер. Каждый узел графа представляет собой концепцию, а каждое ребро — отношение между двумя такими концепциями. В этой статье я поделюсь методом преобразования любого текстового корпуса в граф концепций. Я использую термин “граф концепций” (Graph of Concept, GC) взаимозаменяемо с термином “граф знаний” для более точного описания того, что я демонстрирую здесь.

Все компоненты, которые я использовал в этой реализации, можно установить локально, поэтому этот проект легко запускается на персональном компьютере. Здесь я не использую модели GPT, потому что я верю в использование более маленьких открытых моделей. Я использую фантастические модели Mistral 7B Openorca instruct и Zephyr. Эти модели можно локально установить с Ollama.

Базы данных, такие как Neo4j, упрощают хранение и извлечение графовых данных. Здесь я использую Dataframes в памяти Pandas и библиотеку NetworkX для простоты.

Наша цель здесь — преобразовать любой текстовый корпус в граф концепций (GC) и визуализировать его, как красивое баннерное изображение этой статьи. Мы сможем взаимодействовать с графом с помощью перемещения узлов и ребер, масштабирования изображения, а также изменения физики графа по своему усмотрению. Вот ссылка на страницу Github, которая показывает результат того, что мы строим.

https://rahulnyk.github.io/knowledge_graph/

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

Граф Знаний

Рассмотрим следующий текст.

Мэри имела маленькую овечку,Вы уже слышали эту сказку раньше;Но знаете ли вы, что она подала свою тарелку,И ела еще чуть-чуть!

(Надеюсь, здесь нет детей, читающих это 😝)

Вот одно из возможных представлений текста в виде графа знаний.

Диаграмма, созданная автором с использованием draw.io

В следующей статье от IBM наглядно объясняется фундаментальное понятие графов знаний.

Что такое граф знаний? | IBM

www.ibm.com

Цитируя отрывок из статьи для краткого изложения идеи:

Граф знаний, также известный как семантическая сеть, представляет собой сеть реальных мировых сущностей – объектов, событий, ситуаций или понятий – и показывает связь между ними. Эта информация обычно хранится в графовой базе данных и визуализируется в виде графической структуры, что объясняет термин “граф знаний”.

Почему граф знаний?

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

Мы также можем использовать графы знаний для реализации Усиленной генерации с использованием графического поиска (GRAG или GAG) и взаимодействовать с нашими документами. Это может дать нам гораздо лучшие результаты, чем простая старая версия RAG, которая имеет несколько недостатков. Например, поиск контекста, наиболее релевантного для запроса с помощью обычного семантического поиска сходства, не всегда эффективен. Особенно когда запрос не предоставляет достаточно контекста о своем истинном намерении или когда контекст разбросан по большому корпусу текста.

Например, рассмотрим такой запрос —

Расскажи мне о генеалогическом древе Хосе Аркадио Буэндии в книге “Сто лет одиночества”.

В книге описано 7 поколений Хосе Аркадио Буэндии, причем половина персонажей названа Хосе Аркадио Буэндия. Будет довольно сложно, если вообще возможно, ответить на этот запрос с помощью простого конвейера RAG.

Еще одним недостатком RAG является то, что он не может сказать вам, что спросить. Очень часто задавать правильные вопросы важнее, чем получить ответы.

Усиленная генерация с использованием графа (GAG) может частично устранить эти недостатки RAG. Что еще лучше, мы можем сочетать и соединять и создавать конвейер Усиленной генерации с использованием графа, чтобы получить лучшее из обоих миров.

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

Создание графа концепций

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

  1. Извлекайте концепции и сущности из текстового материала. Они являются узлами.
  2. Извлечь отношения между концепциями. Они являются связями.
  3. Заполните узлы (концепции) и ребра (связи) в графической структуре или базе данных графов.
  4. Визуализируйте для художественного наслаждения, если не для чего-то еще.

Шаги 3 и 4 звучат понятно. Но как достичь шагов 1 и 2?

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

Диаграмма, созданная автором с использованием draw.io
  1. Разделите текстовый корпус на фрагменты. Назначьте каждому из этих фрагментов идентификатор.
  2. Для каждого фрагмента текста извлекайте концепции и их семантические отношения с помощью LLM. Давайте присвоим этому отношению вес W1. Между одной и той же парой концепций может быть несколько отношений. Каждое такое отношение является связью между парой концепций.
  3. Учтите, что концепции, которые встречаются в одном фрагменте текста, также связаны своей контекстуальной близостью. Давайте присвоим этому отношению вес W2. Обратите внимание, что одна и та же пара концепций может встречаться в нескольких фрагментах.
  4. Группируйте подобные пары, суммируйте их веса и соединяйте их отношения. Таким образом, у нас теперь есть только одна связь между любой отдельной парой концепций. Связь имеет определенный вес и список отношений в качестве своего имени.

Вы можете увидеть реализацию этого метода в виде кода Python в репозитории GitHub, который я делюсь в этой статье. Давайте кратко рассмотрим основные идеи реализации в следующих нескольких разделах.

Для демонстрации метода здесь я использую следующую обзорную статью, опубликованную в PubMed/Cureus на условиях лицензии Creative Commons Attribution. Заслуги авторов в конце этой статьи.

Повышение кадрового потенциала Индии в здравоохранении

Здоровье Индии за последнее время улучшилось, но все еще отстает от показателей своих ровесников….

www.cureus.com

Мистраль и Первоочередное

Шаг 1 в приведенной выше схеме выполнения прост. Langchain предоставляет множество разделителей текста, которые мы можем использовать для разделения нашего текста на фрагменты.

Шаг 2 – это там начинается настоящее веселье. Чтобы извлечь понятия и их взаимосвязи, я использую модель Mistral 7B. До того, как я сделал выбор варианта модели, наиболее подходящего для наших целей, я экспериментировал со следующими:

Mistral Instruct, Mistral OpenOrca и Zephyr (версия Hugging Face, производная от Mistral)

Я использовал 4-битную квантованную версию этих моделей – чтобы мой Mac не начал меня ненавидеть – запущенных локально с Ollama.

Ollama

Быстрый старт с большими языковыми моделями локально.

ollama.ai

Все эти модели – это настроенные на инструкцию модели с системным приглашением и пользовательским приглашением. Все они хорошо выполняют инструкции и аккуратно форматируют ответ в JSON, если мы попросим об этом.

После нескольких раундов проб и ошибок, я наконец сделал выбор в пользу модели Zephyr с использованием следующих приглашений.

SYS_PROMPT = (    "Вы - создатель сетевого графа, который извлекает термины и их взаимосвязи из заданного контекста. "    "Вам предоставлен фрагмент контекста (ограниченный «```»). Ваша задача - извлечь онтологию "    "терминов, упомянутых в заданном контексте. Эти термины должны представлять ключевые концепции в соответствии с контекстом. \n"    "Мысль 1: Перебирая каждое предложение, подумайте о ключевых терминах, упомянутых в нем.\n"        "\tТермины могут включать объект, сущность, местоположение, организацию, человека, \n"        "\tсостояние, акроним, документы, услугу, концепцию и т. д.\n"        "\tТермины должны быть как можно более атомарными\n\n"    "Мысль 2: Подумайте, как эти термины могут иметь однозначное отношение к другим терминам.\n"        "\tТермины, упомянутые в одном предложении или одном абзаце, обычно связаны между собой.\n"        "\tТермины могут быть связаны с многими другими терминами\n\n"    "Мысль 3: Определите отношение между каждой такой связанной парой терминов. \n\n"    "Отформатируйте вывод в виде списка json. Каждый элемент списка содержит пару терминов"    "и отношение между ними, как показано ниже: \n"    "[\n"    "   {\n"    '       "node_1": "Концепция извлеченной онтологии",\n'    '       "node_2": "Связанная концепция извлеченной онтологии",\n'    '       "edge": "отношение между двумя концепциями, node_1 и node_2 в одном или двух предложениях"\n'    "   }, {...}\n"    "]")USER_PROMPT = f"контекст: ```{input}``` \n\n вывод: "

Если мы передадим нашу (не подходящую) детскую песенку с таким приглашением, вот результат.

[  {    "node_1": "Мэри",    "node_2": "ягненок",    "edge": "владеется"  },  {    "node_1": "тарелка",    "node_2": "пища",    "edge": "содержится"  }, . . .]

Заметьте, что он даже угадал ‘пища’ как понятие, которое не было явно упомянуто в текстовом фрагменте. Это прекрасно!

Если мы прогоним это через каждый текстовый фрагмент нашей примерной статьи и преобразуем json в таблицу данных Pandas, то она будет выглядеть так.

Каждая строка здесь представляет отношение между парой понятий. Каждая строка представляет собой ребро между двумя узлами в нашем графе, и может быть несколько ребер или отношений между одной и той же парой понятий. Счетчик в таблице данных выше я задал произвольно равным 4.

Контекстуальная близость

Я предполагаю, что понятия, которые встречаются близко друг к другу в корпусе текста, связаны. Назовем это отношение “контекстуальная близость”.

Чтобы вычислить ребра контекстуальной близости, мы преобразуем таблицу данных таким образом, чтобы node_1 и node_2 объединились в одну колонку. Затем мы создаем самосоединение этой таблицы данных с использованием идентификатора фрагмента в качестве ключа. Таким образом, узлы с одинаковыми идентификаторами фрагментов будут объединяться друг с другом, чтобы образовать строку.

Но это также означает, что каждое понятие также будет объединено с самим собой. Это называется самопетлей, когда ребро начинается и заканчивается на одном и том же узле. Чтобы убрать эти самопетли, мы удалим каждую строку, где node_1 равно node_2, из таблицы данных.

В итоге мы получаем таблицу данных, очень похожую на нашу исходную таблицу данных.

Колонка count здесь – это количество фрагментов, где node_1 и node_2 встречаются вместе. Колонка chunk_id – это список всех этих фрагментов.

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

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

Создание сети понятий

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

Добавление нашей таблицы данных в граф NetworkX – это всего лишь несколько строк кода.

G = nx.Graph()## Добавим узлы в графfor node in nodes:    G.add_node(str(node))## Добавим ребра в графfor index, row in dfg.iterrows():    G.add_edge(        str(row["node_1"]),        str(row["node_2"]),        title=row["edge"],        weight=row['count']    )

Здесь мы можем начать использовать возможности графа NetworkX. NetworkX предоставляет нам множество алгоритмов для работы с графами. Вот ссылка на список алгоритмов, которые мы можем запустить на нашем графе.

Алгоритмы – документация NetworkX 3.2.1

Изменить описание

networkx.org

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

Алгоритм Girvan Newman обнаружил 17 сообществ понятий в нашей обзорной статье, с которой мы работаем. Вот одно такое сообщество.

['цифровая технология', 'EVIN', 'медицинские приборы', 'системы управления онлайн-обучением', 'носимая, отслеживаемая технология']

Это сразу дает нам представление о широкой теме обсуждаемых в обзорной статье технологий здравоохранения и позволяет нам задавать вопросы, на которые мы затем можем ответить с помощью нашего RAG Pipeline. Не здорово ли это?

Давайте также рассчитаем степень каждого концепта в нашем графе. Степень узла – это общее количество ребер, с которыми он соединен. Так что в нашем случае, чем выше степень концепта, тем более центральным он является для нашего текста. Мы будем использовать степень в качестве размера узла в нашей визуализации.

Визуализация графа

Визуализация – это самая интересная часть этого упражнения. Она имеет определенную качественность, которая дарит вам художественное удовлетворение.

Я использую библиотеку PiVis для создания интерактивных графов. Pyvis – это библиотека Python для визуализации сетей. Вот статья VoAGI, которая демонстрирует простоту и мощь библиотеки.

Pyvis: Визуализация интерактивных сетевых графов на Python

Все, что нужно, это несколько строк кода

towardsdatascience.com

Pyvis имеет встроенный помощник NetworkX для преобразования нашего графа NetworkX в объекты PyVis. Так что нам больше не нужно писать код… Ура!!

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

Так что, со всеми этими дополнительными возможностями, вот наш граф.

Gif, сгенерированный автором с использованием проекта, обсуждаемого в этой статье.

Ссылка на интерактивный граф: https://rahulnyk.github.io/knowledge_graph/

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

Мы также можем обсудить, как наш граф может помочь нам построить Graph Augmented Retrieval и как это может помочь нам создать более эффективный RAG Pipeline. Но я думаю, что лучше оставить это на другой день. Мы уже достигли нашей цели для этой статьи!

Github Repo

GitHub – rahulnyk/knowledge_graph: Преобразование любого текста в граф знаний. Это можно использовать для…

Преобразование любого текста в граф знаний. Это можно использовать для графового расширения и основанных на графах вопросов и ответов…

github.com

Приветствуются вклады и предложения

Я использовал следующую статью для демонстрации своего кода.

Saxena S G, Godfrey T (11 июня 2023 г.) Возможности Индии в решении проблем кадрового обеспечения в здравоохранении. Cureus 15(6): e40274. DOI 10.7759/cureus.40274

Я благодарен авторам за замечательную работу и за ее выпуск на условиях лицензии Creative Commons Attribution.

Обо мне

Я учусь архитектуре (не строениям… технической). Ранее я работал с моделированием полупроводников, проектированием цифровых схем, моделированием электронных интерфейсов и Интернетом вещей. В настоящее время я работаю с интероперабельностью данных и архитектурами хранилищ данных для здоровья и благополучия в Walmart Health and Wellness.