Abstrakte Wikipedia/Vorschlag für die Architektur eines Systems zur Generierung natürlicher Sprache

This page is a translated version of the page Abstract Wikipedia/Natural language generation system architecture proposal and the translation is 100% complete.

Vorschlag von Ariel Gutman

Dieses Dokument beschreibt eine vorgeschlagene Architektur für ein System zur Generierung natürlicher Sprache (NLG) für die Abstrakte Wikipedia. Bei der Betrachtung der Architektur eines NLG-Systems sollten die folgenden Überlegungen berücksichtigt werden:

  1. Modularität: Das System sollte modular sein, sodass die unterschiedlichen Aspekte der NLG (z. B. morphosyntaktische und phonotaktische Regeln) unabhängig voneinander verändert werden können.
  2. Lexikalität: Das System sollte sowohl lexikalische Daten (getrennt vom Code) erhalten können, sich aber auch auf die Generierung solcher Daten bei Bedarf anhand produktiver Sprachregeln verlassen (z. B. Beugung englischer Pluralformen mit einem -s).
  3. Rekursivität: Aufgrund der kompositorischen und rekursiven Natur der meisten Sprachen[1] muss ein effektives NLG-System selbst rekursiv sein.

Im Kontext der Abstrakten Wikipedia fällt eine weitere Einschränkung ein:

  1. Erweiterbarkeit: Das System sollte sowohl durch Sprachexperten und technisch Beitragende, als auch durch nicht-technisch Beitragende, die keine Experten sind, und die an unterschiedlichen Teilen des Systems arbeiten, erweiterbar sein.

Ausgehend von den obigen Einschränkungen erscheint es vernünftig, anzunehmen, dass eine einzige Wikifunctions-(=WF)-Funktion die Komplexität eines solchen modularen NLG-Systems nicht effektiv abbilden kann. Stattdessen müssen mehrere solche Funktionen beteiligt sein, die jeweils für einen unterschiedlichen Schritt in einer NLG-Pipeline verantwortlich sind.

Im aktuellen Design von WF können einzelne Funktionen nicht:

  • andere WF-Funktionen aufrufen.
  • Daten aus externen Quellen wie Wikidata abrufen.
  • einen globalen Zustand des Systems ändern.

Um diese Einschränkungen zu umgehen, schlägt dieses Dokument vor, eine NLG-Pipeline vom WF-Orchestrierer auszuführen, für den diese Einschränkungen nicht gelten. Darüber hinaus wird die Erstellung einer internen Vorlagensprache vorgeschlagen, die von einem speziellen WF-Evaluierer ausgeführt werden könnte, damit sich auch nicht-technisch Beitragende beteiligen können.

Ein alternativer Ansatz wäre, die Designeinschränkungen für WF-Evaluierer zu entfernen, damit die gesamte NLG-Pipeline in einer einzigen WF-Funktion eingeschlossen werden kann (die dann andere WF-Funktionen aufrufen würde). Dieser Ansatz würde zwar einige Aspekte der Implementierung des Systems ändern (z. B. könnte die Pipeline-Orchestrierung selbst von WF-Beitragenden bearbeitet werden), die konzeptionelle Architektur würde jedoch weitgehend gleich bleiben.

Am Ende des Dokuments gibt es einen kurzen Vergleich mit anderen vorgeschlagenen Ansätzen.

Architektur-Überblick

Wie oben erklärt kann die vollständige NLG-Pipeline nicht in einer einzigen Wikifunctions-(WF)-Funktion eingeschlossen werden, sondern muss vom WF-Orchestrierer ausgeführt werden, was den Abruf von Daten aus externen Quellen (insbesondere Wikidata), den Aufruf unterschiedlicher WF-Funktionen (definiert von Beitragenden) und die Beibehaltung des dazu notwendigen Status ermöglicht. Die geplante Architektur ist im folgenden Diagramm dargestellt, wobei die dunkelblauen Formen Elemente sind, die von zu Wikifunctions (Rechtecke) oder Wikidata (abgerundete Rechtecke) Beitragenden erstellt werden, während die hellblauen Elemente Funktionen oder Daten darstellen, die sich im WF-Orchestrierer befinden und zu denen die Gemeinschaft daher nicht direkt beitragen kann.

 

Lass uns die Schritte im Detail beschreiben:

  1. Bei einem gegebenen Konstruktor wird ein bestimmter Renderer ausgewählt[2] und die in dem gegebenen Konstruktor enthaltenen Daten werden als Funktionsargumente an den Renderer übergeben.
  2. Der Renderer ist im wesentlichen eine Vorlage: eine Kombination von statischem Text und Lücken, die mit den Argumenten des Renderers, Lexemen von Wikidata oder der Ausgabe anderer Renderer gefüllt werden können. Vorlagen sind relativ einfach zu verstehen und zu schreiben und daher können auch nicht-technisch Beitragende Renderer schreiben.
  3. Die Ausgabe des Renderers ist ein Syntaxbaum von Abhängigkeiten (nutzt zum Beispiel Formalismen von Universal Dependencies (UD) oder Surface-Syntactic Universal Dependencies (SUD)),[3] in dem die Knoten nicht flektierte Lexeme sind (identifiziert durch ihre Lemmata), ergänzt durch einige morphologische Einschränkungen. In der Praxis muss der Baum nicht vollständig spezifiziert sein; insbesondere muss statischer Text nicht unbedingt Teil des Baums sein.
  4. Basierend auf einer sprachspezifischen Grammatikspezifikation erlauben die morphologischen Einschränkungen zusammen mit der Struktur des syntaktischen Baums die Flexion der Lemmata gemäß der auf Wikidata vorhandenen lexikalischen Daten oder anhand von Flexionstabellen der Grammatikspezifikation. Die Ausgabe dieses Schritts ist eine lineare Textsequenz, minimal mit Informationen zu Textteilen versehen (d. h. ob ein Wort ein Nomen, ein Verb, eine Präposition, etc. darstellt).
  5. In diesem Schritt werden phonotaktische Einschränkungen angewendet, die sprachspezifische Sandhi-Phänomene anwenden. Dazu kann die Auswahl kontextueller Formen zählen (z. B. in Englisch a/an) oder die Kontraktion/Zusammenfassung benachbarter Formen (z. B. in Französisch de + le = du).
  6. Im letzten Aufräumschritt müssen möglicherweise Leerzeichen, Großschreibung und Interpunktion angepasst werden, um den finalen Text so darzustellen, dass er in einem Wikipedia-Artikel gespeichert werden kann. Dieser Schritt kann auf eine sprachagnostische Weise modelliert werden, indem (sprachabhängige) Anmerkungen aus den vorherigen Schritten genutzt werden.

In der obigen Architektur gibt es drei Komponenten, die von Mitgliedern der Gemeinschaft verwaltet werden müssen:

  1. Vorlagen-Renderer - diese machen den größten Teil der erforderlichen Arbeit aus, da jeder Konstruktor einen Vorlagen-Renderer je Sprache benötigt (obwohl die Wiederverwendung von Renderern für Teile von Sätzen möglich ist). Beachte, dass der Begriff Renderer hier in einem engeren Sinn genutzt wird, als in Architektur für eine Multilinguale Wikipedia. In letzterem definiert der Begriff Renderer eine Ende-zu-Ende-Daten-zu-Text-Funktion, während wir hier den Begriff Renderer für eine bestimmte Komponente der NLG-Pipeline nutzen, nämlich eine Vorlage. Dies ist kein Zufall, da in der obigen Architektur die anderen Teile der Pipeline relativ fixiert sind und nicht dauernd durch Mitglieder der Gemeinschaft verwaltet werden müssen.
  2. Grammatikspezifikationen - diese müssten die relevanten morphologischen Funktionen, die für jede Sprache benötigt werden, ihre Hierarchie und wie diese sich selbst über Abhängigkeitsbeziehungen manifestieren, spezifizieren. Diese Spezifikationen können entweder in Wikidata oder als Funktionen in Wikifunctions gespeichert werden (noch zu entscheiden). Es ist wahrscheinlich, dass die Erstellung und Verwaltung dieser Grammatik grundlegendes linguistisches und technisches Wissen erfordert, da sie aber einmal pro (menschlicher) Sprache erstellt werden, wird dies als akzeptabel angesehen.
  3. Wikidata-Lexeme - diese werden wie heute verwaltet, jedoch wäre es wichtig, dass die von ihnen genutzt Funktionen mit den Grammatikspezifikationen ihrer Sprache in Einklang stehen.

Struktur von Vorlagen

Da der größte Teil der durch Beitragende aus der Gemeinschaft zu erledigenden Arbeit die Erstellung von Vorlagen-Renderern wäre, ist es wichtig, diese Aufgabe so einfach wie möglich zu machen und insbesondere zu verhindern, dass Coding-Erfahrung erforderlich ist.

Ähnlich wie die Kompositions“sprache” in Wikifunctions, können wir eine hauseigene Vorlagensprache entwickeln.[4] Die Vorlagensprache sollte die Angabe eines linguistischen Baums (mit UD-Anmerkungen) über drei Arten von Argumenten erlauben:[5]

  • Statischer Text
  • Terminalfunktionen, die Lemmata aus Wikidata abrufen oder bei Bedarf Lemmata aus anderen Argumenten erstellen (z. B. Nummern[6]).
  • Andere Renderer

Die Vorlagensprache wird ein spezielles Auswertungsmodul haben, das vom WF-Orchestrierer aufgerufen wird. Letzterer wird für die Übergabe der Ausgabe durch die unterschiedlichen Module der oben beschriebenen NLG-Pipeline verantwortlich sein.

Beispiel

Lass und annehmen, dass wir einen einfachen Konstruktor haben, der das Alter einer Person angibt:[7]

Age(
  Entity: Malala Yousafzai (Q32732)
  Age_in_years: 24
)

Um einen solchen Konstruktor für Englisch zu rendern, nutzen wir eine Vorlagennotation wie die folgende (die ein Z14/Implementierungstyp ist):

{
 "type": "implementation",
 "implements": "Age_renderer_en",
 "template": {
   "part": {
     "role": "subject",  # grammatical subject     
     "type": "function call",
     "function": "Resolve_Lexeme",
     "lexeme": {
        "reference": "Entity"
      }
    },
  "part": {
    "role": "root",  # root of the clause     
    "type": "function call",
    "function": "Resolve_Lexeme",
    "lexeme": {
        "value": "be"  # replace with L-id
      }
    },
  "part": {
    "role": "num",  # numerical modifier
    "of": 4,  # Part 4 (“year”)   
    "type": "function call",
    "function": "Cardinal_number",
    "number": {
        "reference": "age_in_years"  
      }
    },
   "part": {
    "role": "npadvmod", 
    "of": 5,  # Part 5 (“old”)
    "type": "function call",
    "function": "Resolve_Lexeme",
    "lexeme": {
        "value": "year"  # replace with L-id
      }
    },
  "part": {
    "role": "acomp",
    "type": "string",
        "value": "old"      
    },
}
}

Einige der syntaktischen Rollen (npadvmod, acomp) haben tatsächlich keine Vereinbarungswirkung und können somit ausgelassen werden.

Struktur von Grammatik

Die Gramatik muss die folgenden Informationen enthalten:

  1. Welche Wortarten die Sprache hat.
  2. Welche grammatikalischen Funktionen für jede Wortart angemessen sind.
  3. (Möglicherweise) eine Typenhierarchie der Funktionen.
  4. Wie grammatikalische Beziehungen (d. h. Abhängigkeitsbeziehungen) mit grammatikalischen Funktionen und Wortarten interagieren.

Beachte, dass die ersten Punkte aus den Wikidata-Lexemen abgeleitet werden können, die für eine bestimmte Sprache verfügbar sind. Es wäre jedoch hilfreich, sie explizit zu einem Teil einer Grammatikdefinition zu machen, die auch die Definitionen der Wikidata-Lexeme durchsetzen/validieren würde.[8] Man könnte einen solchen Prüfer je Sprache als WF-Funktion schreiben, der dann über die Wikidata-Lexeme laufen würde, um zu markieren, ob sie gemäß dem Schema der Sprache korrekt annotiert sind.

Was die grammatikalischen Beziehungen betrifft, können diese entweder als Daten in Wikidata oder als Funktionen in WF kodiert werden. Abhängigkeitsbeziehungen können als Vereinheitlichung grammatikalischer Funktionen ihrer Knoten implementiert werden. Man könnte jede Beziehung als eine WF-Kompositionsfunktion unter Verwendung des Unify-Operators als eingebaute Funktion implementieren. Beispielsweise würde eine "Subj"-Beziehung für ein englisches Wort wie folgt implementiert werden (unter Verwendung der Kurzschreibweise):

subj_en(noun, verb): 
    Unify(noun.pos, NOUN);  # Validate types
    Unify(verb.pos, VERB);
    Unify(noun.number, verb.number);
    Unify(noun.person, verb.person);
    Unify(noun.case, NOMINATIVE);

Beachte, dass die Subj-Funktion bei dieser Implementierung nicht rein funktional ist, da sie ihre Eingabe-Argumente beeinflusst (und der ausgegebene Wert tatsächlich nicht genutzt wird, sofern nicht ein Vereinheitlichungsfehler auftritt). Um die Dinge einfach zu halten, müsste dieses besondere Verhalten vom Funktionsauswerter unterstützt werden.

Möglicherweise möchte man Funktionen bündeln, die zusammen vereinheitlicht werden. Wenn wir beispielsweise beobachten, dass Zahl und Person häufig zusammen vereinheitlicht werden, können wir eine Unterfunktion wie die folgende definieren:

agr(left, right):
    Unify(left.number, right.number);
    Unify(left.person, right.person);

Dann können wir die subj-Beziehung von oben wie folgt neu definieren:

subj_en(noun, verb): 
    Unify(noun.pos, NOUN);  # Validate types
    Unify(verb.pos, VERB);
    agr(noun, verb);
    Unify(noun.case, NOMINATIVE);

Modularer Aufbau von Grammatik und Renderern

Häufig weisen Sprachen aus der gleichen Sprachfamilie grammatikalische und strukturelle Ähnlichkeiten auf. Dieses Phänomen kann genutzt werden, indem eine Hierarchie der Sprachen und Sprachfamilien definiert wird[9] und dem NLG-System erlaubt wird, die dynamische Bindung an die konkreteste Implementierung eines (Unter)-Renderers oder einer (Unter)-Beziehung zu nutzen.

Andere Ansätze

Bisher sind mir zwei andere Systeme bekannt, die für den Umgang mit der NLG der Abstrakten Wikipedia vorgeschlagen wurden.

  1. Grammatical Framework (GF) ist eine etablierte funktionale Programmiersprache, die die Generierung und das Verständnis natürlicher Sprache in unterschiedlichen Sprachen unterstützen soll (siehe Beschreibung im Newsletter). Sie besitzt eine blühende Gemeinschaft aus Informatikern, Linguisten und anderen Enthusiasten, die zu ihr beitragen.
  2. Ninai/Udiron ist ein Python-basiertes NLG-System, das vom Gemeinschaftsmitglied Mahir Morshed aufgebaut wurde. Es nutzt Lexem-Daten aus Wikidata und kombiniert diese über UD-Bäume. Das System wurde mit der Abstrakten Wikipedia im Hinterkopf entwickelt. Einige interessante Beispiele für Konstruktoren und dafür, wie diese gerendert werden, finden sich in der Ninai-Demonstration.

Obwohl beide Systeme unterschiedlich sind, können sie auf ähnliche Weise mit dem in diesem Dokument erläuterten Vorschlag verglichen werden:

  • Beide Systeme sind darauf ausgerichtet, relativ abstrakte und kompositorische semantische Darstellungen in grammatikalische Struktur und dann in Text umzuwandeln.
  • Sie erfordern die Beherrschung einiger Programmierkenntnisse, entweder eine domänenspezifische Sprache (GF) oder eine allgemeine Programmiersprache (Python).
  • Die Reihenfolge der Wörter im ausgegebenen Text wird von der gesamten NLG-Pipeline bestimmt (d.h. das Hinzufügen eines Frage-Operators könnte die Reihenfolge der Wörter in Englisch ändern).
  • Sofern die Grammatikdefinitionen korrekt sind, ist die Ausgabe garantiert grammatikalisch.

Der in diesem Dokument erläuterte Vorschlag ist hingegen speziell so konstruiert, dass Personen ohne vorheriges technisches Wissen möglichst einfach beitragen können. Das impliziert folgendes:

  • Es kann mit konkreten, nicht kompositorischen semantischen Darstellungen (wie dem Altersbeispiel oben) arbeiten. Das schließt allerdings nicht den Umgang mit abstrakteren Darstellungen aus.
  • Im Anfangsstadium sind nahezu keine Programmierkenntnisse erforderlich, um Vorlagen-Renderer zu schreiben. Linguistische Kenntnisse (insbesondere Abhängigkeitsannotationen) können hilfreich sein, um grammatikalische Ausgaben zu erreichen und sind erforderlich, um die Grammatikspezifikationen selbst zu schreiben.
  • Die Reihenfolge der Wörter wird durch die Vorlagen selbst bestimmt und wird nicht später in der Pipeline geändert.
  • Die Ausgabe kann ungrammatikalisch sein, wenn eine Vorlage nicht korrekt entwickelt wurde.

Fußnoten

  1. Die Frage, ob Rekursion in allen Sprachen existiert, wurde in den letzten Jahren hitzig diskutiert.
  2. Es kann nützlich sein, das Rendering des Konstruktors nominal (z. B. “Maries Heirat mit Pierre”) oder verbal (“Marie hat Pierre geheiratet”) zu erlauben. In diesem Fall wäre mehr als ein Renderer pro Konstruktor erforderlich.
  3. Der SUD-Formalismus ist einfacher und möglicherweise für NLG-Aufgaben besser geeignet. Osborne & Gerdes (2019) bieten eine Diskussion über die Mängel von UD. Siehe auch https://surfacesyntacticud.github.io/conversions/ für einen Vergleich der zwei Formalismen. In beiden Fällen müssen wir den Satz von Abhängigkeitsbeziehungen möglicherweise erweitern, um Muster abzubilden, die für NLG erforderlich sind, wie pronominale Querverweise.
  4. Die Vorlagensprache könnte so konzipiert werden, dass sie "syntaktischer Zucker" über der Kompositionssprache ist und somit möglicherweise vom gleichen Auswerter wie die Kompositionssprache ausgeführt werden könnte.
  5. Siehe das Plakat "Nutzung von Abhängigkeitsgrammatik zur Steuerung der Generierung natürlicher Sprache" (A. Gutman, A. Ivanov, J. Kirchner, 2019) sowie das zugehörige Arbeitspapier.
  6. Die Unicode-Bibliothek Common Locale Data Repository (CLDR) kann genutzt werden, um Kardinal- und Ordinalzahlen in unterschiedlichen Sprachen zu rendern sowie für andere Datentypen wie Datumsangaben.
  7. In der Praxis sollte das Alter vermutlich aus dem Geburtsdatum berechnet werden, aber für das Beispiel ist es im Konstruktor spezifiziert. Darüber hinaus können wir und einen dynamischen Konstruktor vorstellen, der einen Teil der Daten bei Bedarf errechnet.
  8. Derzeit gibt es keine konsistente Annotierung von Lexemen, nichtmal in einer einzigen Sprache. Beispielsweise ist die Form "has mit "dritte Person, Singular, Simple Present" annotiert, während die Form "is" mit "dritte Person, Singular, Präsens Indikativ" annotiert ist.
  9. Abhängig von der erforderlichen Granularität können die vorhandenen Hierarchie-Codes aus dem Standard ISO 639-5 genutzt werden oder wir können uns alternativ auf die vorhandene Sprach-Hierarchie verlassen, die in MediaWiki definiert ist.