Watch keynotes, product sessions, workshops, and more from Google I/O See playlist

Dikkatle sinirsel makine çevirisi

TensorFlow.org'da görüntüleyin Google Colab'da çalıştırın Kaynağı GitHub'da görüntüleyin Not defterini indir

Bu not defteri, Dikkate Dayalı Sinirsel Makine Çevirisine Etkili Yaklaşımlara dayalı olarak İspanyolca'dan İngilizce'ye çeviri için diziden diziye (seq2seq) modelini eğitir. Bu, aşağıdakiler hakkında biraz bilgi sahibi olduğunu varsayan gelişmiş bir örnektir:

  • Diziden diziye modeller
  • Keras katmanının altındaki TensorFlow temelleri:

Bu mimari biraz modası geçmiş olsa da, dikkat mekanizmalarını daha derinden anlamak için üzerinde çalışılması gereken çok faydalı bir projedir ( Transformers'a geçmeden önce).

Modeli bu defterde eğittikten sonra , " ¿todavia estan en casa? " gibi bir İspanyolca cümle girebilecek ve İngilizce çevirisini döndürebileceksiniz: " hala evde misin? "

Ortaya çıkan model, tf.saved_model olarak tf.saved_model aktarılabilir, bu nedenle diğer TensorFlow ortamlarında kullanılabilir.

Bir oyuncak örneği için çeviri kalitesi makul, ancak oluşturulan dikkat grafiği belki daha ilginç. Bu, çeviri yaparken giriş cümlesinin hangi bölümlerinin modelin dikkatini çektiğini gösterir:

ispanyolca-ingilizce dikkat planı

Kurulum

pip install tensorflow_text
import numpy as np

import typing
from typing import Any, Tuple

import tensorflow as tf
from tensorflow.keras.layers.experimental import preprocessing

import tensorflow_text as tf_text

import matplotlib.pyplot as plt
import matplotlib.ticker as ticker

Bu öğretici, sıfırdan birkaç katman oluşturur, özel ve yerleşik uygulamalar arasında geçiş yapmak istiyorsanız bu değişkeni kullanın.

use_builtins = True

Bu öğretici, şekilleri yanlış almanın kolay olduğu çok sayıda düşük seviyeli API kullanır. Bu sınıf, öğretici boyunca şekilleri kontrol etmek için kullanılır.

Şekil denetleyicisi

Veri

http://www.manythings.org/anki/ tarafından sağlanan bir dil veri kümesini kullanacağız Bu veri kümesi şu biçimde dil çeviri çiftleri içerir:

May I borrow this book? ¿Puedo tomar prestado este libro?

Kullanılabilir çeşitli dilleri var, ancak İngilizce-İspanyolca veri setini kullanacağız.

Veri kümesini indirin ve hazırlayın

Kolaylık olması açısından, bu veri kümesinin bir kopyasını Google Cloud'da barındırdık, ancak kendi kopyanızı da indirebilirsiniz. Veri kümesini indirdikten sonra, verileri hazırlamak için atacağımız adımlar şunlardır:

  1. Her cümleye bir başlangıç ve bitiş belirteci ekleyin.
  2. Özel karakterleri kaldırarak cümleleri temizleyin.
  3. Bir kelime indeksi ve ters kelime indeksi oluşturun (kelime → id ve id → kelimeden eşlenen sözlükler).
  4. Her cümleyi maksimum uzunluğa yapıştırın.
# Download the file
import pathlib

path_to_zip = tf.keras.utils.get_file(
    'spa-eng.zip', origin='http://storage.googleapis.com/download.tensorflow.org/data/spa-eng.zip',
    extract=True)

path_to_file = pathlib.Path(path_to_zip).parent/'spa-eng/spa.txt'
Downloading data from http://storage.googleapis.com/download.tensorflow.org/data/spa-eng.zip
2646016/2638744 [==============================] - 0s 0us/step
def load_data(path):
  text = path.read_text(encoding='utf-8')

  lines = text.splitlines()
  pairs = [line.split('\t') for line in lines]

  inp = [inp for targ, inp in pairs]
  targ = [targ for targ, inp in pairs]

  return targ, inp
targ, inp = load_data(path_to_file)
print(inp[-1])
Si quieres sonar como un hablante nativo, debes estar dispuesto a practicar diciendo la misma frase una y otra vez de la misma manera en que un músico de banjo practica el mismo fraseo una y otra vez hasta que lo puedan tocar correctamente y en el tiempo esperado.
print(targ[-1])
If you want to sound like a native speaker, you must be willing to practice saying the same sentence over and over in the same way that banjo players practice the same phrase over and over until they can play it correctly and at the desired tempo.

Bir tf.data veri kümesi oluşturun

Bu dize dizilerinden, bunları verimli bir şekilde karıştıran vetf.data.Dataset birtf.data.Dataset dizesi oluşturabilirsiniz:

BUFFER_SIZE = len(inp)
BATCH_SIZE = 64

dataset = tf.data.Dataset.from_tensor_slices((inp, targ)).shuffle(BUFFER_SIZE)
dataset = dataset.batch(BATCH_SIZE)
for example_input_batch, example_target_batch in dataset.take(1):
  print(example_input_batch[:5])
  print()
  print(example_target_batch[:5])
  break
tf.Tensor(
[b'La tienda ya podr\xc3\xada estar cerrada.'
 b'Tuve que hacer un discurso en corto plazo.'
 b'\xc2\xbfA qu\xc3\xa9 hora ves televisi\xc3\xb3n?'
 b'Lamento llegar tarde.'
 b'Tom se quer\xc3\xada quedar a ver que suceder\xc3\xada. Desafortunadamente, se tuvo que ir.'], shape=(5,), dtype=string)

tf.Tensor(
[b'The store might be closed already.'
 b'I had to make a speech at short notice.' b'What time do you watch TV?'
 b"I'm sorry I'm late."
 b'Tom wanted to stick around to see what would happen. Unfortunately, he had to leave.'], shape=(5,), dtype=string)

Metin ön işleme

Bu öğreticinin hedeflerinden biri, tf.saved_model olarak dışa aktarılabilen bir model oluşturmaktır. Dışa aktarılan modeli kullanışlı kılmak için tf.string girdilerini almalı ve tf.string çıktılarını yeniden çalıştırmalıdır: Tüm metin işleme modelin içinde gerçekleşir.

Standardizasyon

Model, sınırlı bir kelime dağarcığına sahip çok dilli metinlerle ilgilenmektedir. Bu yüzden giriş metnini standartlaştırmak önemli olacaktır.

İlk adım, aksanlı karakterleri bölmek ve uyumluluk karakterlerini ASCII eşdeğerleriyle değiştirmek için Unicode normalleştirmesidir.

tensroflow_text paketi bir unicode normalleştirme işlemi içerir:

example_text = tf.constant('¿Todavía está en casa?')

print(example_text.numpy())
print(tf_text.normalize_utf8(example_text, 'NFKD').numpy())
b'\xc2\xbfTodav\xc3\xada est\xc3\xa1 en casa?'
b'\xc2\xbfTodavi\xcc\x81a esta\xcc\x81 en casa?'

Unicode normalleştirme, metin standardizasyon işlevindeki ilk adım olacaktır:

def tf_lower_and_split_punct(text):
  # Split accecented characters.
  text = tf_text.normalize_utf8(text, 'NFKD')
  text = tf.strings.lower(text)
  # Keep space, a to z, and select punctuation.
  text = tf.strings.regex_replace(text, '[^ a-z.?!,¿]', '')
  # Add spaces around punctuation.
  text = tf.strings.regex_replace(text, '[.?!,¿]', r' \0 ')
  # Strip whitespace.
  text = tf.strings.strip(text)

  text = tf.strings.join(['[START]', text, '[END]'], separator=' ')
  return text
print(example_text.numpy().decode())
print(tf_lower_and_split_punct(example_text).numpy().decode())
¿Todavía está en casa?
[START] ¿ todavia esta en casa ? [END]

Metin Vektörleştirme

Bu standardizasyon işlevi, giriş metninin belirteç dizilerine dönüştürülmesini ve sözcük çıkarma işlemlerini gerçekleştirecek olan bir preprocessing.TextVectorization katmanına sarılacaktır.

max_vocab_size = 5000

input_text_processor = preprocessing.TextVectorization(
    standardize=tf_lower_and_split_punct,
    max_tokens=max_vocab_size)

TextVectorization katmanı ve diğer birçok experimental.preprocessing katmanının bir adapt yöntemi vardır. Bu yöntem, eğitim verilerinin bir dönemini okur ve Model.fix çok benzer. Bu adapt yöntemi, verileri temel alarak katmanı başlatır. Burada kelime dağarcığını belirler:

input_text_processor.adapt(inp)

# Here are the first 10 words from the vocabulary:
input_text_processor.get_vocabulary()[:10]
['', '[UNK]', '[START]', '[END]', '.', 'que', 'de', 'el', 'a', 'no']

Bu İspanyolca TextVectorization katmanıdır, şimdi İngilizce olanı oluşturun ve .adapt() :

output_text_processor = preprocessing.TextVectorization(
    standardize=tf_lower_and_split_punct,
    max_tokens=max_vocab_size)

output_text_processor.adapt(targ)
output_text_processor.get_vocabulary()[:10]
['', '[UNK]', '[START]', '[END]', '.', 'the', 'i', 'to', 'you', 'tom']

Artık bu katmanlar, bir dizi diziyi bir dizi simge kimliğine dönüştürebilir:

example_tokens = input_text_processor(example_input_batch)
example_tokens[:3, :10]
<tf.Tensor: shape=(3, 10), dtype=int64, numpy=
array([[   2,   11,  469,   89,  199,  118, 1357,    4,    3,    0],
       [   2,  382,    5,   54,   16, 1155,   14,  780, 4652,    4],
       [   2,   13,    8,    5,  138,  773,  330,   12,    3,    0]])>

get_vocabulary yöntemi, belirteç kimliklerini metne geri dönüştürmek için kullanılabilir:

input_vocab = np.array(input_text_processor.get_vocabulary())
tokens = input_vocab[example_tokens[0].numpy()]
' '.join(tokens)
'[START] la tienda ya podria estar cerrada . [END]             '

Döndürülen belirteç kimlikleri sıfır dolguludur. Bu kolayca bir maskeye dönüştürülebilir:

plt.subplot(1, 2, 1)
plt.pcolormesh(example_tokens)
plt.title('Token IDs')

plt.subplot(1, 2, 2)
plt.pcolormesh(example_tokens != 0)
plt.title('Mask')
Text(0.5, 1.0, 'Mask')

png

Kodlayıcı/kod çözücü modeli

Aşağıdaki şema modele genel bir bakış göstermektedir. Her zaman adımında, kod çözücünün çıkışı, bir sonraki kelimeyi tahmin etmek için kodlanmış giriş üzerinden ağırlıklı bir toplamla birleştirilir. Diyagram ve formüller Luong'un makalesinden alınmıştır .

dikkat mekanizması

İçeri girmeden önce model için birkaç sabit tanımlayın:

embedding_dim = 256
units = 1024

kodlayıcı

Yukarıdaki diyagramın mavi kısmı olan kodlayıcıyı oluşturarak başlayın.

kodlayıcı:

  1. Belirteç kimliklerinin bir listesini alır ( input_text_processor ).
  2. Her belirteç için bir gömme vektörü layers.Embedding (Bir layers.Embedding kullanarak).
  3. layers.GRU yeni bir sıraya layers.GRU (bir layers.GRU kullanarak).
  4. İadeler:
    • İşlenmiş sıra. Bu, dikkat başlığına iletilecektir.
    • İç durum. Bu, kod çözücüyü başlatmak için kullanılacaktır.
class Encoder(tf.keras.layers.Layer):
  def __init__(self, input_vocab_size, embedding_dim, enc_units):
    super(Encoder, self).__init__()
    self.enc_units = enc_units
    self.input_vocab_size = input_vocab_size

    # The embedding layer converts tokens to vectors
    self.embedding = tf.keras.layers.Embedding(self.input_vocab_size,
                                               embedding_dim)

    # The GRU RNN layer processes those vectors sequentially.
    self.gru = tf.keras.layers.GRU(self.enc_units,
                                   # Return the sequence and state
                                   return_sequences=True,
                                   return_state=True,
                                   recurrent_initializer='glorot_uniform')

  def call(self, tokens, state=None):
    shape_checker = ShapeChecker()
    shape_checker(tokens, ('batch', 's'))

    # 2. The embedding layer looks up the embedding for each token.
    vectors = self.embedding(tokens)
    shape_checker(vectors, ('batch', 's', 'embed_dim'))

    # 3. The GRU processes the embedding sequence.
    #    output shape: (batch, s, enc_units)
    #    state shape: (batch, enc_units)
    output, state = self.gru(vectors, initial_state=state)
    shape_checker(output, ('batch', 's', 'enc_units'))
    shape_checker(state, ('batch', 'enc_units'))

    # 4. Returns the new sequence and its state.
    return output, state

Şimdiye kadar nasıl bir araya geldiği aşağıda açıklanmıştır:

# Convert the input text to tokens.
example_tokens = input_text_processor(example_input_batch)

# Encode the input sequence.
encoder = Encoder(input_text_processor.vocabulary_size(),
                  embedding_dim, units)
example_enc_output, example_enc_state = encoder(example_tokens)

print(f'Input batch, shape (batch): {example_input_batch.shape}')
print(f'Input batch tokens, shape (batch, s): {example_tokens.shape}')
print(f'Encoder output, shape (batch, s, units): {example_enc_output.shape}')
print(f'Encoder state, shape (batch, units): {example_enc_state.shape}')
Input batch, shape (batch): (64,)
Input batch tokens, shape (batch, s): (64, 22)
Encoder output, shape (batch, s, units): (64, 22, 1024)
Encoder state, shape (batch, units): (64, 1024)

Kodlayıcı, durumunun kod çözücüyü başlatmak için kullanılabilmesi için dahili durumunu döndürür.

Bir RNN'nin, bir diziyi birden çok çağrı üzerinden işleyebilmesi için durumunu döndürmesi de yaygındır. Dekoderi oluştururken bundan daha fazlasını göreceksiniz.

dikkat kafası

Kod çözücü, giriş dizisinin bölümlerine seçici olarak odaklanmak için dikkati kullanır. Dikkat, her örnek için girdi olarak bir dizi vektör alır ve her örnek için bir "dikkat" vektörü döndürür. Bu dikkat katmanı katmanlara layers.GlobalAveragePoling1D ancak dikkat katmanı ağırlıklı ortalama gerçekleştirir.

Bunun nasıl çalıştığına bakalım:

dikkat denklemi 1

dikkat denklemi 2

Nerede:

  • $s$ kodlayıcı dizinidir.
  • $t$ kod çözücü indeksidir.
  • $\alpha_{ts}$ dikkat ağırlıklarıdır.
  • $h_s$, ilgilenilen kodlayıcı çıkışlarının sırasıdır (trafo terminolojisinde dikkat "anahtar" ve "değer").
  • $h_t$ diziye katılan kod çözücü durumudur (trafo terminolojisinde dikkat "sorgusu").
  • $c_t$, sonuçtaki bağlam vektörüdür.
  • $a_t$, "bağlam" ve "sorgu"yu birleştiren son çıktıdır.

denklemler:

  1. $\alpha_{ts}$ dikkat ağırlıklarını kodlayıcının çıkış sırası boyunca bir softmax olarak hesaplar.
  2. Bağlam vektörünü kodlayıcı çıktılarının ağırlıklı toplamı olarak hesaplar.

Sonuncusu $score$ işlevidir. Görevi, her bir anahtar-sorgu çifti için bir skaler logit puanı hesaplamaktır. İki yaygın yaklaşım vardır:

dikkat denklemi 4

Bu eğitimde Bahdanau'nun ek dikkat kullanılmaktadır . TensorFlow her ikisinin uygulamaları içeren layers.Attention ve layers.AdditiveAttention . Aşağıdaki sınıf, bir çift katmandaki ağırlık matrislerini işler. layers.Dense katmanlar ve yerleşik uygulamayı çağırır.

class BahdanauAttention(tf.keras.layers.Layer):
  def __init__(self, units):
    super().__init__()
    # For Eqn. (4), the  Bahdanau attention
    self.W1 = tf.keras.layers.Dense(units, use_bias=False)
    self.W2 = tf.keras.layers.Dense(units, use_bias=False)

    self.attention = tf.keras.layers.AdditiveAttention()

  def call(self, query, value, mask):
    shape_checker = ShapeChecker()
    shape_checker(query, ('batch', 't', 'query_units'))
    shape_checker(value, ('batch', 's', 'value_units'))
    shape_checker(mask, ('batch', 's'))

    # From Eqn. (4), `W1@ht`.
    w1_query = self.W1(query)
    shape_checker(w1_query, ('batch', 't', 'attn_units'))

    # From Eqn. (4), `W2@hs`.
    w2_key = self.W2(value)
    shape_checker(w2_key, ('batch', 's', 'attn_units'))

    query_mask = tf.ones(tf.shape(query)[:-1], dtype=bool)
    value_mask = mask

    context_vector, attention_weights = self.attention(
        inputs = [w1_query, value, w2_key],
        mask=[query_mask, value_mask],
        return_attention_scores = True,
    )
    shape_checker(context_vector, ('batch', 't', 'value_units'))
    shape_checker(attention_weights, ('batch', 't', 's'))

    return context_vector, attention_weights

Dikkat katmanını test edin

Bir BahdanauAttention katmanı oluşturun:

attention_layer = BahdanauAttention(units)

Bu katman 3 girdi alır:

  • query : Bu, daha sonra kod çözücü tarafından oluşturulacaktır.
  • value : Bu, kodlayıcının çıktısı olacaktır.
  • mask : example_tokens != 0 hariç tutmak için example_tokens != 0
(example_tokens != 0).shape
TensorShape([64, 22])

Dikkat katmanının vektörleştirilmiş uygulaması, bir dizi sorgu vektörü dizisini ve bir dizi değer vektörü dizisini iletmenize izin verir. Sonuç:

  1. Bir dizi sonuç vektörü, sorguların boyutunu gösterir.
  2. Boyut (query_length, value_length) olan bir toplu dikkat eşlemeleri.
# Later, the decoder will generate this attention query
example_attention_query = tf.random.normal(shape=[len(example_tokens), 2, 10])

# Attend to the encoded tokens

context_vector, attention_weights = attention_layer(
    query=example_attention_query,
    value=example_enc_output,
    mask=(example_tokens != 0))

print(f'Attention result shape: (batch_size, query_seq_length, units):           {context_vector.shape}')
print(f'Attention weights shape: (batch_size, query_seq_length, value_seq_length): {attention_weights.shape}')
Attention result shape: (batch_size, query_seq_length, units):           (64, 2, 1024)
Attention weights shape: (batch_size, query_seq_length, value_seq_length): (64, 2, 22)

Dikkat ağırlıkları, her bir dizi için 1.0 olmalıdır.

t=0 0'daki diziler arasındaki dikkat ağırlıkları:

plt.subplot(1, 2, 1)
plt.pcolormesh(attention_weights[:, 0, :])
plt.title('Attention weights')

plt.subplot(1, 2, 2)
plt.pcolormesh(example_tokens != 0)
plt.title('Mask')
Text(0.5, 1.0, 'Mask')

png

Küçük rasgele başlatma nedeniyle, dikkat ağırlıklarının tümü 1/(sequence_length) değerine yakındır. Tek bir dizi için ağırlıkları yakınlaştırırsanız, modelin genişletmeyi ve yararlanmayı öğrenebileceği bazı küçük varyasyonlar olduğunu görebilirsiniz.

attention_weights.shape
TensorShape([64, 2, 22])
attention_slice = attention_weights[0, 0].numpy()
attention_slice = attention_slice[attention_slice != 0]
plt.suptitle('Attention weights for one sequence')

plt.figure(figsize=(12, 6))
a1 = plt.subplot(1, 2, 1)
plt.bar(range(len(attention_slice)), attention_slice)
# freeze the xlim
plt.xlim(plt.xlim())
plt.xlabel('Attention weights')

a2 = plt.subplot(1, 2, 2)
plt.bar(range(len(attention_slice)), attention_slice)
plt.xlabel('Attention weights, zoomed')

# zoom in
top = max(a1.get_ylim())
zoom = 0.85*top
a2.set_ylim([0.90*top, top])
a1.plot(a1.get_xlim(), [zoom, zoom], color='k')
[<matplotlib.lines.Line2D at 0x7f50f5a2d710>]
<Figure size 432x288 with 0 Axes>

png

kod çözücü

Kod çözücünün işi, bir sonraki çıktı belirteci için tahminler oluşturmaktır.

  1. Kod çözücü, kodlayıcı çıktısının tamamını alır.
  2. Şimdiye kadar ne ürettiğini takip etmek için bir RNN kullanır.
  3. RNN çıktısını, kodlayıcının çıktısı üzerinden dikkat çekmek için sorgu olarak kullanır ve bağlam vektörünü üretir.
  4. "Dikkat vektörü" oluşturmak için Denklem 3'ü (aşağıda) kullanarak RNN ​​çıktısını ve bağlam vektörünü birleştirir.
  5. "Dikkat vektörüne" dayalı olarak bir sonraki belirteç için logit tahminleri üretir.

dikkat denklemi 3

İşte Decoder sınıfı ve başlatıcısı. Başlatıcı, gerekli tüm katmanları oluşturur.

class Decoder(tf.keras.layers.Layer):
  def __init__(self, output_vocab_size, embedding_dim, dec_units):
    super(Decoder, self).__init__()
    self.dec_units = dec_units
    self.output_vocab_size = output_vocab_size
    self.embedding_dim = embedding_dim

    # For Step 1. The embedding layer convets token IDs to vectors
    self.embedding = tf.keras.layers.Embedding(self.output_vocab_size,
                                               embedding_dim)

    # For Step 2. The RNN keeps track of what's been generated so far.
    self.gru = tf.keras.layers.GRU(self.dec_units,
                                   return_sequences=True,
                                   return_state=True,
                                   recurrent_initializer='glorot_uniform')

    # For step 3. The RNN output will be the query for the attention layer.
    self.attention = BahdanauAttention(self.dec_units)

    # For step 4. Eqn. (3): converting `ct` to `at`
    self.Wc = tf.keras.layers.Dense(dec_units, activation=tf.math.tanh,
                                    use_bias=False)

    # For step 5. This fully connected layer produces the logits for each
    # output token.
    self.fc = tf.keras.layers.Dense(self.output_vocab_size)

Bu katman için call yöntemi, birden çok tensör alır ve döndürür. Bunları basit konteyner sınıfları halinde düzenleyin:

class DecoderInput(typing.NamedTuple):
  new_tokens: Any
  enc_output: Any
  mask: Any

class DecoderOutput(typing.NamedTuple):
  logits: Any
  attention_weights: Any

İşte call yönteminin uygulanması:

def call(self,
         inputs: DecoderInput,
         state=None) -> Tuple[DecoderOutput, tf.Tensor]:
  shape_checker = ShapeChecker()
  shape_checker(inputs.new_tokens, ('batch', 't'))
  shape_checker(inputs.enc_output, ('batch', 's', 'enc_units'))
  shape_checker(inputs.mask, ('batch', 's'))

  if state is not None:
    shape_checker(state, ('batch', 'dec_units'))

  # Step 1. Lookup the embeddings
  vectors = self.embedding(inputs.new_tokens)
  shape_checker(vectors, ('batch', 't', 'embedding_dim'))

  # Step 2. Process one step with the RNN
  rnn_output, state = self.gru(vectors, initial_state=state)

  shape_checker(rnn_output, ('batch', 't', 'dec_units'))
  shape_checker(state, ('batch', 'dec_units'))

  # Step 3. Use the RNN output as the query for the attention over the
  # encoder output.
  context_vector, attention_weights = self.attention(
      query=rnn_output, value=inputs.enc_output, mask=inputs.mask)
  shape_checker(context_vector, ('batch', 't', 'dec_units'))
  shape_checker(attention_weights, ('batch', 't', 's'))

  # Step 4. Eqn. (3): Join the context_vector and rnn_output
  #     [ct; ht] shape: (batch t, value_units + query_units)
  context_and_rnn_output = tf.concat([context_vector, rnn_output], axis=-1)

  # Step 4. Eqn. (3): `at = tanh(Wc@[ct; ht])`
  attention_vector = self.Wc(context_and_rnn_output)
  shape_checker(attention_vector, ('batch', 't', 'dec_units'))

  # Step 5. Generate logit predictions:
  logits = self.fc(attention_vector)
  shape_checker(logits, ('batch', 't', 'output_vocab_size'))

  return DecoderOutput(logits, attention_weights), state
Decoder.call = call

Kodlayıcı , RNN'sine yapılan tek bir çağrıyla tam giriş sırasını işler. Kod çözücünün bu uygulaması, verimli eğitim için bunu da yapabilir . Ancak bu öğretici, kod çözücüyü birkaç nedenden dolayı bir döngüde çalıştıracaktır:

  • Esneklik: Döngüyü yazmak, eğitim prosedürü üzerinde doğrudan kontrol sahibi olmanızı sağlar.
  • Netlik: Tüm bunları tek bir çağrıda layers.RNN için maskeleme hileleri yapmak ve layers.RNN veya tfa.seq2seq API'lerini kullanmak layers.RNN . Ancak bunu bir döngü olarak yazmak daha net olabilir.

Şimdi bu kod çözücüyü kullanmayı deneyin.

decoder = Decoder(output_text_processor.vocabulary_size(),
                  embedding_dim, units)

Kod çözücü 4 giriş alır.

  • new_tokens - Oluşturulan son jeton. Kod çözücüyü "[START]" belirteci ile başlatın.
  • enc_output - Encoder tarafından oluşturulur .
  • mask - tokens != 0 nerede olduğunu gösteren bir boole tensörü tokens != 0
  • state - Kod çözücüden önceki state çıkışı (kod çözücünün RNN'sinin dahili durumu). Sıfırlamak için None iletin. Orijinal kağıt, onu kodlayıcının son RNN durumundan başlatır.
# Convert the target sequence, and collect the "[START]" tokens
example_output_tokens = output_text_processor(example_target_batch)

start_index = output_text_processor._index_lookup_layer('[START]').numpy()
first_token = tf.constant([[start_index]] * example_output_tokens.shape[0])
# Run the decoder
dec_result, dec_state = decoder(
    inputs = DecoderInput(new_tokens=first_token,
                          enc_output=example_enc_output,
                          mask=(example_tokens != 0)),
    state = example_enc_state
)

print(f'logits shape: (batch_size, t, output_vocab_size) {dec_result.logits.shape}')
print(f'state shape: (batch_size, dec_units) {dec_state.shape}')
logits shape: (batch_size, t, output_vocab_size) (64, 1, 5000)
state shape: (batch_size, dec_units) (64, 1024)

Logitlere göre bir jeton örnekleyin:

sampled_token = tf.random.categorical(dec_result.logits[:, 0, :], num_samples=1)

Çıktının ilk kelimesi olarak belirteci deşifre edin:

vocab = np.array(output_text_processor.get_vocabulary())
first_word = vocab[sampled_token.numpy()]
first_word[:5]
array([['evening'],
       ['kindness'],
       ['anymore'],
       ['clapped'],
       ['fresh']], dtype='<U16')

Şimdi ikinci bir logit kümesi oluşturmak için kod çözücüyü kullanın.

  • Aynı enc_output ve mask enc_output , bunlar değişmedi.
  • Örneklenen belirteci new_tokens olarak new_tokens .
  • Kod çözücünün geçen sefer döndürdüğü decoder_state , böylece RNN geçen sefer kaldığı yerden bir bellekle devam eder.
dec_result, dec_state = decoder(
    DecoderInput(sampled_token,
                 example_enc_output,
                 mask=(example_tokens != 0)),
    state=dec_state)
sampled_token = tf.random.categorical(dec_result.logits[:, 0, :], num_samples=1)
first_word = vocab[sampled_token.numpy()]
first_word[:5]
array([['too'],
       ['outside'],
       ['imagine'],
       ['sixteen'],
       ['hesitated']], dtype='<U16')

Eğitim

Artık tüm model bileşenlerine sahip olduğunuza göre, modeli eğitmeye başlama zamanı. İhtiyacın olacak:

  • Optimizasyonu gerçekleştirmek için bir kayıp işlevi ve optimize edici.
  • Her girdi/hedef grubu için modelin nasıl güncelleneceğini tanımlayan bir eğitim adımı işlevi.
  • Eğitimi yürütmek ve kontrol noktalarını kaydetmek için bir eğitim döngüsü.

Kayıp fonksiyonunu tanımlayın

class MaskedLoss(tf.keras.losses.Loss):
  def __init__(self):
    self.name = 'masked_loss'
    self.loss = tf.keras.losses.SparseCategoricalCrossentropy(
        from_logits=True, reduction='none')

  def __call__(self, y_true, y_pred):
    shape_checker = ShapeChecker()
    shape_checker(y_true, ('batch', 't'))
    shape_checker(y_pred, ('batch', 't', 'logits'))

    # Calculate the loss for each item in the batch.
    loss = self.loss(y_true, y_pred)
    shape_checker(loss, ('batch', 't'))

    # Mask off the losses on padding.
    mask = tf.cast(y_true != 0, tf.float32)
    shape_checker(mask, ('batch', 't'))
    loss *= mask

    # Return the total.
    return tf.reduce_sum(loss)

Eğitim adımını uygulayın

Bir model sınıfıyla başlayın, eğitim süreci bu modelde train_step yöntemi olarak uygulanacaktır. Ayrıntılar için Uygunluğu özelleştirme konusuna bakın.

Burada train_step yöntemi, daha sonra gelecek olan _train_step uygulamasının etrafındaki bir sarmalayıcıdır. Bu sarmalayıcı, hata ayıklamayı kolaylaştırmak için tf.function derlemesini açıp kapatmak için bir anahtar içerir.

class TrainTranslator(tf.keras.Model):
  def __init__(self, embedding_dim, units,
               input_text_processor,
               output_text_processor, 
               use_tf_function=True):
    super().__init__()
    # Build the encoder and decoder
    encoder = Encoder(input_text_processor.vocabulary_size(),
                      embedding_dim, units)
    decoder = Decoder(output_text_processor.vocabulary_size(),
                      embedding_dim, units)

    self.encoder = encoder
    self.decoder = decoder
    self.input_text_processor = input_text_processor
    self.output_text_processor = output_text_processor
    self.use_tf_function = use_tf_function
    self.shape_checker = ShapeChecker()

  def train_step(self, inputs):
    self.shape_checker = ShapeChecker()
    if self.use_tf_function:
      return self._tf_train_step(inputs)
    else:
      return self._train_step(inputs)

Genel olarak Model.train_step yönteminin uygulanması aşağıdaki gibidir:

  1. Bir toplu alma input_text, target_text gelentf.data.Dataset .
  2. Bu ham metin girişlerini belirteç yerleştirmelerine ve maskelere dönüştürün.
  3. encoder_output ve encoder_state encoder_output almak için kodlayıcıyı input_tokens üzerinde çalıştırın.
  4. Dekoder durumunu ve kaybını başlatın.
  5. target_tokens üzerinde döngü target_tokens :
    1. Kod çözücüyü her seferinde bir adım çalıştırın.
    2. Her adım için kaybı hesaplayın.
    3. Ortalama kaybı toplayın.
  6. Kaybın gradyanını hesaplayın ve modelin trainable_variables güncellemeler uygulamak için optimize trainable_variables .

Aşağıda eklenen _preprocess yöntemi, 1 ve 2 numaralı adımları uygular:

def _preprocess(self, input_text, target_text):
  self.shape_checker(input_text, ('batch',))
  self.shape_checker(target_text, ('batch',))

  # Convert the text to token IDs
  input_tokens = self.input_text_processor(input_text)
  target_tokens = self.output_text_processor(target_text)
  self.shape_checker(input_tokens, ('batch', 's'))
  self.shape_checker(target_tokens, ('batch', 't'))

  # Convert IDs to masks.
  input_mask = input_tokens != 0
  self.shape_checker(input_mask, ('batch', 's'))

  target_mask = target_tokens != 0
  self.shape_checker(target_mask, ('batch', 't'))

  return input_tokens, input_mask, target_tokens, target_mask
TrainTranslator._preprocess = _preprocess

Aşağıda eklenen _train_step yöntemi, kod çözücünün fiilen çalıştırılması dışında kalan adımları işler:

def _train_step(self, inputs):
  input_text, target_text = inputs  

  (input_tokens, input_mask,
   target_tokens, target_mask) = self._preprocess(input_text, target_text)

  max_target_length = tf.shape(target_tokens)[1]

  with tf.GradientTape() as tape:
    # Encode the input
    enc_output, enc_state = self.encoder(input_tokens)
    self.shape_checker(enc_output, ('batch', 's', 'enc_units'))
    self.shape_checker(enc_state, ('batch', 'enc_units'))

    # Initialize the decoder's state to the encoder's final state.
    # This only works if the encoder and decoder have the same number of
    # units.
    dec_state = enc_state
    loss = tf.constant(0.0)

    for t in tf.range(max_target_length-1):
      # Pass in two tokens from the target sequence:
      # 1. The current input to the decoder.
      # 2. The target the target for the decoder's next prediction.
      new_tokens = target_tokens[:, t:t+2]
      step_loss, dec_state = self._loop_step(new_tokens, input_mask,
                                             enc_output, dec_state)
      loss = loss + step_loss

    # Average the loss over all non padding tokens.
    average_loss = loss / tf.reduce_sum(tf.cast(target_mask, tf.float32))

  # Apply an optimization step
  variables = self.trainable_variables 
  gradients = tape.gradient(average_loss, variables)
  self.optimizer.apply_gradients(zip(gradients, variables))

  # Return a dict mapping metric names to current value
  return {'batch_loss': average_loss}
TrainTranslator._train_step = _train_step

Aşağıda eklenen _loop_step yöntemi, kod çözücüyü çalıştırır ve artan kaybı ve yeni kod çözücü durumunu ( dec_state ) dec_state .

def _loop_step(self, new_tokens, input_mask, enc_output, dec_state):
  input_token, target_token = new_tokens[:, 0:1], new_tokens[:, 1:2]

  # Run the decoder one step.
  decoder_input = DecoderInput(new_tokens=input_token,
                               enc_output=enc_output,
                               mask=input_mask)

  dec_result, dec_state = self.decoder(decoder_input, state=dec_state)
  self.shape_checker(dec_result.logits, ('batch', 't1', 'logits'))
  self.shape_checker(dec_result.attention_weights, ('batch', 't1', 's'))
  self.shape_checker(dec_state, ('batch', 'dec_units'))

  # `self.loss` returns the total for non-padded tokens
  y = target_token
  y_pred = dec_result.logits
  step_loss = self.loss(y, y_pred)

  return step_loss, dec_state
TrainTranslator._loop_step = _loop_step

Eğitim adımını test edin

Bir TrainTranslator oluşturun ve Model.compile yöntemini kullanarak eğitim için yapılandırın:

translator = TrainTranslator(
    embedding_dim, units,
    input_text_processor=input_text_processor,
    output_text_processor=output_text_processor,
    use_tf_function=False)

# Configure the loss and optimizer
translator.compile(
    optimizer=tf.optimizers.Adam(),
    loss=MaskedLoss(),
)

train_step test edin. Bunun gibi bir metin modeli için kayıp şurada başlamalıdır:

np.log(output_text_processor.vocabulary_size())
8.517193191416238
%%time
for n in range(10):
  print(translator.train_step([example_input_batch, example_target_batch]))
print()
{'batch_loss': <tf.Tensor: shape=(), dtype=float32, numpy=7.6357193>}
{'batch_loss': <tf.Tensor: shape=(), dtype=float32, numpy=7.605328>}
{'batch_loss': <tf.Tensor: shape=(), dtype=float32, numpy=7.549541>}
{'batch_loss': <tf.Tensor: shape=(), dtype=float32, numpy=7.3899865>}
{'batch_loss': <tf.Tensor: shape=(), dtype=float32, numpy=6.7982726>}
{'batch_loss': <tf.Tensor: shape=(), dtype=float32, numpy=4.9411764>}
{'batch_loss': <tf.Tensor: shape=(), dtype=float32, numpy=4.6064944>}
{'batch_loss': <tf.Tensor: shape=(), dtype=float32, numpy=4.3681216>}
{'batch_loss': <tf.Tensor: shape=(), dtype=float32, numpy=4.0767484>}
{'batch_loss': <tf.Tensor: shape=(), dtype=float32, numpy=4.048546>}

CPU times: user 1min 53s, sys: 5.05 s, total: 1min 58s
Wall time: 25.3 s

tf.function olmadan hata ayıklamak daha kolay olsa da, performans artışı sağlar. Artık _train_step yöntemi çalıştığına göre, antrenman sırasında performansı en üst düzeye çıkarmak için tf.function -wrapped _tf_train_step tf.function deneyin:

@tf.function(input_signature=[[tf.TensorSpec(dtype=tf.string, shape=[None]),
                               tf.TensorSpec(dtype=tf.string, shape=[None])]])
def _tf_train_step(self, inputs):
  return self._train_step(inputs)
TrainTranslator._tf_train_step = _tf_train_step
translator.use_tf_function = True

İlk çağrı, işlevi izlediği için yavaş olacaktır.

translator.train_step([example_input_batch, example_target_batch])
{'batch_loss': <tf.Tensor: shape=(), dtype=float32, numpy=4.0749407>}

Ancak bundan sonra genellikle istekli train_step yönteminden train_step daha hızlıdır:

%%time
for n in range(10):
  print(translator.train_step([example_input_batch, example_target_batch]))
print()
{'batch_loss': <tf.Tensor: shape=(), dtype=float32, numpy=4.0411434>}
{'batch_loss': <tf.Tensor: shape=(), dtype=float32, numpy=6.767884>}
{'batch_loss': <tf.Tensor: shape=(), dtype=float32, numpy=3.9755635>}
{'batch_loss': <tf.Tensor: shape=(), dtype=float32, numpy=3.8640413>}
{'batch_loss': <tf.Tensor: shape=(), dtype=float32, numpy=3.7729979>}
{'batch_loss': <tf.Tensor: shape=(), dtype=float32, numpy=3.762789>}
{'batch_loss': <tf.Tensor: shape=(), dtype=float32, numpy=3.7184463>}
{'batch_loss': <tf.Tensor: shape=(), dtype=float32, numpy=3.6814885>}
{'batch_loss': <tf.Tensor: shape=(), dtype=float32, numpy=3.6582916>}
{'batch_loss': <tf.Tensor: shape=(), dtype=float32, numpy=3.6099083>}

CPU times: user 1min 42s, sys: 3.43 s, total: 1min 45s
Wall time: 14.5 s

Yeni bir modelin iyi bir testi, tek bir girdi kümesine fazla sığabileceğini görmektir. Deneyin, kayıp hızla sıfıra gitmelidir:

losses = []
for n in range(100):
  print('.', end='')
  logs = translator.train_step([example_input_batch, example_target_batch])
  losses.append(logs['batch_loss'].numpy())

print()
plt.plot(losses)
....................................................................................................
[<matplotlib.lines.Line2D at 0x7f5181cbbb90>]

png

Artık eğitim adımının işe yaradığından emin olduğunuza göre, sıfırdan eğitmek için modelin yeni bir kopyasını oluşturun:

train_translator = TrainTranslator(
    embedding_dim, units,
    input_text_processor=input_text_processor,
    output_text_processor=output_text_processor)

# Configure the loss and optimizer
train_translator.compile(
    optimizer=tf.optimizers.Adam(),
    loss=MaskedLoss(),
)

Modeli eğit

Kendi özel eğitim Model.train_step yazarken yanlış bir şey Model.train_step da, önceki bölümde olduğu gibi Model.train_step yöntemini uygulamak, Model.train_step çalıştırmanıza ve tüm bu ortak kod kodunu yeniden Model.fit kaçınmanıza olanak tanır.

Bu öğretici yalnızca birkaç dönem için eğitir, bu nedenle toplu kayıpların geçmişini toplamak için bir callbacks.Callback kullanın, çizim için:

class BatchLogs(tf.keras.callbacks.Callback):
  def __init__(self, key):
    self.key = key
    self.logs = []

  def on_train_batch_end(self, n, logs):
    self.logs.append(logs[self.key])

batch_loss = BatchLogs('batch_loss')
train_translator.fit(dataset, epochs=3,
                     callbacks=[batch_loss])
Epoch 1/3
1859/1859 [==============================] - 2113s 1s/step - batch_loss: 2.0331
Epoch 2/3
1859/1859 [==============================] - 2076s 1s/step - batch_loss: 1.0389
Epoch 3/3
1859/1859 [==============================] - 2098s 1s/step - batch_loss: 0.8090
<tensorflow.python.keras.callbacks.History at 0x7f50f58b9b10>
plt.plot(batch_loss.logs)
plt.ylim([0, 3])
plt.xlabel('Batch #')
plt.ylabel('CE/token')
Text(0, 0.5, 'CE/token')

png

Arsadaki görünür sıçramalar, dönem sınırlarındadır.

Çevirmek

Artık model eğitildiğine göre, tam text => text çevirisini yürütmek için bir işlev uygulayın.

Bunun için modelin, output_text_processor tarafından sağlanan text => token IDs eşlemesini tersine output_text_processor . Ayrıca özel jetonların kimliklerini de bilmesi gerekir. Bunların hepsi yeni sınıfın yapıcısında uygulanır. Gerçek çeviri yönteminin uygulanması bunu takip edecektir.

Genel olarak bu, her zaman adımında kod çözücüye yapılan girdinin kod çözücünün son tahmininden bir örnek olması dışında eğitim döngüsüne benzer.

class Translator(tf.Module):
  def __init__(self,
               encoder, decoder, 
               input_text_processor,
               output_text_processor):
    self.encoder = encoder
    self.decoder = decoder
    self.input_text_processor = input_text_processor
    self.output_text_processor = output_text_processor

    self.output_token_string_from_index = (
        tf.keras.layers.experimental.preprocessing.StringLookup(
            vocabulary=output_text_processor.get_vocabulary(),
            invert=True))

    # The output should never generate padding, unknown, or start.
    index_from_string = tf.keras.layers.experimental.preprocessing.StringLookup(
        vocabulary=output_text_processor.get_vocabulary())
    token_mask_ids = index_from_string(['',
                                        '[UNK]',
                                        '[START]']).numpy()

    token_mask = np.zeros([index_from_string.vocabulary_size()], dtype=np.bool)
    token_mask[np.array(token_mask_ids)] = True
    self.token_mask = token_mask

    self.start_token = index_from_string('[START]')
    self.end_token = index_from_string('[END]')
translator = Translator(
    encoder=train_translator.encoder,
    decoder=train_translator.decoder,
    input_text_processor=input_text_processor,
    output_text_processor=output_text_processor,
)

Belirteç kimliklerini metne dönüştürün

Uygulanacak ilk yöntem, belirteç kimliklerini insan tarafından okunabilir metne dönüştüren tokens_to_text .

def tokens_to_text(self, result_tokens):
  shape_checker = ShapeChecker()
  shape_checker(result_tokens, ('batch', 't'))
  result_text_tokens = self.output_token_string_from_index(result_tokens)
  shape_checker(result_text_tokens, ('batch', 't'))

  result_text = tf.strings.reduce_join(result_text_tokens,
                                       axis=1, separator=' ')
  shape_checker(result_text, ('batch'))

  result_text = tf.strings.strip(result_text)
  shape_checker(result_text, ('batch',))
  return result_text
Translator.tokens_to_text = tokens_to_text

Bazı rastgele belirteç kimlikleri girin ve ne ürettiğini görün:

example_output_tokens = tf.random.uniform(
    shape=[5, 2], minval=0, dtype=tf.int64,
    maxval=output_text_processor.vocabulary_size())
translator.tokens_to_text(example_output_tokens).numpy()
array([b'places picked', b'finger showing', b'embassy sapporo',
       b'rest claus', b'cloth it'], dtype=object)

Kod çözücünün tahminlerinden örnek

Bu işlev, kod çözücünün logit çıktılarını alır ve bu dağıtımdan belirteç kimliklerini örnekler:

def sample(self, logits, temperature):
  shape_checker = ShapeChecker()
  # 't' is usually 1 here.
  shape_checker(logits, ('batch', 't', 'vocab'))
  shape_checker(self.token_mask, ('vocab',))

  token_mask = self.token_mask[tf.newaxis, tf.newaxis, :]
  shape_checker(token_mask, ('batch', 't', 'vocab'), broadcast=True)

  # Set the logits for all masked tokens to -inf, so they are never chosen.
  logits = tf.where(self.token_mask, -np.inf, logits)

  if temperature == 0.0:
    new_tokens = tf.argmax(logits, axis=-1)
  else: 
    logits = tf.squeeze(logits, axis=1)
    new_tokens = tf.random.categorical(logits/temperature,
                                        num_samples=1)

  shape_checker(new_tokens, ('batch', 't'))

  return new_tokens
Translator.sample = sample

Bu işlevi bazı rastgele girişlerde test edin:

example_logits = tf.random.normal([5, 1, output_text_processor.vocabulary_size()])
example_output_tokens = translator.sample(example_logits, temperature=1.0)
example_output_tokens
<tf.Tensor: shape=(5, 1), dtype=int64, numpy=
array([[1151],
       [ 733],
       [4493],
       [4726],
       [4234]])>

Çeviri döngüsünü uygulayın

İşte metinden metne çeviri döngüsünün eksiksiz bir uygulaması.

Bu uygulama, sonuçları tensörlere birleştirmek için tf.concat kullanmadan önce python listelerinde toplar.

Bu uygulama statik olarak ortaya grafiği unrolls max_length tekrarlamalar. Python'da istekli yürütme ile bu sorun değil.

def translate_unrolled(self,
                       input_text, *,
                       max_length=50,
                       return_attention=True,
                       temperature=1.0):
  batch_size = tf.shape(input_text)[0]
  input_tokens = self.input_text_processor(input_text)
  enc_output, enc_state = self.encoder(input_tokens)

  dec_state = enc_state
  new_tokens = tf.fill([batch_size, 1], self.start_token)

  result_tokens = []
  attention = []
  done = tf.zeros([batch_size, 1], dtype=tf.bool)

  for _ in range(max_length):
    dec_input = DecoderInput(new_tokens=new_tokens,
                             enc_output=enc_output,
                             mask=(input_tokens!=0))

    dec_result, dec_state = self.decoder(dec_input, state=dec_state)

    attention.append(dec_result.attention_weights)

    new_tokens = self.sample(dec_result.logits, temperature)

    # If a sequence produces an `end_token`, set it `done`
    done = done | (new_tokens == self.end_token)
    # Once a sequence is done it only produces 0-padding.
    new_tokens = tf.where(done, tf.constant(0, dtype=tf.int64), new_tokens)

    # Collect the generated tokens
    result_tokens.append(new_tokens)

    if tf.executing_eagerly() and tf.reduce_all(done):
      break

  # Convert the list of generates token ids to a list of strings.
  result_tokens = tf.concat(result_tokens, axis=-1)
  result_text = self.tokens_to_text(result_tokens)

  if return_attention:
    attention_stack = tf.concat(attention, axis=1)
    return {'text': result_text, 'attention': attention_stack}
  else:
    return {'text': result_text}
Translator.translate = translate_unrolled

Basit bir girişte çalıştırın:

%%time
input_text = tf.constant([
    'hace mucho frio aqui.', # "It's really cold here."
    'Esta es mi vida.', # "This is my life.""
])

result = translator.translate(
    input_text = input_text)

print(result['text'][0].numpy().decode())
print(result['text'][1].numpy().decode())
print()
its very cold here .
this is my life .

CPU times: user 301 ms, sys: 3.92 ms, total: 304 ms
Wall time: 159 ms

Bu modeli dışa aktarmak istiyorsanız, bu yöntemi bir tf.function . Bunu yapmaya çalışırsanız, bu temel uygulamanın birkaç sorunu vardır:

  1. Ortaya çıkan grafikler çok büyüktür ve oluşturulması, kaydedilmesi veya yüklenmesi birkaç saniye sürer.
  2. Statik olarak açılmamış bir döngüden kopamazsınız, bu nedenle tüm çıktılar yapılsa bile her zaman max_length yinelemelerini çalıştırır. Ancak o zaman bile, istekli infazdan marjinal olarak daha hızlıdır.
f = tf.function(input_signature=[tf.TensorSpec(dtype=tf.string, shape=[None])])
def tf_translate(self, input_text):
  return self.translate(input_text)

Translator.tf_translate = tf_translate

Derlemek için tf.function kez çalıştırın:

%%time
result = translator.tf_translate(
    input_text = input_text)
CPU times: user 289 ms, sys: 8.67 ms, total: 297 ms
Wall time: 155 ms
%%time
result = translator.tf_translate(
    input_text = input_text)

print(result['text'][0].numpy().decode())
print(result['text'][1].numpy().decode())
print()
its a very cold here .
this is my life .

CPU times: user 330 ms, sys: 20.7 ms, total: 350 ms
Wall time: 183 ms

[İsteğe bağlı] Sembolik bir döngü kullanın

Translator.translate = translate_symbolic

İlk uygulama, çıktıları toplamak için python listelerini kullandı. Bu kullanımlar tf.range izin döngü iterasyon olarak tf.autograph döngü dönüştürmek. Bu uygulamadaki en büyük değişiklik, tensörleri toplamak için python list yerine tf.TensorArray kullanılmasıdır. Grafik modunda değişken sayıda tensör toplamak için tf.TensorArray gereklidir.

İstekli yürütme ile bu uygulama orijinali ile aynı performansı gösterir:

%%time
result = translator.translate(
    input_text = input_text)

print(result['text'][0].numpy().decode())
print(result['text'][1].numpy().decode())
print()
its very cold here .
this is my life .

CPU times: user 318 ms, sys: 16.6 ms, total: 334 ms
Wall time: 180 ms

Ama onu bir tf.function iki fark göreceksiniz.

@tf.function(input_signature=[tf.TensorSpec(dtype=tf.string, shape=[None])])
def tf_translate(self, input_text):
  return self.translate(input_text)

Translator.tf_translate = tf_translate

Birincisi: max_iterations kopyalarını oluşturmadığından, grafik oluşturma çok daha hızlıdır (~10x).

%%time
result = translator.tf_translate(
    input_text = input_text)
CPU times: user 1.37 s, sys: 12.1 ms, total: 1.38 s
Wall time: 1.25 s

İkincisi: Derlenmiş işlev, küçük girdilerde (bu örnekte 5x) çok daha hızlıdır, çünkü döngüden çıkabilir.

%%time
result = translator.tf_translate(
    input_text = input_text)

print(result['text'][0].numpy().decode())
print(result['text'][1].numpy().decode())
print()
its really cold in a lot .
this is my life .

CPU times: user 181 ms, sys: 4.49 ms, total: 185 ms
Wall time: 36.5 ms

Süreci görselleştirin

translate yöntemi tarafından döndürülen dikkat ağırlıkları, modelin her bir çıktı belirtecini oluşturduğunda "nereye baktığını" gösterir.

Bu nedenle, girdi üzerindeki dikkatin toplamı hepsini döndürmelidir:

a = result['attention'][0]

print(np.sum(a, axis=-1))
[0.99999994 0.9999999  1.0000001  1.         1.         1.

 1.         0.99999994]

İşte ilk örneğin ilk çıktı adımı için dikkat dağılımı. Dikkatin artık eğitimsiz modele göre çok daha fazla odaklandığına dikkat edin:

_ = plt.bar(range(len(a[0, :])), a[0, :])

png

Giriş ve çıkış sözcükleri arasında kabaca bir hizalama olduğundan, dikkatin köşegen yakınına odaklanmasını beklersiniz:

plt.imshow(np.array(a), vmin=0.0)
<matplotlib.image.AxesImage at 0x7f50b0f69590>

png

Daha iyi bir dikkat planı yapmak için bazı kodlar:

Etiketli dikkat grafikleri

i=0
plot_attention(result['attention'][i], input_text[i], result['text'][i])
/home/kbuilder/.local/lib/python3.7/site-packages/ipykernel_launcher.py:14: UserWarning: FixedFormatter should only be used together with FixedLocator
  
/home/kbuilder/.local/lib/python3.7/site-packages/ipykernel_launcher.py:15: UserWarning: FixedFormatter should only be used together with FixedLocator
  from ipykernel import kernelapp as app

png

Birkaç cümle daha çevirin ve onları çizin:

%%time
three_input_text = tf.constant([
    # This is my life.
    'Esta es mi vida.',
    # Are they still home?
    '¿Todavía están en casa?',
    # Try to find out.'
    'Tratar de descubrir.',
])

result = translator.tf_translate(three_input_text)

for tr in result['text']:
  print(tr.numpy().decode())

print()
this is my life .
are you still at home ?
lets try to find out .

CPU times: user 172 ms, sys: 82.1 ms, total: 254 ms
Wall time: 43 ms
result['text']
<tf.Tensor: shape=(3,), dtype=string, numpy=
array([b'this is my life .', b'are you still at home ?',
       b'lets try to find out .'], dtype=object)>
i = 0
plot_attention(result['attention'][i], three_input_text[i], result['text'][i])
/home/kbuilder/.local/lib/python3.7/site-packages/ipykernel_launcher.py:14: UserWarning: FixedFormatter should only be used together with FixedLocator
  
/home/kbuilder/.local/lib/python3.7/site-packages/ipykernel_launcher.py:15: UserWarning: FixedFormatter should only be used together with FixedLocator
  from ipykernel import kernelapp as app

png

i = 1
plot_attention(result['attention'][i], three_input_text[i], result['text'][i])
/home/kbuilder/.local/lib/python3.7/site-packages/ipykernel_launcher.py:14: UserWarning: FixedFormatter should only be used together with FixedLocator
  
/home/kbuilder/.local/lib/python3.7/site-packages/ipykernel_launcher.py:15: UserWarning: FixedFormatter should only be used together with FixedLocator
  from ipykernel import kernelapp as app

png

i = 2
plot_attention(result['attention'][i], three_input_text[i], result['text'][i])
/home/kbuilder/.local/lib/python3.7/site-packages/ipykernel_launcher.py:14: UserWarning: FixedFormatter should only be used together with FixedLocator
  
/home/kbuilder/.local/lib/python3.7/site-packages/ipykernel_launcher.py:15: UserWarning: FixedFormatter should only be used together with FixedLocator
  from ipykernel import kernelapp as app

png

Kısa cümleler genellikle işe yarar, ancak girdi çok uzunsa, model kelimenin tam anlamıyla odağını kaybeder ve makul tahminler sunmayı bırakır. Bunun iki ana nedeni vardır:

  1. Model, modelin tahminlerinden bağımsız olarak, her adımda doğru belirteci beslemeye zorlayan öğretmenle eğitildi. Model, bazen kendi tahminleriyle beslenseydi daha sağlam hale getirilebilirdi.
  2. Model, yalnızca RNN durumu aracılığıyla önceki çıktısına erişebilir. RNN durumu bozulursa, modelin kurtarılmasının bir yolu yoktur. Transformatörler bunu kodlayıcı ve kod çözücüde öz-dikkat kullanarak çözer.
long_input_text = tf.constant([inp[-1]])

import textwrap
print('Expected output:\n', '\n'.join(textwrap.wrap(targ[-1])))
Expected output:
 If you want to sound like a native speaker, you must be willing to
practice saying the same sentence over and over in the same way that
banjo players practice the same phrase over and over until they can
play it correctly and at the desired tempo.
result = translator.tf_translate(long_input_text)

i = 0
plot_attention(result['attention'][i], long_input_text[i], result['text'][i])
_ = plt.suptitle('This never works')
/home/kbuilder/.local/lib/python3.7/site-packages/ipykernel_launcher.py:14: UserWarning: FixedFormatter should only be used together with FixedLocator
  
/home/kbuilder/.local/lib/python3.7/site-packages/ipykernel_launcher.py:15: UserWarning: FixedFormatter should only be used together with FixedLocator
  from ipykernel import kernelapp as app

png

İhracat

Memnun olduğunuz bir modeliniz olduğunda, onu oluşturan bu python programının dışında kullanmak için onu bir tf.saved_model olarak dışa aktarmak isteyebilirsiniz.

Model bir alt sınıfıdır yana tf.Module (aracılığıyla keras.Model ) ve ihracat için tüm işlevselliği bir derlenmektedir tf.function modeli ile temiz bir şekilde dışa gerekir tf.saved_model.save :

Artık işlev izlendiğine göre, saved_model.save kullanılarak dışa aktarılabilir:

tf.saved_model.save(translator, 'translator',
                    signatures={'serving_default': translator.tf_translate})
WARNING:absl:Found untraced functions such as encoder_2_layer_call_and_return_conditional_losses, encoder_2_layer_call_fn, decoder_2_layer_call_and_return_conditional_losses, decoder_2_layer_call_fn, embedding_4_layer_call_and_return_conditional_losses while saving (showing 5 of 60). These functions will not be directly callable after loading.
WARNING:tensorflow:FOR KERAS USERS: The object that you are saving contains one or more Keras models or layers. If you are loading the SavedModel with `tf.keras.models.load_model`, continue reading (otherwise, you may ignore the following instructions). Please change your code to save with `tf.keras.models.save_model` or `model.save`, and confirm that the file "keras.metadata" exists in the export directory. In the future, Keras will only load the SavedModels that have this file. In other words, `tf.saved_model.save` will no longer write SavedModels that can be recovered as Keras models (this will apply in TF 2.5).

FOR DEVS: If you are overwriting _tracking_metadata in your class, this property has been used to save metadata in the SavedModel. The metadta field will be deprecated soon, so please move the metadata to a different file.
WARNING:tensorflow:FOR KERAS USERS: The object that you are saving contains one or more Keras models or layers. If you are loading the SavedModel with `tf.keras.models.load_model`, continue reading (otherwise, you may ignore the following instructions). Please change your code to save with `tf.keras.models.save_model` or `model.save`, and confirm that the file "keras.metadata" exists in the export directory. In the future, Keras will only load the SavedModels that have this file. In other words, `tf.saved_model.save` will no longer write SavedModels that can be recovered as Keras models (this will apply in TF 2.5).

FOR DEVS: If you are overwriting _tracking_metadata in your class, this property has been used to save metadata in the SavedModel. The metadta field will be deprecated soon, so please move the metadata to a different file.
INFO:tensorflow:Assets written to: translator/assets
INFO:tensorflow:Assets written to: translator/assets
reloaded = tf.saved_model.load('translator')
result = reloaded.tf_translate(three_input_text)
%%time
result = reloaded.tf_translate(three_input_text)

for tr in result['text']:
  print(tr.numpy().decode())

print()
this is my life .
are you still at home ?
lets try to figure out .

CPU times: user 167 ms, sys: 5.11 ms, total: 172 ms
Wall time: 35.4 ms

Sonraki adımlar