[PYTHON] Wie erstelle ich eine japanisch-englische Übersetzung?

So erstellen Sie eine japanisch-englische Übersetzung

Wir werden eine japanisch-englische Übersetzung mit Tensorflow und Keras implementieren.

Dies ist das Inhaltsverzeichnis für diesen Artikel.

  1. Umgebungs- und Datensatzdetails (#env)
  2. [Basisfluss](# Basisfluss)
  3. Datenvorverarbeitung (#preprocess)
  4. [Modell erstellen](# Modell konstruieren)
  5. Lernen
  6. [bewerten](# bewerten)

Die Details des Codes werden auf github veröffentlicht. Bitte beziehen Sie sich darauf. Japanese-English_Translation Da es als .pyinb gespeichert ist, kann es einfach mit Google Colab verschoben werden. Ich werde den Code veröffentlichen, wenn ich vor langer Zeit die Verarbeitung natürlicher Sprache studiert habe. (Veröffentlicht ein wenig organisiert)

Wir freuen uns darauf, Ihnen zu helfen.

Umgebungs- und Datensatzdetails

Hardware-Umgebung gooble colab

Software-Umgebung python3 tensorflow (version2.3.1)

Datensatz small_parallel_enja

small_parallel_enja ist ein kleiner Datensatz einiger Sätze, die aus dem Tanaka-Korpus extrahiert wurden. Es wurde vorverarbeitet und ist sehr einfach zu bedienen. Da der Datensatz in Trainingsdaten, Verifizierungsdaten und Testdaten unterteilt ist, muss er nicht unterteilt werden. Wenn genügend Ressourcen vorhanden sind, kann möglicherweise eine Kreuzverifizierung unter Verwendung einer Mischung aus Trainingsdaten und Verifizierungsdaten als Trainingsdaten durchgeführt werden. (Für diejenigen, die mehrere GPUs in der Küche haben)

Grundfluss Wir werden gemäß dem folgenden Ablauf vorgehen.

1. Datenvorverarbeitung

2. Modellbau

3. Lernen

4. Bewertung

Nun, es ist normal ww

Datenvorverarbeitung Es ist ganz einfach, weil ich die vorverarbeiteten Daten verwende.

Tokenize verwendet die in Tensorflow integrierte Keras-API. tf.keras.preprocessing.text.Tokenizer

Es ist ziemlich einfach zu bedienen und ein Beispiel ist unten gezeigt.

tokenizer = tf.keras.preprocessing.text.Tokenizer(oov="<unk>")
tokenizer.fit_on_texts(texts)
sequences = tokenizer.texts_to_sequences(texts)

Erstellen Sie eine Instanz von tf.keras.preprocessing.text.Tokenizer und Ich werde Ihnen die Wörter sagen, die für diese Instanz mit fit_on_texts (Texte) verwendet werden sollen. Auf diese Weise verwalten Sie eindeutige Wörter intern. Danach müssen Sie nur noch jeden Satz mit tokenizer.texts_to_sequences (Texte) digitalisieren. Texte beziehen sich auf Textdatensätze. Das Textformat muss eine Liste von Zeichenfolgen sein.

texts = ["I am Niwaka", "Hello !", .., "Wow !"]

Der obige Code ist ein Beispiel für das Textformat, das an die Instanz tf.keras.preprocessing.text.Tokenizer übergeben wird.

Wie benutzt man tf.keras.preprocessing.text.Tokenizer Sie können dies herausfinden, indem Sie auf den obigen Link springen.

Um das Lernen per Mini-Batch durchführen zu können, muss die Form der Daten im Mini-Batch übereinstimmen. Daten in natürlicher Sprache haben jedoch im Allgemeinen eine variable Länge </ strong>. Daher muss es im Gegensatz zu anderen Datensätzen entwickelt werden.

Es gibt zwei Möglichkeiten, mit variablen Daten umzugehen.

1.padding 2. Setzen Sie die Stapelgröße auf 1 (Wenn die Zeitreihenlänge mehrere hundert Ebenen beträgt, sollte ich diese verwenden?)

Hier verwenden wir eine Polsterung von 1. Das Auffüllen ist eine Methode, um die Länge L zu bestimmen, indem ein spezieller Wert für Daten eingegeben wird, die nicht die maximale Zeitreihenlänge im Mini-Batch erfüllen. Es scheint, dass 0 als spezieller Wert in Tensorflow und Keras festgelegt ist.

Angenommen, Sie haben einen Datensatz mit einer ungleichmäßigen Länge, z.

sequences = [
  [12, 45],
  [3, 4, 7],
  [4],
]

Die maximale Länge des obigen Datensatzes beträgt 3. Wenn das Auffüllen durchgeführt wird, ist es wie folgt.

padded_sequences = [
  [12, 45, 0],
  [3, 4, 7],
  [4, 0, 0],
]

In Tensorflow lautet die Auffüllverarbeitung für Textdaten tf.keras.preprocessing.sequence.pad_sequences </ Es wird von einer API namens> bereitgestellt.

Fügen Sie zur Verwendung die Länge zu tf.keras.preprocessing.sequence.pad_sequences hinzu Geben Sie einfach den Datensatz, den Sie vereinheitlichen möchten, als Eingabe an. Das Auffüllargument gibt an, ob 0 nach oder 0 vor aufgefüllt werden soll. Durch Angabe von "Post" wird 0 mit Post-Filling gefüllt. Ich denke, Sie können es verwenden, wie Sie möchten.

padded_sequences = tf.keras.preprocessing.sequence.pad_sequences(sequences, padding="post")

Jetzt können Sie per Mini-Batch lernen. Aber hier gibt es ein Problem. Es ist eine Frage, wie das Modell 0 interpretiert. </ strong>

Wenn möglich, möchten Sie den speziellen Wert 0 ignorieren können. Andernfalls ist es wenig sinnvoll, eine RNN zu verwenden, die variable Längen verarbeiten kann.

Tensorflow bietet eine Funktion namens Maskierung </ strong>. Die Maskierung ist eine Funktion, die den Wert im angegebenen Schritt ignoriert. Dies ermöglicht es, Daten variabler Länge gemeinsam zu verarbeiten. (Daten mit variabler Länge können ohne Maskierung verarbeitet werden, es wird jedoch auch ein spezieller Wert von 0 in das Modell aufgenommen. Das ist unangenehm, daher möchte ich dies vermeiden.)

Für weitere Informationen folgen Sie bitte dem Link unten. Unter dem Link werden detaillierte Erklärungen zur Verwendung von Making and Padding in Tensorflow und Keras geschrieben. Masking and padding with Keras

Im Tensorflow wird die Maskierung auf folgende Arten aktiviert:

  1. Fügen Sie tf.keras.layers.Masking hinzu
  2. Setzen Sie das Argument mask_zero von tf.keras.layers.Embedding auf True.
  3. Übergeben Sie es direkt an die Ebene, die die Maske verwendet. (Dies ist ein einfacher Weg, vielleicht verwende ich dies für Videos usw.)

Hier verwenden wir 2.

In dem diesmal verwendeten Modell generiert das Einbetten automatisch eine Maske, und diese Maske wird automatisch auf die nächste Ebene übertragen.

Modellkonstruktion Verwenden Sie das Modell Seq2Seq als Modell. Was ist Seq2Seq? Sequenz Ein Modell, das Daten in andere Sequenzdaten umwandelt. Sequenzdaten sind hier Zeitreihendaten.

Die Schnittstelle von Seq2Seq ist

Sequenz nach der Konvertierung= Seq2Seq(Sequenz vor der Konvertierung)

ist.

Angenommen, Sie geben "Ich bin ein Schüler" in das Seq2Seq-Modell ein.

"I am student ." = Seq2Seq("Ich bin ein Student.")

Seq2Seq besteht aus zwei Modulen. Der erste ist Encoder </ strong> und der zweite ist Decoder </ strong>. Sequenzdaten werden vom Encoder codiert und geben Funktionen aus, die für den Menschen unverständlich sind. Geben Sie es und das Start-Token in den Decoder ein, um weitere Sequenzdaten abzurufen. Hier ist das Start-Token ein spezielles Wort, das den Beginn einer Sequenz bedeutet.

Die Schnittstelle zwischen Encoder und Decoder wird unten in einer Pseudosprache beschrieben.

Eigenschaften, die Menschen nicht verstehen können= Encoder(Sequenz vor der Konvertierung)
Sequenz nach der Konvertierung= Decoder(Eigenschaften, die Menschen nicht verstehen können,<start>Zeichen)    

RNN wird in jedem Modul verwendet. Der spezifische Mechanismus ist Visualizing A Neural Machine Translation Model (Mechanics of Seq2seq Models With Attention) Sie können es sehen, indem Sie den ersten Teil von lesen. In diesem Artikel geht es um Aufmerksamkeit, aber er beschreibt auch Seq2Seq.

Seq2Seq verwendet RNN. RNN ist gut in der Verarbeitung natürlicher Sprachen, da es Daten variabler Länge verarbeiten kann. Zusätzlich werden die in jedem Schritt verwendeten Gewichte geteilt, was die Zunahme der Parameter verringert. Beachten Sie jedoch, dass Daten mit einer zu langen Zeitreihenlänge zum Verschwinden des Gradienten und zur Explosion des Gradienten während der Fehlerrückausbreitung führen. Selbst wenn die Zeitreihenlänge nur 10 beträgt, entspricht dies dem Erweitern von 10 Ebenen auf der Zeitachse. GRU wird für RNN übernommen. GRU ist ein RNN-Modell, das seinen Gradienten nicht leicht verliert.

Das Modelldiagramm des diesmal verwendeten Decoders und Encoders ist wie folgt.

スクリーンショット 2020-11-16 19.01.01.png Abbildung 1 Encoder

スクリーンショット 2020-11-16 19.01.07.png Abbildung 2 Decoder

Ich verwende jeweils nur eine RNN für Encoder und Decoder. Da der Datensatz klein ist, habe ich ein kleineres Modell gewählt.

Unten ist der Code mit Tensorflow und Keras.

Es verwendet die funktionale API. Wenn Sie Daten mit variabler Länge darstellen möchten, geben Sie None für die Form von tf.keras.Input an.

Um die funktionale API zu verwenden, folgen Sie bitte dem unten stehenden Link. The Functional API Unten finden Sie den Modellimplementierungscode. Modell, Encoder und Decoder sind jeweils verfügbar. Das Modell ist lernbereit. Die durch Training mit model.fit erhaltenen Parameter werden in den Codierer und Decodierer eingelesen. Die Verarbeitung unterscheidet sich zwischen Lernen und Inferenz.

def CreateEncoderModel(vocab_size):
  units = 128
  emb_layer = tf.keras.layers.Embedding(vocab_size, units, mask_zero=True)#Maske, um das Auffüllen zu aktivieren_zero=True
  gru_layer  = tf.keras.layers.GRU(units)
  encoder_inputs = tf.keras.Input(shape=(None,))
  outputs = emb_layer(encoder_inputs)
  outputs = gru_layer(outputs)
  
  encoder = tf.keras.Model(encoder_inputs, outputs)

  return encoder

def CreateDecoderModel(vocab_size):
  units = 128

  emb_layer = tf.keras.layers.Embedding(vocab_size, units, mask_zero=True)#Maske, um das Auffüllen zu aktivieren_zero=True
  gru_layer  = tf.keras.layers.GRU(units, return_sequences=True)
  dense_layer = tf.keras.layers.Dense(vocab_size, activation="softmax")

  decoder_inputs  = tf.keras.Input(shape=(None,))
  encoder_outputs = tf.keras.Input(shape=(None,))

  outputs = emb_layer(decoder_inputs)
  outputs = gru_layer(outputs, initial_state=encoder_outputs)
  outputs = dense_layer(outputs)
  
  decoder = tf.keras.Model([decoder_inputs, encoder_outputs], outputs)

  return decoder

def CreateModel(seed, ja_vocab_size, en_vocab_size):
  tf.random.set_seed(seed)
  encoder = CreateEncoderModel(ja_vocab_size)
  decoder = CreateDecoderModel(en_vocab_size)

  encoder_inputs = tf.keras.Input(shape=(None,))
  decoder_inputs = tf.keras.Input(shape=(None,))

  encoder_outputs = encoder(encoder_inputs)
  decoder_outputs = decoder([decoder_inputs, encoder_outputs])
  
  model = tf.keras.Model([encoder_inputs, decoder_inputs], decoder_outputs)
  model.compile(optimizer='adam',
                loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=False),
                metrics=['accuracy'])
  return model, encoder, decoder

Lernen Lassen Sie uns mit den Stapelgrößen 32, 64, 128 suchen.

Die experimentellen Einstellungen sind unten gezeigt.

  1. Die Anzahl der RNN-Einheiten beträgt 128
  2. Wie man das Gewicht aktualisiert, ist Adam (Lernrate bleibt die Standardeinstellung)
  3. Die Anzahl der Epochen beträgt 2
  4. Bewertungsmethode ist BLEU

Wir haben die Epoche zweimal gestoppt und die Validierungsdaten mit dem Modell der zweiten Epoche ausgewertet. BLEU ist ein Index zur Messung der Qualität von Übersetzungen.

Unten ist der Lerncode.

bleu_scores = []
batch_size_list = [32, 64, 128]
for batch_size in batch_size_list:
  model, encoder, decoder = CreateModel(seed, len(ja_tokenizer.word_index)+1, len(en_tokenizer.word_index)+1)
  model.fit([train_ja_sequences, train_en_sequences[:, :-1]], train_en_sequences[:, 1:], batch_size=batch_size, epochs=2)
  model.save(str(batch_size)+"model.h5")
  encoder.load_weights(str(batch_size)+"model.h5", by_name=True)
  decoder.load_weights(str(batch_size)+"model.h5", by_name=True)
  bleu_score = Evaluate(valid_ja, valid_en, encoder, decoder)
  bleu_scores.append(bleu_score)

BLEU wird mit der Evaluate-Funktion gemessen. (Die Implementierung wird auf github veröffentlicht.) Das Modell wurde unter Verwendung jeder Stapelgröße als Name gespeichert.

Die Decode-Methode gibt das Wort aus, das die maximale Wahrscheinlichkeit für jeden Schritt darstellt. Ich entschied gierig das Wort. (Gierige Methode) In der Tat ist es besser, Beam Search zu verwenden. Beam Search ist ein Suchalgorithmus mit leicht entspannten gierigen Bedingungen. Selbst wenn Sie das Wort für jeden Schritt gierig festlegen, wissen Sie nicht, ob es die optimale Lösung ist. Daher ist es besser, die Strahlensuche zu verwenden. Die folgende Erklärung ist hilfreich für die Strahlensuche. C5W3L03 Beam Search Der Link ist ein Video, daher ist es eine gute Idee, es anzusehen, wenn Sie Zeit haben.

Bei Keras frage ich mich, ob bei der Berechnung des Verlustwerts eine Maske angewendet wird. Ich habe gehört, dass es angewendet wird, bin mir aber nicht sicher, weil ich nicht weiß, was dort vor sich geht.

Wenn Sie sich unwohl fühlen, kann die Implementierung der Kostenfunktion von Neuronale maschinelle Übersetzung mit Aufmerksamkeit hilfreich sein. Beachten Sie jedoch, dass die Implementierung des Link-Ziels für diejenigen, die nur mit model.fit gelernt haben, recht schwierig ist. Die Implementierung der verknüpften Kostenfunktion wird so implementiert, dass die Kosten zum Zeitpunkt des Maskierungsschritts nicht in den Endkosten enthalten sind.

Die experimentellen Ergebnisse sind grafisch dargestellt. スクリーンショット 2020-11-18 16.22.00.png Fig. 3 Versuchsergebnisse

Bitte beachten Sie, dass das Bild rau ist.

Die Chargengröße mit der besten BLEU für die Validierungsdaten beträgt 32, verwenden Sie also 32 für die Umschulung. Wie Sie in Abbildung 3 sehen können, können kleinere Chargengrößen zu besseren Ergebnissen führen. Mischen Sie vor Beginn der Auswertung die Trainingsdaten und die Verifizierungsdaten und trainieren Sie erneut. Beim erneuten Lernen wurde die Anzahl der Epochen auf 10 festgelegt. Alles andere ist das gleiche.

train_and_valid_ja_sequences = tf.concat([train_ja_sequences, valid_ja_sequences], 0)
train_and_valid_en_sequences = tf.concat([train_en_sequences, valid_en_sequences], 0)

best_model, best_encoder, best_decoder = CreateModel(seed, len(ja_tokenizer.word_index)+1, len(en_tokenizer.word_index)+1)
best_model.fit([train_and_valid_ja_sequences, train_and_valid_en_sequences[:, :-1]], train_and_valid_en_sequences[:, 1:], batch_size=32, epochs=10)
best_model.save("best_model.h5")

Wenn Sie eine GPU verwenden, erhalten Sie möglicherweise nicht immer die gleichen Ergebnisse.

Evaluation Es war BLEU 0,19 für die Testdaten. (Maximum ist 1) Ich weiß es nicht, weil ich es nicht mit anderen verglichen habe, aber ich denke, es ist ein ziemlich schreckliches Ergebnis www

Der Verarbeitungscode für die Testdaten lautet wie folgt.

best_encoder.load_weights("best_model.h5", by_name=True)
best_decoderbest_decoder.load_weights("best_model.h5", by_name=True)
bleu_score = Evaluate(test_ja, test_en, best_encoder, best_decoder)
print("bleu on test_dataset:")
print(bleu_score)

Es ist eine einfache Frage, aber es scheint mehrere BLEU-Bewertungsmethoden zu geben. (Es scheint einige Glättungsfunktionen zu geben.) Es scheint, dass es nicht einheitlich ist, aber bitte sagen Sie mir, wer damit vertraut ist. Wenn es nicht einheitlich ist, sollte BLEU mit der Glättungsfunktion gemessen werden, die am besten funktioniert ... Ist das eine Ameise? ...

Endlich

Ich werde diesen Artikel mit einigen Möglichkeiten zur Verbesserung der Genauigkeit beenden.

  1. Invertieren Sie die Eingabedaten
  2. Integrieren Sie Aufmerksamkeit in das Modell
  3. Verwenden Sie stop_word.
  4. Ensemble
  5. Vertiefen Sie die Ebene (vergessen Sie nicht, die Sprungverbindung zu verwenden).
  6. Teilen Sie die Gewichte der Einbettungsebene und der vollständig verbundenen Ebene
  7. Ändern Sie das Modell in Transformer
  8. Ändern Sie die anfängliche Gewichtseinstellungsmethode

Ich habe diejenigen aufgelistet, die Sie finden können, indem Sie im Internet suchen. Nur weil Sie es verwenden, bedeutet dies nicht, dass sich BLEU verbessern wird. Wenn Sie interessiert sind, fragen Sie bitte den Google-Lehrer.

Ich bin neu in der Verarbeitung natürlicher Sprache, daher würde ich mich freuen, wenn Sie mir sagen könnten, ob etwas nicht stimmt.

Referenzen 1.small_parallel_enja 2.Masking and padding with Keras 3.The Functional API 4. Visualizing A Neural Machine Translation Model (Mechanics of Seq2seq Models With Attention) 5.Neural machine translation with attention 6.C5W3L03 Beam Search

Recommended Posts