בניית גרפי ידע מטקסט היא תחום מחקר מרתק כבר לא מעט זמן. עם הופעת מודלים של שפה גדולה (LLMs), תחום זה זכה ליותר תשומת לב מיינסטרים. עם זאת, לימודי LLM יכולים להיות די יקרים. גישה חלופית היא כוונון עדין של מודלים קטנים יותר, שנתמכו במחקר אקדמי, המניב פתרונות יעילים יותר. היום, נחקור את Relik , מסגרת להפעלת מודלים של מיצוי מידע מהיר וקל משקל, שפותחה על ידי קבוצת NLP באוניברסיטת Sapienza ברומא.
צינור חילוץ מידע טיפוסי ללא LLM נראה כך:
התמונה ממחישה צינור מיצוי מידע, החל מנתוני קלט המורכבים מטקסט המזכיר "תומאז אוהב לכתוב פוסטים בבלוג. הוא מתעניין במיוחד בציור דיאגרמות". התהליך מתחיל ברזולוציית coreference לזיהוי "תומאז" ו"הוא" כאותה ישות. זיהוי ישויות בשם (NER) מזהה לאחר מכן ישויות כגון "תומאז", "בלוג" ו"דיאגרמה".
קישור ישויות הוא התהליך העוקב אחר NER, שבו ישויות מוכרות ממופים לערכים תואמים במסד נתונים או במאגר ידע. לדוגמה, "Tomaz" מקושר ל-"Tomaz Bratanic (Q12345)" ו-"Blog" ל-"Blog (Q321)", אבל ל-"Diagram" אין התאמה במאגר הידע.
מיצוי מערכות יחסים הוא השלב הבא שבו המערכת מזהה ומחלצת מערכות יחסים משמעותיות בין הישויות המוכרות. דוגמה זו מזהה כי ל"תומאז" יש מערכת יחסים עם "בלוג" המאופיין ב-"WRITES", מה שמצביע על כך שתומאז כותב בלוגים. בנוסף, הוא מזהה של"תומאז" יש קשר עם "דיאגרמה" המאופיין ב-"INTERESTED_IN", מה שמצביע על כך שתומאז מתעניין בדיאגרמות.
לבסוף, מידע מובנה זה, כולל הישויות והקשרים ביניהן, מאוחסן בגרף ידע, המאפשר נתונים מאורגנים ונגישים להמשך ניתוח או אחזור.
באופן מסורתי, ללא הכוח של LLMs, כל התהליך הזה מסתמך על חבילה של מודלים מיוחדים, שכל אחד מהם מטפל במשימה ספציפית החל מרזולוציית coreference ועד מיצוי קשרים. בעוד ששילוב מודלים אלה דורש יותר מאמץ ותיאום, הוא מציע יתרון משמעותי: עלויות מופחתות. על ידי כוונון עדין של דגמים קטנים יותר, ספציפיים למשימה, ניתן לשמור על ההוצאות הכוללות של בנייה ותחזוקה של המערכת.
הקוד זמין ב- GitHub .
אני מציע לך להשתמש בסביבת Python נפרדת כמו Google Colab , מכיוון שנצטרך לשחק קצת עם תלות. הדגמים מהירים יותר ב-GPU, כך שתוכל להשתמש בזמן ריצה המופעל על GPU אם יש לך את גרסת ה-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)
השלב הראשון בצנרת הוא מודל רזולוציית coreference. רזולוציית Coreference היא המשימה של זיהוי כל הביטויים בטקסט המתייחסים לאותה ישות.
למיטב ידיעתי, אין הרבה מודלים של קוד פתוח זמינים לרזולוציית coreference. ניסיתי את maverick-coref , אבל בבדיקות שלי Coreferee מ- spaCy עבד טוב יותר, אז נשתמש בזה. החיסרון היחיד בשימוש ב-Coreferee הוא שאנחנו צריכים להתמודד עם גיהנום של תלות, מה שנפתר במחברת, אבל לא נעבור על זה כאן.
אתה יכול לטעון את מודל coreference ב- 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."
שימו לב שהשכתוב לא תמיד מחזיר משפטים נכונים מבחינה דקדוקית עקב שימוש בלוגיקת החלפה פשוטה עבור ישויות בתוך האשכול. עם זאת, זה אמור להיות מספיק טוב עבור רוב התרחישים.
כעת אנו מיישמים את רזולוציית ה-coreference על מערך הנתונים החדשות שלנו ועוטפים את התוצאות כמסמכי 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 Browser כדי לאמת את הגרף המיובא. אתה אמור לקבל הדמיה דומה על ידי הפעלת הצהרת 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, ניתן לבנות גרפי ידע מתקדמים המאפשרים משימות ניתוח ואחזור נתונים מורכבות, כל זאת ללא העלויות הגבוהות הכרוכות בדרך כלל בפריסת LLMs. שיטה זו לא רק הופכת כלי עיבוד נתונים רבי עוצמה לנגישים יותר, אלא גם מקדמת חדשנות ויעילות בזרימות עבודה של מיצוי מידע.
הקפד לתת כוכב לספריית Relik . הקוד זמין ב- GitHub .
כדי ללמוד עוד על נושא זה, הצטרפו אלינו ל-NODES 2024 ב-7 בנובמבר, כנס המפתחים הווירטואלי החינמי שלנו בנושא אפליקציות חכמות, גרפי ידע ובינה מלאכותית. הירשם עכשיו !