ΕΛ/ΛΑΚ | creativecommons.gr | mycontent.ellak.gr |
freedom

Βρίσκοντας τις πιο κοντινές λέξεις για την Ελληνική γλώσσα ή εκπαιδεύοντας το Word2vec πάνω στην ελληνική Wikipedia

Θα χρησιμοποιήσουμε έναν κοινό υπολογιστή για να αναλύσουμε ένα μεγάλο μέρος του συνόλου των λέξεων της ελληνικής γλώσσας και να καταλήξουμε να βρούμε ποιές είναι οι πιο σχετικές/κοντινές στο νόημα λέξεις για κάθε λέξη.

Πχ βάζοντας παιδί θα βλέπουμε μπαμπάς, μαμά, αγόρι, κορίτσι, ενώ βάζοντας φασκόμηλο θα βλέπουμε ρίγανι, χαμομήλι. Στόχος μας είναι να φτιάξουμε ένα πολύ απλό παιχνίδι με ερωτήσεις και απαντήσεις.

Χωρίς να διαθέτουμε κάποιον υπερυπολογιστή και κυρίως χωρίς πληροφορίες για τη γλώσσα, όπως πληροφορίες που αφορούν τη δομή της, το λεξιλόγιο της και τα μέρη του λόγου, μέχρι πριν λίγα χρόνια θα φαινόταν εξωπραγματικό το πείραμα μας. Είναι όμως εφικτό σήμερα χάρη σε δυο λόγους:

α) τις μεγάλες εξελίξεις στο χώρο του Natural Language Processing, όπως η ανακάλυψη καινούργιων αλγορίθμων και τεχνικών ανάλυσης της γλώσσας
β) την ύπαρξη ενός μεγάλου σετ δεδομένων, ελεύθερα για χρήση, από την Ελληνική Wikipedia

Το πείραμα

Θα εφαρμόσουμε το μοντέλο Word2vec στο σετ δεδομένων της ελληνικής Wikipedia και θα παίξουμε λίγο με το τελικό αποτέλεσμα. Τα εργαλεία μας είναι το Gensim και λίγος κώδικας Python, input το σύνολο των άρθρων που έχουν γραφτεί μέχρι σήμερα στην ελληνική Wikipedia, ενώ το αποτέλεσμα θα είναι ένα αρχείο με ένα διανυσματικό χώρο αρκετών εκατοντάδων διαστάσεων, στον οποίο η κάθε λέξη που θα αναλύσουμε θα έχει και ένα διάνυσμα.
Ο τρόπος που το κάθε διάνυσμα είναι τοποθετημένος στον διανυσματικό αυτό χώρο είναι τέτοιος ώστε λέξεις που “μοιάζουν”, στο πλαίσιο στο οποίο έχουν χρησιμοποιηθεί, να βρίσκονται κοντά. Με πιο απλά λόγια το αρχείο αυτό θα περιέχει την ανάλυση των λέξεων που αναφέρονται στο σετ των δεδομένων μας.

Ένα μικρό πλαίσιο γύρω απο τα σχετικά θέματα:

  • σετ δεδομένων της ελληνικής Wikipedia
 

Η αγαπημένη μας ελεύθερη εγκυκλοπαίδεια Wikipedia δίνει σε καθημερινή βάση όλα τα άρθρα για καθεμία απο τις γλώσσες που υποστηρίζει, σε συμπιεσμένη μορφή. Τα κείμενα είναι σε mediawiki μορφή, οπότε θα χρειαστεί να αφαιρέσουμε το markup και να κρατήσουμε μόνο το κείμενο.

  • Word2vec

Είναι το πιο γνωστό μοντέλο word vectors(διανύσματα λέξεων), το οποίο κυκλοφόρησε το 2013. Ο σκοπός των word vectors είναι να δώσουν αριθμητικές απεικονήσεις για κάθε λέξη από ένα μεγάλο λεξικό της γλώσσας. Πρόκειται ουσιαστικά για μετάφραση λέξεων απή τη γλώσσα σε αριθμητική αναπαράσταση. Η απεικόνιση των λέξεων σε διανύσματα στο μοντέλο περιέχει πληροφορίες για το νόημα ή την ερμηνεία της κάθε λέξεις και τις σχέσεις της με τις υπόλοιπες λέξεις στο λεξικό.

Οι λέξεις με κοντινά διανύσματα έχουν σχετικά νοήματα και αυτό είναι κάτι που βρίσκει εφαρμογή σε θεματικές του Natural Language Processing όπως το Sentiment Analysis, Topic Modeling, Text classification.

Ένα πλεονέκτημα των μοντέλων με τα διανύσματα λέξεων είναι οτι λειτουργούν χωρίς επιτήρηση –fully unsupervised– μαθαίνουν δηλαδή τις σχέσεις και τα νοήματα αναλύοντας τεράστια σύνολα απο κείμενα, χωρίς να διαθέτουν άλλες πληροφορίες για τη γλώσσα.

  • Gensim

Είναι ένα από τα καλύτερα λογισμικά για τον τομέα του NLP, είναι ανοιχτό λογισμικό και είναι γραμμένο στην Python — https://github.com/RaRe-Technologies/gensim

Φτιάχνοντας το περιβάλλον μας

Ξεκινάμε φτιάχνοντας το περιβάλλον στο οποίο θα δουλέψουμε, το δικό μου είναι ένα Ubuntu 16.04 σύστημα με 8 CPU και 32 GB RAM.

Κάνουμε update και εγκαθιστούμε τα απαραίτητα πακέτα

root@second ~ # apt-get update; apt-get upgrade -y
root@second ~ # apt-get install -y gcc python3-pip python3-dev vim htop

Κάνουμε update το pip (python package manager) και εγκαθιστούμε το gensim

root@second ~ # pip3 install --upgrade pip
root@second ~ # pip3 install setuptools
root@second ~ # pip3 install ipython gensim

φτιάχνουμε ένα directory για να δουλεύουμε

root@second ~ # mkdir word2vec-wiki
root@second ~ # cd word2vec-wiki

φέρνουμε το συμπιεσμένο αρχείο για το ελληνικό Wikipedia

root@second ~/word2vec-wiki # wget https://dumps.wikimedia.org/elwiki/latest/elwiki-latest-pages-articles.xml.bz2

Το αρχείο που κατέβασα ήταν 276MB.

Εκπαιδεύοντας ένα Word2vec μοντέλο με το Gensim

Με ipython εκτελούμε τις εντολές:

root@second ~/word2vec-wiki # ipython
import logging
import multiprocessing
from gensim.corpora import WikiCorpus, MmCorpus
from gensim.models.word2vec import Word2Vec
logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO)
# για να μας δείχνει χρήσιμα logs
wiki = WikiCorpus("/root/word2vec-wiki/elwiki-latest-pages-articles.xml.bz2",lemmatize=False, dictionary={})
2018-03-04 17:40:12,622 : INFO : adding document #0 to Dictionary(0 unique tokens: [])
...
2018-03-04 17:43:38,341 : INFO : built Dictionary(1301633 unique tokens: ['mocca', 'dupka', 'λαϊζάν', 'περισέλληνο', 'σημειοσυνόλου']...) from 131991 documents (total 63111075 corpus positions)

αυτό πήρε 4 λεπτά.

Το αρχείο έχει όλα τα άρθρα στην mediawiki μορφή και εδώ φτιάχνει ένα corpus (σώμα κειμένων) το οποίο περιέχει τα κείμενα, όπου κάθε κείμενο είναι μια σελίδα της Wikipedia για ένα θέμα. Το corpus αυτό είναι ένα αντιπροσωπευτικό σύνολο κειμένων το οποίο θα χρησιμοποιηθεί σαν δείγμα για την ανάλυση που θα γίνει στις λέξεις.

Για να δούμε τι περιέχει αυτό

In [4]: wiki
Out[4]: <gensim.corpora.wikicorpus.WikiCorpus at 0x7fb993b92748>
In [5]: for a,b in enumerate(wiki.get_texts()):
   ...:     if a < 4:
   ...:         print(b)
   ...:     break
['αθλητισμός', 'είναι', 'συστηματική', 'σωματική', 'καλλιέργεια', 'και', 'δράση', 'με', 'συγκεκριμένο', 'τρόπο', 'ειδική', 'μεθοδολογία', 'και', 'παιδαγωγική', 'με', 'σκοπό', 'την', 'ύψιστη', 'σωματική', 'απόδοση', 'ως', 'επίδοση', 'σε', 'αθλητικούς', 'αγώνες', 'στο', 'αθλητικό', 'και', 'κοινωνικό', 'γίγνεσθαι', 'παράλληλα', 'αθλητισμός', 'είναι', 'ένας', 'κοινωνικός', 'θεσμός', 'οποίος', 'αντικατοπτρίζει', 'τη', 'δεδομένη', 'κοινωνία', 'και', 'τον', 'πολιτισμό', 'της', 'για', 'παράδειγμα', 'στην', 'αρχαία', 'ελλάδα', 'αθλητισμός', 'στην', 'αθήνα', 'θεωρούταν', 'κοινωνικό', 'και', 'πολιτισμικό', 'αγαθό', 'και', 'είχε', 'παιδαγωγικό', 'χαρακτήρα', 'ενώ', 'αντίθετα', 'στην', 'σπάρτη', 'αθλητισμός', 'χρησιμοποιούταν', 'για', 'την', 'στρατιωτική', 'εκπαίδευση', 'ωστόσο', 'σημαντική', 'είναι', 'στρωματική', 'διάσταση', 'του', 'αθλητισμού', 'στο', 'πέρασμα', 'του', 'χρόνου', 'γενική', 'τάση', 'ήταν', 'ιδίως', 'τον', 'και', 'αιώνα', 'τα', 'κατώτερα', 'κοινωνικά', 'στρώματα', 'να', 'ασχολούνται', 'με', 'τα', 'λαικα', 'παιχνίδια', 'όπως', 'το', 'ποδόσφαιρο', 'ενώ', 'τα', 'ανώτερα', 'κοινωνικά', 'στρώματα', 'με', 'τα', 'ευγενή', 'αθλήματα', 'όπως', 'ήταν', 'ιππασία', 'και', 'ξιφασκία', 'αρχείο', 'hermes', 'logios', 'altemps', 'jpg', 'thumb', 'ερμής', 'μυθολογία', 'προστάτης', 'του', 'αθλητισμού', 'ωστόσο', 'πρέπει', 'να', 'διαχωριστεί', 'έννοια', 'της', 'άθλησης', 'από', 'την', 'έννοια', 'της', 'άσκησης', 'άσκηση', 'γίνεται', 'άθληση', 'όταν', 'αποκτά', 'ανταγωνιστικό', 'χαρακτήρα', 'για', 'παράδειγμα', 'ένας', 'που', 'τρέχει', 'στο', 'δρόμο', 'ασκείται', 'ωστόσο', 'άν', 'έχει', 'κάποιον', 'αντίπαλο', 'ώστε', 'για', 'το', 'ποιος', 'θα', 'τερματίσει', 'πρώτος', 'ακόμα', 'κι', 'αν', 'ανταγωνίζεται', 'τον', 'ίδιο', 'του', 'τον', 'εαυτό', 'με', 'το', 'χρονόμετρο', 'αθλείται', 'επίσης', 'πρέπει', 'να', 'προστεθεί', 'και', 'έννοια', 'της', 'κίνησης', 'αθλητισμός', 'μπορεί', 'να', 'πάρει', 'πέντε', 'μορφές', 'είτε', 'ως', 'ερασιτεχνικός', 'είτε', 'ως', 'επαγγελματικός', 'είτε', 'ως', 'μαζικός', 'αθλητισμός', 'είτε', 'ως', 'φυσικές', 'δραστηριότητες', 'είτε', 'με', 'την', 'μορφή', 'των', 'παιχνιδιών', 'υπάρχουν', 'τρεις', 'θεωρίες', 'σχετικά', 'με', 'τη', 'γένεση', 'του', 'αθλητισμού', 'όλες', 'οι', 'αθλητικές', 'ασκήσεις', 'έχουν', 'λατρευτικές', 'ρίζες', 'carl', 'diem', 'οι', 'σωματικές', 'ασκήσεις', 'είναι', 'φυσική', 'συνέπεια', 'των', 'διαδικασιών', 'της', 'εργασίας',

είναι ένα σύνολο απο python lists στο οποίο το κάθε list αντιπροσωπεύει ένα άρθρο του Wikipedia, στο οποίο έχει αφαιρεθεί η markup, έχουν αφαιρεθεί διάφορα άλλα στοιχεία της γλώσσας (όπως κόμματα, τελείες κτλ) και όλες οι λέξεις είναι με μικρά γράμματα.

In [6]: sentences = list(wiki.get_texts())
2018-03-04 17:49:12,964 : INFO : finished iterating over Wikipedia corpus of 131991 documents with 63111075 positions (total 303219 articles, 63672063 positions before pruning articles shorter than 50 words)

αυτό πήρε άλλα 4 λεπτά

In [7]: len(sentences)
131991

Το corpus μας έχει 131.991 κείμενα (όσες και οι σελίδες στο Wikipedia)

το wiki έχει μετατραπεί σε python λίστα και είναι έτοιμο να περάσει στον Word2vec αλγόριθμο τον οποίο υλοποιεί το Gensim

In [8]: params = {'size': 200, 'window': 10, 'min_count': 10,'workers': max(1, multiprocessing.cpu_count() -1), 'sample': 1E-3,}
In [9]: word2vec = Word2Vec(sentences, **params)
2018-03-04 17:51:39,552 : INFO : collecting all words and their counts
2018-03-04 17:57:40,009 : INFO : training on a 315555375 raw words (245385357 effective words) took 331.0s, 741397 effective words/s
In [10]: word2vec.wv.save_word2vec_format('model')

αυτό πήρε 8 λεπτά και το αποτέλεσμα το σώζουμε στο αρχείο ‘model’ για να το κάνουμε load κάθε φορά που θέλουμε και να μην χρειάζεται να το ξανα-υπολογίζουμε.

Το μοντέλος μας ‘model’ είναι η εφαρμογή του αλγορίθμου του gensim

Αν δοκιμάσουμε να ανοίξουμε το αρχείο αυτό θα δούμε οτι περιέχει μια μεγάλη λίστα απο διανύσματα για κάθε λέξη, πχ

root@second ~/word2vec-wiki # ls -lh model 
-rw-r--r-- 1 root root 376M Feb 16 15:37 model
root@second ~/word2vec-wiki # less model
...
σάμος -1.377902 -0.502284 -1.725532 1.610379 0.000059 -1.113552 1.012219 -0.849380 -0.692436 0.275749 0.594147 -1.283388 0.371137 -1.118496 1.026632 -0.293938 2.056278 0.980091 -0.150985 0.520737 1.067245 -0.203645 -1.076626 -0.917293 0.727399 -2.126547 -1.331171 -0.557430 -0.120140 -1.679607 -1.214803 -0.235743 1.117850 0.036515 -1.112181 -1.025965 1.658404 0.213739 0.003557 -0.144658 -0.696650 -2.392424 -1.045619 0.847903 -1.828993 0.539993 0.123133 0.303936 
...

Αυτό δεν παρέχει καμιά πληροφορία για μας, είναι όμως η γλώσσα την οποία μπορεί να καταλάβει ο υπολογιστής.

In [11]: from gensim.models import KeyedVectors
In [14]: model = KeyedVectors.load_word2vec_format('model')
2018-03-04 18:00:49,492 : INFO : loading projection weights from model

Ενδιαφέροντα αποτελέσματα

Ας δούμε τι αποτέλεσμα έχει παραχθεί.

Το κλασικό παράδειγμα στα Word2vec μοντέλα είναι η εύρεση της λέξης που ταιριάζει στην ερώτηση ‘άντρας->βασιλιάς, γυναίκα-> ???’ Η λέξη που ψάχνουμε είναι το αντίστοιχο για τη γυναίκα, όπως ο βασιλιάς για τον άντρα. Το Gensim έχοντας το εκπαιδευμένο μοντέλο μας θα μας δώσει την απάντηση με αυτό τον τρόπο:

In [16]: model.most_similar(positive=['γυναίκα', 'βασιλιάς'], negative=['άντρας'])
2018-03-04 18:02:14,306 : INFO : precomputing L2-norms of word weight vectors
Out[16]: 
[('βασίλισσα', 0.6089198589324951),
 ('βασιλιά', 0.5953291654586792),
 ('σύζυγο', 0.5802819132804871),
...

Το αποτέλεσμα είναι εντυπωσιακό! Η πιο σχετική λέξη που βρήκε σε αυτό το ερώτημα ήταν και η σωστή. Δίπλα σε κάθε λέξη είναι η πιθανότητα που δίνει το μοντέλο για την κάθε λέξη.

In [22]: model.most_similar(positive=['αγόρι', 'μπαμπάς'], negative=['μαμά'])
Out[22]: 
[('κορίτσι', 0.7002422213554382),
 ('μωρό', 0.6980640888214111),
 ('κοριτσάκι', 0.6687779426574707),
 ('τρελό', 0.6575441360473633),
 ('σκυλί', 0.6574292182922363),
 ('παιδάκι', 0.6519930362701416),
 ('σκυλάκι', 0.6386491656303406),

Και εδώ τα αποτελέσματα είναι πολύ πετυχημένα.

In [82]: model.most_similar(['αγόρια', 'κορίτσια'])
Out[82]: 
[('παιδιά', 0.7597203850746155),
 ('μωρά', 0.716261625289917),
 ('ορφανά', 0.6735644340515137),
 ('δίδυμα', 0.6693589091300964),
 ('παιδάκια', 0.6521530151367188),

Το Gensim έχει πολύ χρήσιμες συναρτήσεις όπως η most_similar, στην οποία περνάμε είτε strings είτε list με strings.

In [83]: model.most_similar('ποδήλατο')
Out[83]: 
[('τρέξιμο', 0.6936282515525818),
 ('περπάτημα', 0.6569424867630005),
 ('κολύμπι', 0.6434358358383179),
 ('έλκηθρο', 0.6299928426742554),
 ('σκι', 0.6249086856842041),
 ('σχοινί', 0.6115301847457886
In [85]: model.most_similar('δένδρο', topn=100)
Out[85]: 
[('δέντρο', 0.8690638542175293),
 ('έντομο', 0.7177870869636536),
 ('φυτό', 0.7136266231536865),
 ('ψάρι', 0.7057873606681824),
 ('άνθος', 0.7005383372306824),
 ('θηλαστικό', 0.6950464248657227),
 ('αυγό', 0.6883149743080139),
 ('όστρακο', 0.6804207563400269),
 ('ζώο', 0.6773611307144165),
 ('αρπακτικό', 0.6737581491470337),
...

Ενδιαφέρουσα και η συνάρτηση doesnt_match όπου βρίσκει ποιά λέξη δεν ταιριάζει

In [86]: model.doesnt_match('πρωινό βραδινό δημητριακά μεσημεριανό'.split())
Out[86]: 'δημητριακά'
In [87]: model.doesnt_match('πορτοκάλια μήλα φράουλες φασκόμηλο'.split())
Out[87]: 'φασκόμηλο'
In [88]: model.doesnt_match('κάπνισμα περπάτημα κολύμπι ποδήλατο'.split())
Out[88]: 'κάπνισμα'

Σε επόμενο άθρο θα παρουσιαστεί το παιχνίδι που παράχθηκε μέσα απο αυτή τη διαδικασία, το οποίο έχει ανέβει στο www.wordgames.gr

Αuthor: Markos Gogoulos Software Engineer based in Athens Greece, co-founder of https://mist.io , member of https://plagiari.sm . Interested in IT Security, Devops, Education

Πηγή άρθρου: https://medium.com/@mgogoulos

Leave a Comment

Social Media Auto Publish Powered By : XYZScripts.com