[PYTHON] [Japanische Version] Beurteilung der Wortähnlichkeit für Polynomwörter mit ELMo und BERT

Überblick

Verarbeitungsmodelle für natürliche Sprachen wie ELMo und BERT bieten kontextsensitive wortverteilte Darstellungen. Sie können erwarten, unterscheiden zu können, welche Bedeutungen in Sätzen mit Polynomwörtern verwendet werden, die mehrere Bedeutungen haben. Zuvor veröffentlichte Artikel

Anschließend haben wir anhand der englischen Version von ELMo und BERT überprüft, ob das Wort "richtig" die drei Bedeutungen "richtig", "richtig" und "richtig" unterscheiden kann. Dieses Mal werden wir die japanische Version von vorgelernten ELMo und BERT verwenden, um ein ähnliches Experiment mit japanischen Polynomwörtern durchzuführen.

Sowohl ELMo als auch BERT, die auf Japanisch vorgelernt wurden, verwenden das von Stockmark veröffentlichte Modell.

Problemstellung

In der englischen Version des Experiments habe ich die drei Bedeutungen von "richtig" unterschieden, aber ich konnte kein gutes Beispiel mit drei oder mehr Bedeutungen auf Japanisch finden, daher werde ich mehrere Polynomwörter mit zwei Bedeutungen betrachten. Insgesamt werden 32 Beispielsätze verwendet, wobei 4 Sätze für jede Bedeutung der vier Polynomwörter "ziemlich", "respektlos", "unschuldig" und "Hals" verwendet werden. Die meisten Beispielsätze stammen aus Wörterbüchern in japanischer Sprache im Internet, und einige von ihnen wurden geändert.

Ich habe zum ersten Mal einen Keks gemacht, aber es war nicht schwierig und ich finde es ziemlich lecker. `` Er sagt es nicht, aber es ist ihm sehr wichtig, klein zu sein. `Das Restaurant dort ist billig, aber sehr lecker. `Es gibt ziemlich viele Leute, die sich nach der Toilette nicht die Hände waschen. ``

Ich habe genug. Mehr ist in Ordnung. `` »Das musst du nicht tun. `` Zu diesem Zeitpunkt entschied ich, dass das Land nicht genutzt werden würde, und ich wusste, dass es in Ordnung wäre, wenn ich um Geld bitten könnte. `` Im Gegensatz zu anderen Menschen kann der Lehrer beim Spielen arbeiten, also ist es in Ordnung. ``

»Letzte Nacht war ich enttäuscht, Ihnen etwas Unansehnliches zu zeigen. `Haben Sie insgesamt das Gefühl, dass Sie so etwas Respektloses sagen? Er äußerte respektlose Bemerkungen, aber er ging am Arbeitsplatz nicht gut und kündigte sofort. `` Was sagst du? Sei nicht respektlos. Hier kommst du nicht hin. geh zurück! ``

»Ich war ein wenig enttäuscht vom Bücherregal meines Bruders. »Dieser Kugelschreiber tut mir leid. Ein Student missachtete den Hut des Polizisten und rannte auf einen Blick los. Â »Als er ging, respektierte er den Brief, der nicht im Besitz war, vom Tisch.

Während man die Brillanz des Mondes unschuldig betrachtete, wurde in Tengo so etwas wie eine Erinnerung aus der Antike hervorgerufen. „Und ich wollte denken, wenn ich diese Bemühungen unschuldig fortsetzen würde, würde dies letztendlich zu einem Durchbruch führen. Ein Reh spielt unschuldig im Feuer über dem Sukinohana und in der funkelnden rotbraunen Erektion. `` Das Rauschen der Wellen traf den ganzen Tag instinktiv die Felsenecken am Ufer, zerquetscht und bespritzt. ``

Sobald ich dies besuchte und mich über das Schwingen erkundigte, gab mir der Ehemann meiner Schwester 300 Yen. Zu dieser Zeit stand eine Frau mit einem säugenden Baby am Tor und bat um Unschuld. Die Mutter des verhafteten Mannes gab im Interview bekannt, dass der Verdächtige am Tag zuvor angegriffen worden war. Das Ergebnis war, dass Kotaro einen Unschuldsbrief erhielt und gezwungen war, die Straße von Ichiri zu seinem alten Vater zu benutzen.

Ich binde mir immer die Haare, weil sie mir beim Quetschen im Nacken im Weg stehen. `` Lachen Sie mit angespannter Stimme, während Sie sich zurücklehnen. `Am Kragen der Kleidung befand sich eine weiße Dekoration, wahrscheinlich um die Schönheit des langen Halses zu verstärken. Der Angestellte runzelte ein wenig die Stirn, dachte nach und schüttelte dann höflich den Kopf. ``

Arbeitnehmer, die aufgrund von Arbeitsunfällen in Urlaub sind, können nicht entlassen werden. `` Dieses Projekt hat die Leiter jedes einzelnen Teams. `Wenn Sie nicht gefeuert werden wollen, erzielen Sie Ergebnisse! `Ich wurde aus der Firma entlassen, aber ich konnte es meiner Familie nicht sagen und gab vor, jeden Tag in die Firma zu gehen und Zeit im Park zu verbringen. ``

Ich denke, dass es üblich ist, "Kubi" in Katakana für die Bedeutung B von "Hals" zu schreiben, aber ich schreibe es in Kanji, um es zum gleichen Ausdruck wie A zu machen.

Geben Sie diese Beispielsätze in ELMo und BERT ein, um den eingebetteten Vektor des Zielworts und die Kosinusähnlichkeit zwischen den Vektoren zu extrahieren.

cossim(\mathbf{u} ,\mathbf{v} ) = \frac{\mathbf{u} \cdot \mathbf{v}}{|\mathbf{u}| \, |\mathbf{v}|}

Um zu überprüfen, ob Wörter mit derselben Bedeutung einander ähnlicher sind.

Implementierung

Die Berechnung wurde im Google-Labor durchgeführt. TensorFlow verwendet die Version 1.x-Serie.

Vorbereitung

Importieren Sie die erforderlichen Bibliotheken und mounten Sie Google Drive.

import json
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns

#Bibliothek zur Verwendung von Japanisch mit matplotlib
!pip install japanize_matplotlib
import japanize_matplotlib

#Mounten Sie Google Drive
from google.colab import drive
drive.mount('/content/drive')

Das Stockmark-Vorlernmodell verwendet das MeCab + NEologd-Wörterbuch als Tokenizer. Das Installationsverfahren ist wie in [diesem Artikel] beschrieben (https://qiita.com/jovyan/items/bdfd3c660173be20932a), aber ich werde es erneut veröffentlichen.

#MeCab-Installation
!apt install aptitude swig
!aptitude install mecab libmecab-dev mecab-ipadic-utf8 git make curl xz-utils file -y

#Installation des NEologd-Wörterbuchs
%cd /content
!git clone --depth 1 https://github.com/neologd/mecab-ipadic-neologd.git
%cd mecab-ipadic-neologd
!echo yes | ./bin/install-mecab-ipadic-neologd -n

#Installieren Sie die Bibliothek, um MeCab in Python aufzurufen
!pip install mecab-python3
!pip install unidic-lite  #Ohne diesen Mecab-Beim Ausführen von python3 wird eine Fehlermeldung angezeigt
import MeCab

Die Arbeit wird im Verzeichnis / content / drive / 'My Drive' / synonym_classification erledigt.

%cd /content/drive/'My Drive'/synonym_classification

Bereiten Sie als Nächstes eine Liste der zu verwendenden Beispielsätze vor.

target_words = ["sehr gut", "Respektlosigkeit", "Unschuldig", "Hals"]

texts1 = ["Ich habe zum ersten Mal einen Keks gemacht, aber es war nicht schwierig und ich finde es ziemlich lecker.", 
          "Er sagt nichts, aber es ist ihm sehr wichtig, klein zu sein.", 
          "Das Restaurant dort ist billig, aber sehr lecker.", 
          "Es gibt ziemlich viele Leute, die sich nach der Toilette nicht die Hände waschen.", 
          "Ich habe genug. Mehr ist in Ordnung.", 
          "Das musst du nicht tun.", 
          "Zu diesem Zeitpunkt entschied ich, dass das Land nicht genutzt werden würde, und ich wusste, dass es in Ordnung wäre, wenn ich um Geld bitten könnte.", 
          "Trotzdem geht es dem Lehrer im Gegensatz zu anderen Menschen gut, weil er beim Spielen arbeiten kann."]

texts2 = ["Letzte Nacht war ich enttäuscht, Ihnen etwas Unansehnliches zu zeigen.", 
          "Haben Sie insgesamt das Gefühl, dass Sie so etwas Respektloses sagen?", 
          "Er wurde mit respektlosen Bemerkungen geäußert, aber er ging am Arbeitsplatz nicht gut und kündigte sofort.", 
          "Was sagst du Sei nicht respektlos. Hier kommst du nicht hin. geh zurück!", 
          "Ich war ein wenig enttäuscht vom Bücherregal meines Bruders.", 
          "Es tut mir leid für diesen Kugelschreiber.", 
          "Ein Student missachtete den Hut des Polizisten und rannte auf einen Blick los.", 
          "Nun, als er ging, respektierte er den Brief, der nicht sein eigener war, vom Tisch."]

texts3 = ["Während man die Brillanz des Mondes betrachtete, wurde in Tengo an so etwas wie eine Erinnerung erinnert, die aus alten Zeiten überliefert wurde.", 
          "Das Rauschen der Wellen traf den ganzen Tag instinktiv die Felsen am Ufer, zerquetscht und bespritzt. ..", 
          "Und ich wollte denken, wenn ich diese Bemühungen unschuldig fortsetzen würde, würde dies letztendlich zu einem Durchbruch führen.", 
          "Hirsche spielen unschuldig im Feuer von Sukinohana und der funkelnden rotbraunen Erektion.", 
          "Sobald ich diesen Ort besuchte und mich über das Schwingen erkundigte, gab mir der Ehemann meiner Schwester 300 Yen.", 
          "Zu dieser Zeit stand eine Frau mit einem säugenden Baby am Tor und bat um ihre Unschuld.", 
          "Die Mutter des verhafteten Mannes erzählte dem Interview, dass der Verdächtige am Tag zuvor angegriffen worden war.", 
          "Infolgedessen erhielt Kotaro einen Unschuldsbrief und musste die Straße von Ichiri zu seinem alten Vater benutzen.", ]
          
texts4 = ["Ich binde mir immer die Haare, weil sie mir beim Quetschen im Nacken im Weg stehen.", 
          "Er lacht mit angespannter Stimme, während er den Kopf zurückbeugt.", 
          "Am Kragen der Kleidung befand sich eine weiße Dekoration, wahrscheinlich um die Schönheit des langen Halses zu betonen.", 
          "Der Angestellte runzelte ein wenig die Stirn, dachte nach und schüttelte dann höflich den Kopf.", 
          "Arbeitnehmer, die aufgrund von Arbeitsunfällen in Urlaub sind, können nicht entlassen werden.", 
          "Das Projekt hängt von jedem einzelnen Team ab.", 
          "Wenn Sie nicht gefeuert werden möchten, erzielen Sie Ergebnisse!", 
          "Er wurde aus der Firma entlassen, aber er konnte es seiner Familie nicht sagen und verbrachte jeden Tag im Park, als würde er ins Büro gehen."]

Da Sie eine Datei in BERT eingeben müssen, schreiben Sie sie in eine Textdatei.

with open('texts1.txt', mode='w') as f:
  f.write('\n'.join(texts1))
with open('texts2.txt', mode='w') as f:
  f.write('\n'.join(texts2))
with open('texts3.txt', mode='w') as f:
  f.write('\n'.join(texts3))
with open('texts4.txt', mode='w') as f:
  f.write('\n'.join(texts4))

Da die Eingabe in ELMo im Voraus tokenisiert werden muss, bereiten Sie eine Tokenizer-Funktion vor und tokenisieren Sie jeden Satz.

def mecab_tokenizer(texts, 
                    dict_path="/usr/lib/x86_64-linux-gnu/mecab/dic/mecab-ipadic-neologd"):
  mecab = MeCab.Tagger("-Owakati -d " + dict_path)
  token_list = []
  for s in texts:
      parsed = mecab.parse(s).replace('\n', '')
      token_list += [parsed.split()]
  return token_list
token_list1 = mecab_tokenizer(texts1)
token_list2 = mecab_tokenizer(texts2)
token_list3 = mecab_tokenizer(texts3)
token_list4 = mecab_tokenizer(texts4)

Der Inhalt von token_list1 ist wie folgt.

['Zum ersten Mal', 'Plätzchen', 'Zu', 'Herstellung', 'Ta', 'aber', '、', 'Schwer', 'Nicht', 'Ta', 'Shi', '、', 'sehr gut', 'おいShiく', 'Machen', 'Ta', 'Wann', 'Überlegen', '。']
['er', 'Ist', 'Mund', 'Zu', 'Ist', 'Ausgegeben', 'Abwesend', 'aber', '、', 'Zurück', 'Aber', 'klein', 'Ding', 'Zu', 'Zu', 'sehr gut', 'Qi', 'Zu', 'Shi', 'Hand', 'ich', 'Masu', '。']
['da drüben', 'von', 'Restaurant', 'Ist', '、', 'billig', 'vonに', 'sehr gut', 'Köstlich', 'Hmm', 'ist', 'Yo', '。']
['Toilette', 'von', 'nach', 'damit', '、', 'Hand', 'Zu', 'Gewaschen', 'Abwesend', 'Mann', 'Ist', 'sehr gut', 'Viele', 'ich', 'Masu', '。']
['Bereits', 'ausreichend', 'Was', 'Besser', 'Ta', '。', 'Dies', 'das ist alles', 'Ist', 'sehr gut', 'ist', '。']
['Eine solche', 'Ding', 'Bis', 'Shi', 'Hand', 'Ist es', 'Ohne', 'Hand', 'Ebenfalls', 'sehr gut', 'ist', '。']
['Dies', 'Wann', 'Zu', 'Ist', 'Land', 'Ist', 'Ist es', 'Abwesend', 'Ding', 'Zu', 'Shi', 'Hand', '、', 'Geld', 'damit', 'Bitte', 'Aber', 'damitき', 'Masure', 'Wenn', 'sehr gut', 'Ist', 'Wann', 'Ich kenne', 'Hand', 'ich', 'Ta', 'von', 'damit', 'ござich', 'Masu', 'Aber', '。']
['Immer noch', '、', 'Lehrer', 'Ist', 'Andere', 'von', 'Mann', 'Wann', 'Anders', 'Hand', '、', 'abspielen', 'Während', 'Job', 'Aber', 'Tun können', 'vondamit', 'sehr gut', 'damit', 'Vielen Dank', 'Masu', '。']

Das Zielwort muss als einzelnes Token getrennt werden, um Polynomwörter zu bestimmen, aber es ist wahr, dass "ganz" ein Token in jedem Satz ist. Andere Zielwörter könnten ebenfalls mit einem Token versehen werden. Tatsächlich war es diesmal am schwierigsten, ein Polynomwort auszuwählen, das diese Bedingung erfüllt.

Eigentlich wollte ich die Ergebnisse mit anderen vorgelernten japanischen BERTs zusätzlich zum Aktienmarkenmodell vergleichen, aber mit anderen Wörterbüchern als dem NEologd-Wörterbuch wird beispielsweise "OK" zu einem Token oder WordPiece Beim Tokenisieren mit oder Satzstück wurden "Yui" und "Struktur" getrennt, und die Aufgabe der Unterscheidung von Polynomwörtern konnte nicht ausgeführt werden. Aus diesem Grund vergleichen wir diesmal nur vorgefertigte ELMo und BERT von Stockmark.

ELMo Das ELMo-Modell verwendet diese Implementierung (https://github.com/HIT-SCIR/ELMoForManyLangs) mit vorgefertigten Standardparametern. Wie man diesen Artikel benutzt, den ich vorher geschrieben habe

Ist das gleiche wie.

!pip install overrides
!git clone https://github.com/HIT-SCIR/ELMoForManyLangs.git
%cd ./ELMoForManyLangs
!python setup.py install
%cd ..

Laden Sie das Standard-Pre-Training-Modell von [hier] herunter (https://drive.google.com/drive/folders/1sau1I10rFeAn8BDk8eZDL5qaEjTlNghp) und legen Sie es im Ordner . / ELMo_ja_word_level ab. Es gibt "Einbettungsmodell für Worteinheiten" und "Einbettungsmodell für Zeicheneinheiten / Worteinheiten", aber dieses Mal werden wir "Einbettungsmodell für Worteinheiten" verwenden.

Nachdem das Modell fertig ist, erstellen Sie eine "Embedder" -Instanz und definieren Sie eine Funktion zum Berechnen und Abrufen des eingebetteten Vektors des Zielworts.

from ELMoForManyLangs.elmoformanylangs import Embedder
from overrides import overrides

elmo_model_path = "./ELMo_ja_word_level"
elmo_embedder = Embedder(elmo_model_path, batch_size=64)

def my_index(l, x, default=-1):
  return l.index(x) if x in l else default

def find_position(token_list, word):
  pos_list = [my_index(t, word) for t in token_list]
  assert -1 not in pos_list
  return pos_list

def get_elmo_word_embeddings(token_list, target_word):
  embs_list = elmo_embedder.sents2elmo(token_list, output_layer=-2)
  pos_list = find_position(token_list, target_word)
  word_emb_list = []
  for i, embs in enumerate(embs_list):
    word_emb_list.append(embs[:, pos_list[i], :])
  return word_emb_list

Das Argument output_layer der Methode sents2elmo der Instanz Embedder gibt die Ebene an, aus der der eingebettete Vektor extrahiert wird, und die Details lauten wie folgt. 0: Kontextunabhängige Einbettungsschicht für das erste Wort 1: Erste Schicht LSTM-Schicht 2: Zweite LSTM-Schicht -1: Durchschnitt von 3 Schichten (Standard) -2: Alle drei Ebenen ausgeben Dieses Mal wird "output_layer = -2" angegeben, um den Unterschied zwischen den Ausgabeebenen zu vergleichen.

Geben Sie den Token-Text ein, um den Einbettungsvektor für das Zielwort zu berechnen.

elmo_embeddings = get_elmo_word_embeddings(token_list1, target_words[0])
elmo_embeddings += get_elmo_word_embeddings(token_list2, target_words[1])
elmo_embeddings += get_elmo_word_embeddings(token_list3, target_words[2])
elmo_embeddings += get_elmo_word_embeddings(token_list4, target_words[3])
elmo_embeddings = np.array(elmo_embeddings)

print(elmo_embeddings.shape)
# (32, 3, 1024)

Da die Worteinbettung, die nicht vom Kontext der ersten Schicht abhängt, nicht zur Unterscheidung mehrdeutiger Wörter verwendet werden kann, verwenden wir den Durchschnitt der ersten und zweiten Schicht von LSTM und der drei Schichten, die als ELMo-Vektor bezeichnet werden.

elmo_lstm1_embeddings = elmo_embeddings[:, 1, :]
elmo_lstm2_embeddings = elmo_embeddings[:, 2, :]
elmo_mean_embeddings = np.mean(elmo_embeddings, axis=1)

Bereiten Sie vor der Berechnung der Kosinusähnlichkeit des eingebetteten Vektors auch den eingebetteten Vektor von BERT vor.

BERT Dieser Artikel, den ich zuvor geschrieben habe, beschreibt im Wesentlichen auch die Verwendung des vorgefertigten BERT-Modells.

Gemäß. Laden Sie zunächst das vorab trainierte Stockmark-Modell (TensorFlow-Version) von [diesem Link] herunter (https://drive.google.com/drive/folders/1iDlmhGgJ54rkVBtZvgMlgbuNwtFQ50V-) und legen Sie es im Verzeichnis . / BERT_base_stockmark ab. Ich werde. Importieren Sie als Nächstes die TensorFlow Version 1.x-Serie und klonen Sie das offizielle BERT-Repository.

%tensorflow_version 1.x
import tensorflow as tf

!git clone https://github.com/google-research/bert.git

Von dem Code im geklonten Repository muss tokenization.py geändert werden, um MeCab als Tokenizer zu verwenden. Bitte lesen Sie diesen Artikel, da es zu lang sein wird, um ihn erneut zu veröffentlichen. Der Code "extract_features.py", der den eingebetteten Vektor abruft, muss diesmal nicht geändert werden. Durch Ausführen der folgenden Schritte wird der eingebettete Vektor für alle Token an "bert_embeddings * .jsonl" ausgegeben. Alle Ebenen werden als Ebenen zum Extrahieren des eingebetteten Vektors angegeben.

#BERT-Ausführung
for i in range(1, 5):
  input_file = 'texts' + str(i) + '.txt'
  output_file = 'bert_embeddings' + str(i) + '.jsonl'

  !python ./bert/extract_features_mecab_neologd.py \
    --input_file=$input_file \
    --output_file=$output_file \
    --vocab_file=./BERT_base_stockmark/vocab.txt \
    --bert_config_file=./BERT_base_stockmark/bert_config.json \
    --init_checkpoint=./BERT_base_stockmark/output_model.ckpt \
    --layers 0,1,2,3,4,5,6,7,8,9,10,11

Extrahieren Sie nur den eingebetteten Vektor des Zielworts aus der Ausgabe-JSONL-Datei.

def extract_bert_embeddings(input_path, target_token, target_layer=10): 
  with open(input_path, 'r') as f:
      output_jsons = f.readlines()

  embs = []
  for output_json in output_jsons:
      output = json.loads(output_json)
      for feature in output['features']:
          if feature['token'] != target_token: continue
          for layer in feature['layers']:
              if layer['index'] != target_layer: continue
              embs.append(layer['values'])
  return np.array(embs)
bert_embeddings = []
for i in range(12):
  emb1 = extract_bert_embeddings('./bert_embeddings1.jsonl', 
                                 target_layer=i, target_token=target_words[0])
  emb2 = extract_bert_embeddings('./bert_embeddings2.jsonl', 
                                 target_layer=i, target_token=target_words[1])
  emb3 = extract_bert_embeddings('./bert_embeddings3.jsonl', 
                                 target_layer=i, target_token=target_words[2])
  emb4 = extract_bert_embeddings('./bert_embeddings4.jsonl', 
                                 target_layer=i, target_token=target_words[3])
  embeddings = np.vstack([emb1, emb2, emb3, emb4])
  bert_embeddings.append(embeddings)
bert_embeddings = np.array(bert_embeddings)

Ergebnis

Nachdem wir nun die eingebetteten Vektoren für die beiden Modelle haben, wollen wir die Ähnlichkeit der Wörter bestimmen. Bereiten Sie zunächst eine Funktion vor, um die Korrelationsmatrix der Kosinusähnlichkeit zu berechnen.

def calc_sim_mat(arr):
  num = len(arr) # number of vectors contained in arr
  sim_mat = np.zeros((num, num))
  norm = np.apply_along_axis(lambda x: np.linalg.norm(x), 1, arr) # norm of each vector
  normed_arr = arr / np.reshape(norm, (-1,1))
  for i, vec in enumerate(normed_arr):
    sim = np.dot(normed_arr, np.reshape(vec, (-1,1)))
    sim = np.reshape(sim, -1) #flatten
    sim_mat[i] = sim
  return sim_mat

Schauen wir uns zunächst das Ergebnis der Verwendung des eingebetteten Vektors von ELMo für die zweite Schicht von LSTM und BERT für die zweite Schicht vom Ende an.

sim_mat_elmo = calc_sim_mat(elmo_lstm2_embeddings)
sim_mat_bert = calc_sim_mat(bert_embeddings[10])

Bereiten Sie eine Funktion vor und führen Sie sie aus, die das Berechnungsergebnis visualisiert.

def show_sim_mat(sim_mat, labels, title=None, export_fig=False):
  sns.set(font_scale=1.1, font="IPAexGothic") 
  g = sns.heatmap(
      sim_mat,
      vmin=0,
      vmax=1,
      cmap="YlOrRd")
  ticks_pos = range(2, 32, 4)
  plt.xticks(ticks=ticks_pos, labels=labels, rotation='vertical')
  plt.yticks(ticks=ticks_pos, labels=labels)
  for i in range(8, 25, 8):
    plt.plot([0, 32], [i, i], ls='-', lw=1, color='b')
    plt.plot([i, i], [0, 32], ls='-', lw=1, color='b')
  for i in range(4, 29, 8):
    plt.plot([0, 32], [i, i], ls='--', lw=1, color='b')
    plt.plot([i, i], [0, 32], ls='--', lw=1, color='b')
  if title:
    plt.title(title, fontsize=24)
  if export_fig:
    plt.savefig(export_fig, bbox_inches='tight')
  plt.show()
labels = ['Ganz A.', 'Ganz B.', 'Respektlosigkeit A.', 'Respektlosigkeit B.', 'Unschuldig A.', 'Unschuldig B.', 'Hals A.', 'Hals B.']
show_sim_mat(sim_mat_elmo, labels, 'ELMo', 'ELMo.png')
show_sim_mat(sim_mat_bert, labels, 'BERT', 'BERT.png')

Die Ergebnisse sind wie folgt. Die Ähnlichkeit zwischen Wörtern in 32 Beispielsätzen wird durch eine Heatmap von 32 x 32 Quadraten dargestellt. Alle 4 Sätze wird eine Trennlinie gezogen, in der Polynomwörter synonym verwendet werden. Im Idealfall ist die Farbe des diagonalen Blocks aus 4x4-Quadraten dunkler und die Farbe der anderen nicht diagonalen Teile heller. <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/613488/c55744f2-649d-7628-3724-56689760acc3.png ", height=280> <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/613488/a67af78a-bb98-52cd-3844-9a6de901ead0.png ", height=280> In Bezug auf ELMo war es bei der Berechnung von diesem Artikel dasselbe, aber der Winkel zwischen eingebetteten Vektoren ist tendenziell klein und die allgemeine Ähnlichkeit ist Der Wert ist groß und die Farbe ist dunkel. Zumindest können Sie sehen, dass die diagonalen Blöcke der 8x8 Quadrate desselben Wortes dunkler sind als die anderen, aber die Bedeutungen der Polynomwörter scheinen nicht so unterschiedlich zu sein. Auf der anderen Seite können Sie in Bezug auf BERT deutlich sehen, wo die Farbe des diagonalen Blocks von 4x4-Quadraten dunkler ist als die des nicht diagonalen Teils. Insbesondere denke ich, dass A / B und Hals A ziemlich gut unterschieden werden können.

Übrigens ist es nicht möglich, die Genauigkeit nur anhand der Wärmekarte genau zu bewerten. Lassen Sie uns das Ergebnis anhand eines quantitativen Index bewerten. Wir haben vier Beispielsätze für jede Bedeutung eines Polynomworts vorbereitet, sodass jedes Polynomwort drei Gefährten mit derselben Bedeutung hat. Daher sind für jedes Polynomwort die drei mit der höchsten Ähnlichkeit die Polynomwörter mit derselben Bedeutung, die vom Modell abgeleitet werden. Berechnet die Genauigkeit dieses Modells für die Inferenz. Die block_size in der Funktion unten ist die Größe eines diagonalen Blocks in der Heatmap oben, die jetzt 4 ist. Gibt eine Liste der Genauigkeitsraten für jeden der 32 Beispielsätze und deren Durchschnittswerte aus.

def eval_precision(sim_mat, block_size):
  num_data = len(sim_mat)
  precision_list = []
  for i in range(num_data):
    block_id = int(i / block_size)
    pred = np.array([1 if (block_id * block_size <= j and j < (block_id+1) * block_size) 
                    else 0 for j in range(num_data)])
    sorted_args = np.argsort(sim_mat[i])[::-1]
    sorted_pred = pred[sorted_args]
    precision = np.mean(sorted_pred[1:block_size])
    precision_list.append(precision)
  precision_arr = np.array(precision_list)
  av_precision = np.mean(precision_arr)
  return av_precision, precision_arr
#ELMo LSTM 2. Schicht
av_precision, precision_arr = eval_precision(sim_mat_elmo, block_size=4)
print(np.round(av_precision, 2))
for i in range(8):
  print(np.round(precision_arr[4*i:4*(i+1)], 2))
#BERT 11. Schicht
av_precision, precision_arr = eval_precision(sim_mat_bert, block_size=4)
print(np.round(av_precision, 2))
for i in range(8):
  print(np.round(precision_arr[4*i:4*(i+1)], 2))

Das Ergebnis ist wie folgt.

** [ELMo LSTM 2. Schicht] ** ** Durchschnitt ** 0,54

Beispielsatz 1 Beispielsatz 2 Beispielsatz 3 Beispielsatz 4
Ganz A. 1.0 0.33 0.67 0.67
Ganz B. 0.67 1.0 0.33 0.67
Respektlosigkeit A. 0.33 0.33 0.33 0.33
Respektlosigkeit B. 0.33 0.67 0.67 1.0
Unschuldig A. 0.67 0.33 0.67 0.33
Unschuldig B. 0.67 0.33 0.33 0.67
Hals A. 0.67 0.67 1.0 0.67
Hals B. 0.67 0 0 0.67

** [BERT 11. Schicht] ** ** Durchschnitt ** 0,78

Beispielsatz 1 Beispielsatz 2 Beispielsatz 3 Beispielsatz 4
Ganz A. 1.0 1.0 1.0 1.0
Ganz B. 1.0 1.0 1.0 1.0
Respektlosigkeit A. 0 0.67 0.67 0.67
Respektlosigkeit B. 1.0 0.67 0.67 0.67
Unschuldig A. 1.0 1.0 1.0 1.0
Unschuldig B. 0.67 0.67 0.33 0.33
Hals A. 1.0 1.0 1.0 1.0
Hals B. 0.67 0 0.67 0.67

Das Ergebnis ist schließlich, dass die Genauigkeit von BERT auch bei quantitativer Betrachtung hoch ist. In Experiment in englischer Version betrug die durchschnittliche Genauigkeitsrate ELMo 0,61 und BERT 0,78, sodass beide Modelle fast die gleiche Genauigkeit wie die englische Version aufweisen. Es ist geworden. Beide Modelle haben Probleme mit der Bedeutung des Halses B, aber liegt es daran, dass er als Hals statt als Hals geschrieben ist?

Schließlich werden wir die Genauigkeit der Ebenen vergleichen, die den eingebetteten Vektor extrahieren. Für BERT wird auch der eingebettete Vektor des Durchschnitts aller Schichten und des Durchschnitts der letzten 6 Schichten berechnet.

# ELMo
#LSTM 1. Schicht
sim_mat_elmo = calc_sim_mat(elmo_lstm1_embeddings)
av_precision, _ = eval_precision(sim_mat_elmo, block_size=4)
print('LSTM1', np.round(av_precision, 2))

#LSTM 2. Schicht
sim_mat_elmo = calc_sim_mat(elmo_lstm2_embeddings)
av_precision, _ = eval_precision(sim_mat_elmo, block_size=4)
print('LSTM2', np.round(av_precision, 2))

#3-Schicht-Durchschnitt
sim_mat_elmo = calc_sim_mat(elmo_mean_embeddings)
av_precision, _ = eval_precision(sim_mat_elmo, block_size=4)
print('mean', np.round(av_precision, 2))
# BERT
#Jede Schicht
for i in range(12):
  sim_mat_bert = calc_sim_mat(bert_embeddings[i])
  av_precision, _ = eval_precision(sim_mat_bert, block_size=4)
  print(i+1, np.round(av_precision, 2))

#Alle Schichten durchschnittlich
sim_mat_bert = calc_sim_mat(np.mean(bert_embeddings, axis=0))
av_precision, _ = eval_precision(sim_mat_bert, block_size=4)
print('average-all', np.round(av_precision, 2))

#Zweite Hälfte 6 Schichten durchschnittlich
sim_mat_bert = calc_sim_mat(np.mean(bert_embeddings[-6:], axis=0))
av_precision, _ = eval_precision(sim_mat_bert, block_size=4)
print('average-last6', np.round(av_precision, 2))

Die Ergebnisse sind wie folgt. Zeigt die durchschnittliche Genauigkeit für alle Beispielsätze an.

[ELMo]

Schicht Durchschnitt der Konformitätsrate
LSTM 1. Schicht 0.52
LSTM 2. Schicht 0.54
ELMo 0.54

[BERT]

Schicht Durchschnitt der Konformitätsrate
1. Schicht 0.42
2. Schicht 0.48
3. Schicht 0.67
4. Schicht 0.73
5. Schicht 0.73
6. Schicht 0.73
7. Schicht 0.72
8. Schicht 0.73
9. Schicht 0.78
10. Schicht 0.78
11. Schicht 0.78
12. Schicht 0.77
Alle Schichten durchschnittlich 0.77
Endgültiger 6-Schicht-Durchschnitt 0.77

In der englischen Version des Experiments erreichte ELMo die höchste Genauigkeit in der 1. LSTM-Schicht und BERT in der mittleren Schicht. Diesmal ist ELMo jedoch der Durchschnitt der 2. und 3. LSTM-Schicht, und BERT ist die letzte Schicht außer der letzten Schicht. Es ist die höchste Genauigkeit in der anderen Schicht. Ich denke, die Tendenz dazu hängt von den Daten und Aufgaben vor dem Training ab.

abschließend

Die Geschichte war die gleiche wie der Artikel, den ich zuvor geschrieben habe, aber ich fühlte die Schwierigkeit aufgrund von Japanisch, wie die Notwendigkeit eines separaten Schreibens. Beim Vergleich von ELMo und BERT wurde festgestellt, dass BERT Polynomwörter genauer unterscheiden kann als in der englischen Version. Es war schade, dass wir uns aufgrund der unterschiedlichen Tokenizer nicht mit anderen japanischen Vorlernmodellen vergleichen konnten.

Recommended Posts

[Japanische Version] Beurteilung der Wortähnlichkeit für Polynomwörter mit ELMo und BERT
Verwenden Sie ELMo und BERT, um die Wortähnlichkeit für Polynomwörter zu bestimmen
Python: Japanischer Text: Charakteristisch für Sprache aufgrund von Wortähnlichkeit
Trennung von japanischem Nachnamen und Vornamen mit BERT
Berechnung der Ähnlichkeit zwischen Sätzen mit Word2Vec (vereinfachte Version)
Negative / positive Beurteilung von Sätzen durch BERT und Visualisierung von Gründen
[Für Anfänger] Eine Wortzusammenfassung der gängigen Programmiersprachen (Version 2018)