Побудова графіків знань з тексту була захоплюючою галуззю досліджень протягом досить тривалого часу. З появою великих мовних моделей (LLM) ця сфера привернула більше уваги. Однак LLMs може бути досить дорогим. Альтернативний підхід полягає в тонкому налаштуванні менших моделей, який підтверджується академічними дослідженнями, що забезпечує більш ефективні рішення. Сьогодні ми дослідимо Relik , структуру для запуску неймовірно швидких і легких моделей вилучення інформації, розроблену групою NLP Римського університету Сапієнца.
Типовий конвеєр вилучення інформації без LLM виглядає так:
Зображення ілюструє конвеєр вилучення інформації, починаючи з вхідних даних, які складаються з тексту зі згадкою «Томаз любить писати дописи в блогах. Його особливо цікавить малювання діаграм». Процес починається з кореференційної роздільної здатності, щоб ідентифікувати «Томаза» та «Він» як ту саму сутність. Потім функція розпізнавання іменованих об’єктів (NER) визначає такі об’єкти, як «Томаз», «Блог» і «Діаграма».
Зв’язування сутностей — це процес, який слідує за NER, де розпізнані сутності зіставляються з відповідними записами в базі даних або базі знань. Наприклад, «Tomaz» пов’язано з «Tomaz Bratanic (Q12345)», а «Blog» — із «Blog (Q321)», але «Діаграма» не має відповідності в базі знань.
Вилучення зв’язків — це наступний крок, на якому система визначає та виділяє значущі зв’язки між розпізнаними об’єктами. У цьому прикладі показано, що «Tomaz» має зв’язок із «Blog», що характеризується «WRITES», що вказує на те, що Tomaz пише блоги. Крім того, він визначає, що «Томаз» має зв’язок із «Діаграмою», яка характеризується «INTERESTED_IN», що вказує на те, що Томаз зацікавлений у діаграмах.
Нарешті, ця структурована інформація, включаючи об’єкти та їхні зв’язки, зберігається в графі знань, що дає змогу організовувати та доступні дані для подальшого аналізу чи пошуку.
Традиційно, без потужності LLM, весь цей процес спирається на набір спеціалізованих моделей, кожна з яких виконує конкретне завдання від вирішення кореференції до вилучення зв’язків. Хоча інтеграція цих моделей вимагає більше зусиль і координації, вона дає значну перевагу: зниження витрат. Тонко налаштовуючи менші моделі, що відповідають конкретним завданням, можна контролювати загальні витрати на створення та підтримку системи.
Код доступний на GitHub .
Я пропоную вам використовувати окреме середовище Python, наприклад Google Colab , оскільки нам доведеться трохи пограти із залежностями. Моделі працюють швидше на графічному процесорі, тому ви можете використовувати середовище виконання з графічним процесором, якщо у вас є версія Pro.
Крім того, нам потрібно налаштувати Neo4j, рідну базу даних графів, щоб зберігати видобуту інформацію. Є багато способів налаштувати екземпляр бази даних . Однак я рекомендую використовувати Neo4j Aura , який надає безкоштовний хмарний екземпляр, до якого можна легко отримати доступ із записника Google Colab.
Neo4j Aura – повністю кероване хмарне рішення
Після створення бази даних ми можемо визначити з’єднання за допомогою LlamaIndex:
from llama_index.graph_stores.neo4j import Neo4jPGStore username="neo4j" password="rubber-cuffs-radiator" url="bolt://54.89.19.156:7687" graph_store = Neo4jPGStore( username=username, password=password, url=url, refresh_schema=False )
Ми використаємо набір даних новин, який я деякий час тому отримав через Diffbot API . Набір даних зручно доступний на GitHub для повторного використання:
import pandas as pd NUMBER_OF_ARTICLES = 100 news = pd.read_csv( "https://raw.githubusercontent.com/tomasonjo/blog-datasets/main/news_articles.csv" ) news = news.head(NUMBER_OF_ARTICLES)
Першим кроком у конвеєрі є модель кореферентної роздільної здатності. Кореференційна роздільна здатність — це завдання ідентифікації всіх виразів у тексті, які відносяться до однієї сутності.
Наскільки мені відомо, існує не так багато моделей з відкритим вихідним кодом, доступних для кореферентного вирішення. Я спробував maverick-coref , але в моїх тестах Coreferee від spaCy працював краще, тож ми використаємо його. Єдиним недоліком використання Coreferee є те, що нам доводиться мати справу з пеклом залежностей, який вирішується в блокноті, але ми не будемо проходити через це тут.
Ви можете завантажити базову модель у spaCy за допомогою такого коду:
import spacy, coreferee coref_nlp = spacy.load('en_core_web_lg') coref_nlp.add_pipe('coreferee')
Модель Coreferee виявляє кластери вираження, які посилаються на ту саму сутність або сутності. Щоб переписати текст на основі цих кластерів, ми повинні реалізувати нашу власну функцію:
def coref_text(text): coref_doc = coref_nlp(text) resolved_text = "" for token in coref_doc: repres = coref_doc._.coref_chains.resolve(token) if repres: resolved_text += " " + " and ".join( [ t.text if t.ent_type_ == "" else [e.text for e in coref_doc.ents if t in e][0] for t in repres ] ) else: resolved_text += " " + token.text return resolved_text
Давайте перевіримо функцію, щоб переконатися, що моделі та залежності налаштовані правильно:
print( coref_text("Tomaz is so cool. He can solve various Python dependencies and not cry") ) # Tomaz is so cool . Tomaz can solve various Python dependencies and not cry
У цьому прикладі модель визначила, що «Томаз» і «Він» стосуються однієї сутності. Використовуючи функцію coref_text, ми замінюємо «He» на «Tomaz».
Зауважте, що переписування не завжди повертає граматично правильні речення через використання простої логіки заміни для об’єктів у кластері. Однак це повинно бути достатньо для більшості сценаріїв.
Тепер ми застосовуємо роздільну здатність кореференції до нашого набору даних новин і загортаємо результати як документи LlamaIndex:
from llama_index.core import Document news["coref_text"] = news["text"].apply(coref_text) documents = [ Document(text=f"{row['title']}: {row['coref_text']}") for i, row in news.iterrows() ]
Relik — це бібліотека з моделями зв’язування сутностей (EL) і вилучення зв’язків (RE), а також підтримує моделі, які поєднують обидва. У зв’язуванні сутностей Вікіпедія використовується як цільова база знань для зіставлення сутностей у тексті з відповідними записами в енциклопедії.
З іншого боку, виділення зв’язків включає ідентифікацію та класифікацію зв’язків між сутностями в тексті, що дозволяє витягувати структуровану інформацію з неструктурованих даних.
Якщо ви використовуєте безкоштовну версію Colab, використовуйте модель relik-ie/relik-relation-extraction-small, яка виконує лише вилучення зв’язків. Якщо у вас є версія Pro або ви використовуватимете її на потужнішому локальному комп’ютері, ви можете перевірити модель relik-ie/relik-cie-small, яка виконує зв’язування об’єктів і вилучення зв’язків.
from llama_index.extractors.relik.base import RelikPathExtractor relik = RelikPathExtractor( model="relik-ie/relik-relation-extraction-small" ) # Use on Pro Collab with GPU # relik = RelikPathExtractor( # model="relik-ie/relik-cie-small", model_config={"skip_metadata": True, "device":"cuda"} # )
Крім того, ми маємо визначити модель вбудовування, яка буде використовуватися для вбудовування сутностей і LLM для потоку запитань-відповідей:
import os from llama_index.embeddings.openai import OpenAIEmbedding from llama_index.llms.openai import OpenAI os.environ["OPENAI_API_KEY"] = "sk-" llm = OpenAI(model="gpt-4o", temperature=0.0) embed_model = OpenAIEmbedding(model_name="text-embedding-3-small")
Зверніть увагу, що LLM не використовуватиметься під час побудови графіка.
Тепер, коли все готово, ми можемо створити екземпляр PropertyGraphIndex і використовувати документи новин як вхідні дані для графа знань.
Крім того, нам потрібно передати модель relik як значення kg_extractors, щоб отримати зв’язки:
from llama_index.core import PropertyGraphIndex index = PropertyGraphIndex.from_documents( documents, kg_extractors=[relik], llm=llm, embed_model=embed_model, property_graph_store=graph_store, show_progress=True, )
Після побудови графіка ви можете відкрити браузер Neo4j, щоб перевірити імпортований графік. Ви повинні отримати подібну візуалізацію, виконавши такий оператор Cypher:
MATCH p=(:__Entity__)--(:__Entity__) RETURN p LIMIT 250
Результати
Використовуючи LlamaIndex, тепер легко відповідати на запитання. Щоб використовувати типові засоби отримання графіків, ви можете поставити такі прості запитання, як:
query_engine = index.as_query_engine(include_text=True) response = query_engine.query("What happened at Ryanair?") print(str(response))
Тут вступають у гру визначені LLM і модель вбудовування. Звичайно, ви також можете застосувати користувальницькі ретривери для потенційно кращої точності.
Побудова графів знань, не покладаючись на LLMs, не тільки здійсненна, але й економічно ефективна. Тонко налаштовуючи менші моделі, орієнтовані на конкретні завдання, такі як ті, які є у структурі Relik, ви можете досягти високопродуктивного вилучення інформації для ваших додатків RAG.
Пов’язування сутностей, критичний крок у цьому процесі, гарантує, що розпізнані сутності точно зіставляються з відповідними записами в базі знань, таким чином зберігаючи цілісність і корисність графа знань.
Використовуючи фреймворки, такі як Relik, і такі платформи, як Neo4j, можна побудувати розширені графи знань, які полегшують складні завдання аналізу та пошуку даних, і все це без великих витрат, які зазвичай пов’язані з розгортанням LLM. Цей метод не тільки робить потужні засоби обробки даних більш доступними, але також сприяє інноваціям і ефективності робочих процесів вилучення інформації.
Не забудьте поставити бібліотеці Relik зірку . Код доступний на GitHub .
Щоб дізнатися більше про цю тему, приєднуйтесь до нас на NODES 2024 7 листопада, нашій безкоштовній віртуальній конференції для розробників, присвяченій інтелектуальним програмам, графам знань і ШІ. Зареєструватися ЗАРАЗ !