Aufbauseminar, Universität Düsseldorf, SoSe 2018
Ziel der praktischen Sitzungen ist, dass ihr in Gruppen von 1-3 Personen zunächst einen einfachen semantischen Parser für die GeoQuery-Domäne implementiert, entsprechend den Vorgaben in der Einführung. In der zweiten Hälfte des Semesters sollt ihr diesen Parser dann verbessern und erweitern.
Eine Basis für GeoPar habe ich unter https://github.com/texttheater/geopar bereits gelegt. Ladet diesen Code zunächst über den grünen Button herunter. (Wenn du dich mit Git/GitHub bereits auskennst, kannst du auch gleich deinen eigenen Fork erstellen und klonen.)
Wichtig ist hier vor allem das Modul terms
, das es ermöglicht,
GeoQuery-Ausdrücke als Python-Objekte zu verarbeiten. Über das Modul
data
erhältst du bequemen Zugriff auf die Trainings- und
Testdaten.
Um NLUs in MRs übersetzen zu können, braucht GeoPar geeignete
Lexikoneinträge im Modul lexicon
. Zum Beispiel:
answer(A, (city(A), loc(A,B), const(B, stateid(virginia))))
Hierfür werden folgende lexikalische MRs benötigt:
city(_)
loc(_, _)
const(_, stateid(virginia))
Mit jeder dieser lexikalischen MRs muss also mindestens ein (Multi)wort aus
dem Satz im Lexikon assoziiert sein. In diesem Fall ist dieses NLU-MR-Paar
lexikalisch abgedeckt. Der Unit-Test in test_lexical_coverage.py
überprüft die lexikalische Abdeckung für jedes NLU-MR-Paar in den
Trainingsdaten. Führe ihn aus:
$ python3 -m unittest test_lexicon
Du wirst feststellen, dass die lexikalische Abdeckung bisher äußerst gering ist, denn das Lexikon besteht bisher nur aus drei Beispieleinträgen.
Deine Aufgabe für die ersten beiden praktischen Sitzungen: Erweitere
lexicon.py
so, dass die gesamten Trainingsdaten abgedeckt sind und
mit den lexikalischen MRs möglichst die richtigen (Multi)wörter assoziiert
werden, also z.B. für city(_, _)
nicht gerade in, sondern
besser cities. Überlege dir, wie man das machen könnte. Einträge für die
Staaten und Städte der USA kann man zum Beispiel automatisiert erstellen.
Unser nächstes Zwischenziel ist das Implementieren des Parsing-Algorithmus.
Zentral ist dabei die Definition einer Python-Klasse ParseItem
im Modul parseitems
,
deren Objekte Parsing-Items repräsentieren (vgl. wiederum das Vorlesungsskript
aus der Einführungssitzung). Diese Klasse sollte für jeden Typ von
Parsing-Aktion eine Methode haben (skip
, shift
,
coref
, drop
, lift
, finish
,
idle
), die (aufgerufen mit entsprechenden Argumenten) das
jeweilige Nachfolge-Item zurückgibt.
Wenn du das implementiert hast, sollte es möglich sein, mit dem initialen Item für eine NLU zu beginnen und durch das wiederholte Aufrufen der richtigen Methoden ein Item zu erhalten, das die gewünschte MRL enthält (vgl. z.B. das Beispiel in Table 1 in der Einführung). Das aktuelle Git-Repositorium enthält hierfür einen Test, den du wie folgt ausführen kannst:
$ python3 -m unittest test_parseitems
test_parseitems.py
an, um zu sehen, wie sich das parseitems
-Modul verhalten sollte.terms
-Bibliothek wurde aktualisiert. Die Term-Objekte haben jetzt eine replace
-Methode, mit der man eine Variable durch einen anderen Term ersetzen kann. Das brauchst du für die coref
-Aktion.lstack
(neu im Git-Repositorium) stellt eine Prolog-Listen ähnliche Datenstruktur zur Verfügung, die für das Implementieren von Stack und Queue nützlich sein kann.parsestacks
findest du die Klasse StackElement
. Der Stack in Parsing-Items sollte aus Objekten dieser Klasse bestehen. Die integrate
-Methode der StackElement
-Klasse sollte das Implementieren von drop
und lift
deutlich vereinfachen.