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

Mô hình biến áp để hiểu ngôn ngữ

Xem trên TensorFlow.org Chạy trong Google Colab Xem nguồn trên GitHub Tải xuống sổ ghi chép

Hướng dẫn này đào tạo mô hình Transformer để dịchtập dữ liệu từ tiếng Bồ Đào Nha sang tiếng Anh . Đây là một ví dụ nâng cao giả định kiến ​​thức về tạochú ý văn bản .

Ý tưởng cốt lõi đằng sau mô hình Máy biến áp là khả năng tự chú ý — khả năng chú ý đến các vị trí khác nhau của trình tự đầu vào để tính toán biểu diễn của trình tự đó. Transformer tạo ra các lớp tự chú ý và được giải thích bên dưới trong các phần Chú ý sản phẩm chấm theo tỷ lệChú ý nhiều đầu .

Mô hình máy biến áp xử lý đầu vào có kích thước thay đổi bằng cách sử dụng các lớp tự chú ý thay vì RNN hoặc CNN . Kiến trúc chung này có một số ưu điểm:

  • Nó không đưa ra giả định về các mối quan hệ thời gian / không gian trên dữ liệu. Điều này lý tưởng để xử lý một tập hợp các đối tượng (ví dụ, các đơn vị StarCraft ).
  • Các kết quả đầu ra của lớp có thể được tính toán song song, thay vì một chuỗi như RNN.
  • Các mục ở xa có thể ảnh hưởng đến đầu ra của nhau mà không cần chuyển qua nhiều bước RNN, hoặc các lớp tích chập (ví dụ: xem Bộ biến đổi bộ nhớ cảnh ).
  • Nó có thể học các phụ thuộc tầm xa. Đây là một thách thức trong nhiều nhiệm vụ trình tự.

Nhược điểm của kiến ​​trúc này là:

  • Đối với chuỗi thời gian, đầu ra cho một bước thời gian được tính toán từ toàn bộ lịch sử thay vì chỉ các đầu vào và trạng thái ẩn hiện tại. Điều này thể kém hiệu quả hơn.
  • Nếu đầu vào không có một thời gian / mối quan hệ không gian, như văn bản, một số mã hóa vị trí phải được bổ sung hoặc các mô hình có hiệu quả sẽ nhìn thấy một túi từ.

Sau khi huấn luyện mô hình trong sổ tay này, bạn sẽ có thể nhập một câu tiếng Bồ Đào Nha và gửi lại bản dịch tiếng Anh.

Bản đồ nhiệt chú ý

Thiết lập

pip install -q tensorflow_datasets
pip install -q -U tensorflow-text
import collections
import logging
import os
import pathlib
import re
import string
import sys
import time

import numpy as np
import matplotlib.pyplot as plt

import tensorflow_datasets as tfds
import tensorflow_text as text
import tensorflow as tf
logging.getLogger('tensorflow').setLevel(logging.ERROR)  # suppress warnings

Tải xuống tập dữ liệu

Sử dụng bộ dữ liệu TensorFlow để tải bộ dữ liệu dịch tiếng Bồ Đào Nha-Anh từ Dự án dịch mở TED Talks .

Tập dữ liệu này chứa khoảng 50000 ví dụ đào tạo, 1100 ví dụ xác thực và 2000 ví dụ kiểm tra.

examples, metadata = tfds.load('ted_hrlr_translate/pt_to_en', with_info=True,
                               as_supervised=True)
train_examples, val_examples = examples['train'], examples['validation']

Đối tượngtf.data.Dataset trả về bởi tập dữ liệu TensorFlow mang lại các cặp ví dụ văn bản:

for pt_examples, en_examples in train_examples.batch(3).take(1):
  for pt in pt_examples.numpy():
    print(pt.decode('utf-8'))

  print()

  for en in en_examples.numpy():
    print(en.decode('utf-8'))
e quando melhoramos a procura , tiramos a única vantagem da impressão , que é a serendipidade .
mas e se estes fatores fossem ativos ?
mas eles não tinham a curiosidade de me testar .

and when you improve searchability , you actually take away the one advantage of print , which is serendipity .
but what if it were active ?
but they did n't test for curiosity .

Mã hóa và tách văn bản

Bạn không thể đào tạo một mô hình trực tiếp trên văn bản. Trước tiên, văn bản cần được chuyển đổi thành một số biểu diễn số. Thông thường, bạn chuyển đổi văn bản thành chuỗi ID mã thông báo, chúng ở dạng chỉ mục thành một bản nhúng.

Một cách triển khai phổ biến được trình bày trong hướng dẫn tạo mã định danh từ phụ là xây dựng bộ tách mật khẩu phụ ( text.BertTokenizer ) được tối ưu hóa cho tập dữ liệu này và xuất chúng trong một kiểu mẫu đã lưu .

Tải xuống và giải nén và nhập mẫu đã saved_model :

model_name = "ted_hrlr_translate_pt_en_converter"
tf.keras.utils.get_file(
    f"{model_name}.zip",
    f"https://storage.googleapis.com/download.tensorflow.org/models/{model_name}.zip",
    cache_dir='.', cache_subdir='', extract=True
)
Downloading data from https://storage.googleapis.com/download.tensorflow.org/models/ted_hrlr_translate_pt_en_converter.zip
188416/184801 [==============================] - 0s 0us/step
'./ted_hrlr_translate_pt_en_converter.zip'
tokenizers = tf.saved_model.load(model_name)

tf.saved_model chứa hai văn bản tokenizer, một cho tiếng Anh và một cho tiếng Bồ Đào Nha. Cả hai đều có các phương pháp giống nhau:

[item for item in dir(tokenizers.en) if not item.startswith('_')]
['detokenize',
 'get_reserved_tokens',
 'get_vocab_path',
 'get_vocab_size',
 'lookup',
 'tokenize',
 'tokenizer',
 'vocab']

Các tokenize phương pháp chuyển đổi một loạt chuỗi đến một đệm-lô ID token. Phương pháp này tách dấu câu, chữ thường và unicode-chuẩn hóa đầu vào trước khi mã hóa. Sự chuẩn hóa đó không hiển thị ở đây vì dữ liệu đầu vào đã được chuẩn hóa.

for en in en_examples.numpy():
  print(en.decode('utf-8'))
and when you improve searchability , you actually take away the one advantage of print , which is serendipity .
but what if it were active ?
but they did n't test for curiosity .
encoded = tokenizers.en.tokenize(en_examples)

for row in encoded.to_list():
  print(row)
[2, 72, 117, 79, 1259, 1491, 2362, 13, 79, 150, 184, 311, 71, 103, 2308, 74, 2679, 13, 148, 80, 55, 4840, 1434, 2423, 540, 15, 3]
[2, 87, 90, 107, 76, 129, 1852, 30, 3]
[2, 87, 83, 149, 50, 9, 56, 664, 85, 2512, 15, 3]

Phương thức detokenize cố gắng chuyển đổi các ID mã thông báo này trở lại thành văn bản có thể đọc được của con người:

round_trip = tokenizers.en.detokenize(encoded)
for line in round_trip.numpy():
  print(line.decode('utf-8'))
and when you improve searchability , you actually take away the one advantage of print , which is serendipity .
but what if it were active ?
but they did n ' t test for curiosity .

Phương pháp lookup cấp thấp hơn chuyển đổi từ mã thông báo-ID thành văn bản mã thông báo:

tokens = tokenizers.en.lookup(encoded)
tokens
<tf.RaggedTensor [[b'[START]', b'and', b'when', b'you', b'improve', b'search', b'##ability', b',', b'you', b'actually', b'take', b'away', b'the', b'one', b'advantage', b'of', b'print', b',', b'which', b'is', b's', b'##ere', b'##nd', b'##ip', b'##ity', b'.', b'[END]'], [b'[START]', b'but', b'what', b'if', b'it', b'were', b'active', b'?', b'[END]'], [b'[START]', b'but', b'they', b'did', b'n', b"'", b't', b'test', b'for', b'curiosity', b'.', b'[END]']]>

Ở đây bạn có thể thấy khía cạnh "subword" của tokenizers. Từ "khả năng tìm kiếm" được phân tách thành "khả năng tìm kiếm ##" và từ "khả năng tìm kiếm" thành "s ##rect ## nd ## ip ## ity"

Thiết lập đường dẫn đầu vào

Để xây dựng một đường dẫn đầu vào phù hợp cho việc đào tạo, bạn sẽ áp dụng một số biến đổi cho tập dữ liệu.

Hàm này sẽ được sử dụng để mã hóa các lô văn bản thô:

def tokenize_pairs(pt, en):
    pt = tokenizers.pt.tokenize(pt)
    # Convert from ragged to dense, padding with zeros.
    pt = pt.to_tensor()

    en = tokenizers.en.tokenize(en)
    # Convert from ragged to dense, padding with zeros.
    en = en.to_tensor()
    return pt, en

Đây là một đường dẫn đầu vào đơn giản có thể xử lý, xáo trộn và phân lô dữ liệu:

BUFFER_SIZE = 20000
BATCH_SIZE = 64
def make_batches(ds):
  return (
      ds
      .cache()
      .shuffle(BUFFER_SIZE)
      .batch(BATCH_SIZE)
      .map(tokenize_pairs, num_parallel_calls=tf.data.AUTOTUNE)
      .prefetch(tf.data.AUTOTUNE))


train_batches = make_batches(train_examples)
val_batches = make_batches(val_examples)

Mã hóa vị trí

Vì mô hình này không chứa bất kỳ sự lặp lại hoặc tích chập nào, nên mã hóa vị trí được thêm vào để cung cấp cho mô hình một số thông tin về vị trí tương đối của các từ trong câu.

Vectơ mã hóa vị trí được thêm vào vectơ nhúng. Nhúng đại diện cho một mã thông báo trong không gian d chiều nơi các mã thông báo có ý nghĩa tương tự sẽ gần nhau hơn. Nhưng các nhúng không mã hóa vị trí tương đối của các từ trong một câu. Vì vậy, sau khi thêm mã hóa vị trí, các từ sẽ gần nhau hơn dựa trên sự giống nhau về nghĩa của chúng và vị trí của chúng trong câu , trong không gian d chiều.

Công thức tính toán mã hóa vị trí như sau:

$$\Large{PE_{(pos, 2i)} = \sin(pos / 10000^{2i / d_{model} })} $$
$$\Large{PE_{(pos, 2i+1)} = \cos(pos / 10000^{2i / d_{model} })} $$
def get_angles(pos, i, d_model):
  angle_rates = 1 / np.power(10000, (2 * (i//2)) / np.float32(d_model))
  return pos * angle_rates
def positional_encoding(position, d_model):
  angle_rads = get_angles(np.arange(position)[:, np.newaxis],
                          np.arange(d_model)[np.newaxis, :],
                          d_model)

  # apply sin to even indices in the array; 2i
  angle_rads[:, 0::2] = np.sin(angle_rads[:, 0::2])

  # apply cos to odd indices in the array; 2i+1
  angle_rads[:, 1::2] = np.cos(angle_rads[:, 1::2])

  pos_encoding = angle_rads[np.newaxis, ...]

  return tf.cast(pos_encoding, dtype=tf.float32)
n, d = 2048, 512
pos_encoding = positional_encoding(n, d)
print(pos_encoding.shape)
pos_encoding = pos_encoding[0]

# Juggle the dimensions for the plot
pos_encoding = tf.reshape(pos_encoding, (n, d//2, 2))
pos_encoding = tf.transpose(pos_encoding, (2, 1, 0))
pos_encoding = tf.reshape(pos_encoding, (d, n))

plt.pcolormesh(pos_encoding, cmap='RdBu')
plt.ylabel('Depth')
plt.xlabel('Position')
plt.colorbar()
plt.show()
(1, 2048, 512)

png

Đắp mặt nạ

Che dấu tất cả các mã thông báo pad trong loạt chuỗi. Nó đảm bảo rằng mô hình không coi padding là đầu vào. Mặt nạ cho biết vị trí có giá trị pad 0 : nó xuất ra giá trị 1 tại những vị trí đó và 0 nếu không.

def create_padding_mask(seq):
  seq = tf.cast(tf.math.equal(seq, 0), tf.float32)

  # add extra dimensions to add the padding
  # to the attention logits.
  return seq[:, tf.newaxis, tf.newaxis, :]  # (batch_size, 1, 1, seq_len)
x = tf.constant([[7, 6, 0, 0, 1], [1, 2, 3, 0, 0], [0, 0, 0, 4, 5]])
create_padding_mask(x)
<tf.Tensor: shape=(3, 1, 1, 5), dtype=float32, numpy=
array([[[[0., 0., 1., 1., 0.]]],


       [[[0., 0., 0., 1., 1.]]],


       [[[1., 1., 1., 0., 0.]]]], dtype=float32)>

Mặt nạ nhìn trước được sử dụng để che dấu các mã thông báo trong tương lai theo một trình tự. Nói cách khác, mặt nạ cho biết mục nào không nên được sử dụng.

Điều này có nghĩa là để dự đoán từ thứ ba, chỉ từ đầu tiên và từ thứ hai sẽ được sử dụng. Tương tự như vậy để dự đoán từ thứ tư, chỉ từ thứ nhất, thứ hai và thứ ba sẽ được sử dụng và cứ tiếp tục như vậy.

def create_look_ahead_mask(size):
  mask = 1 - tf.linalg.band_part(tf.ones((size, size)), -1, 0)
  return mask  # (seq_len, seq_len)
x = tf.random.uniform((1, 3))
temp = create_look_ahead_mask(x.shape[1])
temp
<tf.Tensor: shape=(3, 3), dtype=float32, numpy=
array([[0., 1., 1.],
       [0., 0., 1.],
       [0., 0., 0.]], dtype=float32)>

Sự chú ý của sản phẩm chấm theo tỷ lệ

scaled_dot_product_attention

Hàm chú ý được sử dụng bởi máy biến áp có ba đầu vào: Q (truy vấn), K (phím), V (giá trị). Phương trình được sử dụng để tính trọng số chú ý là:

$$\Large{Attention(Q, K, V) = softmax_k\left(\frac{QK^T}{\sqrt{d_k} }\right) V} $$

Sự chú ý của sản phẩm chấm được chia tỷ lệ bằng hệ số căn bậc hai của độ sâu. Điều này được thực hiện bởi vì đối với các giá trị lớn của độ sâu, sản phẩm chấm phát triển lớn về độ lớn đẩy hàm softmax ở nơi nó có độ dốc nhỏ dẫn đến softmax rất cứng.

Ví dụ, xem xét rằng QK có giá trị trung bình bằng 0 và phương sai là 1. Phép nhân ma trận của chúng sẽ có giá trị trung bình bằng 0 và phương sai là dk . Vì vậy, căn bậc hai của dk được sử dụng để chia tỷ lệ, vì vậy bạn sẽ nhận được một phương sai nhất quán bất kể giá trị của dk . Nếu phương sai quá thấp, đầu ra có thể quá phẳng để tối ưu hóa hiệu quả. Nếu phương sai quá cao, softmax có thể bão hòa khi bắt đầu làm cho việc tìm hiểu trở nên khó khăn hơn.

Mặt nạ được nhân với -1e9 (gần với âm vô cực). Điều này được thực hiện bởi vì mặt nạ được tính tổng với phép nhân ma trận tỷ lệ của Q và K và được áp dụng ngay trước một softmax. Mục đích là để loại bỏ các ô này và đầu vào âm lớn cho softmax gần bằng 0 trong đầu ra.

def scaled_dot_product_attention(q, k, v, mask):
  """Calculate the attention weights.
  q, k, v must have matching leading dimensions.
  k, v must have matching penultimate dimension, i.e.: seq_len_k = seq_len_v.
  The mask has different shapes depending on its type(padding or look ahead)
  but it must be broadcastable for addition.

  Args:
    q: query shape == (..., seq_len_q, depth)
    k: key shape == (..., seq_len_k, depth)
    v: value shape == (..., seq_len_v, depth_v)
    mask: Float tensor with shape broadcastable
          to (..., seq_len_q, seq_len_k). Defaults to None.

  Returns:
    output, attention_weights
  """

  matmul_qk = tf.matmul(q, k, transpose_b=True)  # (..., seq_len_q, seq_len_k)

  # scale matmul_qk
  dk = tf.cast(tf.shape(k)[-1], tf.float32)
  scaled_attention_logits = matmul_qk / tf.math.sqrt(dk)

  # add the mask to the scaled tensor.
  if mask is not None:
    scaled_attention_logits += (mask * -1e9)

  # softmax is normalized on the last axis (seq_len_k) so that the scores
  # add up to 1.
  attention_weights = tf.nn.softmax(scaled_attention_logits, axis=-1)  # (..., seq_len_q, seq_len_k)

  output = tf.matmul(attention_weights, v)  # (..., seq_len_q, depth_v)

  return output, attention_weights

Khi quá trình chuẩn hóa softmax được thực hiện trên K, các giá trị của nó quyết định mức độ quan trọng của Q.

Đầu ra đại diện cho phép nhân của trọng số chú ý và vectơ V (giá trị). Điều này đảm bảo rằng những từ bạn muốn tập trung được giữ nguyên và những từ không liên quan sẽ bị loại bỏ.

def print_out(q, k, v):
  temp_out, temp_attn = scaled_dot_product_attention(
      q, k, v, None)
  print('Attention weights are:')
  print(temp_attn)
  print('Output is:')
  print(temp_out)
np.set_printoptions(suppress=True)

temp_k = tf.constant([[10, 0, 0],
                      [0, 10, 0],
                      [0, 0, 10],
                      [0, 0, 10]], dtype=tf.float32)  # (4, 3)

temp_v = tf.constant([[1, 0],
                      [10, 0],
                      [100, 5],
                      [1000, 6]], dtype=tf.float32)  # (4, 2)

# This `query` aligns with the second `key`,
# so the second `value` is returned.
temp_q = tf.constant([[0, 10, 0]], dtype=tf.float32)  # (1, 3)
print_out(temp_q, temp_k, temp_v)
Attention weights are:
tf.Tensor([[0. 1. 0. 0.]], shape=(1, 4), dtype=float32)
Output is:
tf.Tensor([[10.  0.]], shape=(1, 2), dtype=float32)
# This query aligns with a repeated key (third and fourth),
# so all associated values get averaged.
temp_q = tf.constant([[0, 0, 10]], dtype=tf.float32)  # (1, 3)
print_out(temp_q, temp_k, temp_v)
Attention weights are:
tf.Tensor([[0.  0.  0.5 0.5]], shape=(1, 4), dtype=float32)
Output is:
tf.Tensor([[550.    5.5]], shape=(1, 2), dtype=float32)
# This query aligns equally with the first and second key,
# so their values get averaged.
temp_q = tf.constant([[10, 10, 0]], dtype=tf.float32)  # (1, 3)
print_out(temp_q, temp_k, temp_v)
Attention weights are:
tf.Tensor([[0.5 0.5 0.  0. ]], shape=(1, 4), dtype=float32)
Output is:
tf.Tensor([[5.5 0. ]], shape=(1, 2), dtype=float32)

Vượt qua tất cả các truy vấn cùng nhau.

temp_q = tf.constant([[0, 0, 10],
                      [0, 10, 0],
                      [10, 10, 0]], dtype=tf.float32)  # (3, 3)
print_out(temp_q, temp_k, temp_v)
Attention weights are:
tf.Tensor(
[[0.  0.  0.5 0.5]
 [0.  1.  0.  0. ]
 [0.5 0.5 0.  0. ]], shape=(3, 4), dtype=float32)
Output is:
tf.Tensor(
[[550.    5.5]
 [ 10.    0. ]
 [  5.5   0. ]], shape=(3, 2), dtype=float32)

Sự chú ý từ nhiều phía

sự chú ý nhiều đầu

Sự chú ý đa đầu bao gồm bốn phần:

  • Các lớp tuyến tính và chia thành các đầu.
  • Sự chú ý đến sản phẩm theo tỷ lệ.
  • Kết nối các đầu.
  • Lớp tuyến tính cuối cùng.

Mỗi khối chú ý nhiều đầu nhận được ba đầu vào; Q (truy vấn), K (khóa), V (giá trị). Chúng được đưa qua các lớp tuyến tính (Dày đặc) và chia thành nhiều đầu.

scaled_dot_product_attention được xác định ở trên được áp dụng cho mỗi head (được quảng bá để đạt hiệu quả). Trong bước chú ý phải sử dụng mặt nạ thích hợp. Đầu ra chú ý cho mỗi đầu sau đó được nối (sử dụng tf.transposetf.reshape ) và đưa qua một lớp Dense cuối cùng.

Thay vì một đầu chú ý duy nhất, Q, K và V được chia thành nhiều đầu vì nó cho phép mô hình cùng tham gia vào thông tin ở các vị trí khác nhau từ các không gian biểu diễn khác nhau. Sau khi tách, mỗi phần đầu có số chiều giảm, do đó, tổng chi phí tính toán giống như sự chú ý của phần đầu duy nhất với kích thước đầy đủ.

class MultiHeadAttention(tf.keras.layers.Layer):
  def __init__(self, d_model, num_heads):
    super(MultiHeadAttention, self).__init__()
    self.num_heads = num_heads
    self.d_model = d_model

    assert d_model % self.num_heads == 0

    self.depth = d_model // self.num_heads

    self.wq = tf.keras.layers.Dense(d_model)
    self.wk = tf.keras.layers.Dense(d_model)
    self.wv = tf.keras.layers.Dense(d_model)

    self.dense = tf.keras.layers.Dense(d_model)

  def split_heads(self, x, batch_size):
    """Split the last dimension into (num_heads, depth).
    Transpose the result such that the shape is (batch_size, num_heads, seq_len, depth)
    """
    x = tf.reshape(x, (batch_size, -1, self.num_heads, self.depth))
    return tf.transpose(x, perm=[0, 2, 1, 3])

  def call(self, v, k, q, mask):
    batch_size = tf.shape(q)[0]

    q = self.wq(q)  # (batch_size, seq_len, d_model)
    k = self.wk(k)  # (batch_size, seq_len, d_model)
    v = self.wv(v)  # (batch_size, seq_len, d_model)

    q = self.split_heads(q, batch_size)  # (batch_size, num_heads, seq_len_q, depth)
    k = self.split_heads(k, batch_size)  # (batch_size, num_heads, seq_len_k, depth)
    v = self.split_heads(v, batch_size)  # (batch_size, num_heads, seq_len_v, depth)

    # scaled_attention.shape == (batch_size, num_heads, seq_len_q, depth)
    # attention_weights.shape == (batch_size, num_heads, seq_len_q, seq_len_k)
    scaled_attention, attention_weights = scaled_dot_product_attention(
        q, k, v, mask)

    scaled_attention = tf.transpose(scaled_attention, perm=[0, 2, 1, 3])  # (batch_size, seq_len_q, num_heads, depth)

    concat_attention = tf.reshape(scaled_attention,
                                  (batch_size, -1, self.d_model))  # (batch_size, seq_len_q, d_model)

    output = self.dense(concat_attention)  # (batch_size, seq_len_q, d_model)

    return output, attention_weights

Tạo một lớp MultiHeadAttention để dùng thử. Tại mỗi vị trí trong chuỗi, y , MultiHeadAttention chạy tất cả 8 đầu chú ý trên tất cả các vị trí khác trong chuỗi, trả về một vectơ mới có cùng độ dài tại mỗi vị trí.

temp_mha = MultiHeadAttention(d_model=512, num_heads=8)
y = tf.random.uniform((1, 60, 512))  # (batch_size, encoder_sequence, d_model)
out, attn = temp_mha(y, k=y, q=y, mask=None)
out.shape, attn.shape
(TensorShape([1, 60, 512]), TensorShape([1, 8, 60, 60]))

Điểm mạng chuyển tiếp nguồn cấp dữ liệu khôn ngoan

Mạng chuyển tiếp nguồn cấp dữ liệu khôn ngoan bao gồm hai lớp được kết nối đầy đủ với kích hoạt ReLU ở giữa.

def point_wise_feed_forward_network(d_model, dff):
  return tf.keras.Sequential([
      tf.keras.layers.Dense(dff, activation='relu'),  # (batch_size, seq_len, dff)
      tf.keras.layers.Dense(d_model)  # (batch_size, seq_len, d_model)
  ])
sample_ffn = point_wise_feed_forward_network(512, 2048)
sample_ffn(tf.random.uniform((64, 50, 512))).shape
TensorShape([64, 50, 512])

Bộ mã hóa và giải mã

máy biến áp

Mô hình máy biến áp tuân theo cùng một mô hình chung như một trình tự tiêu chuẩn để trình tự với mô hình chú ý .

  • Câu đầu vào được chuyển qua N lớp mã hóa tạo ra kết quả đầu ra cho mỗi từ / mã thông báo trong chuỗi.
  • Bộ giải mã tập trung vào đầu ra của bộ mã hóa và đầu vào của chính nó (tự chú ý) để dự đoán từ tiếp theo.

Lớp mã hóa

Mỗi lớp mã hóa bao gồm các lớp con:

  1. Chú ý nhiều đầu (với mặt nạ đệm)
  2. Chỉ các mạng chuyển tiếp nguồn cấp dữ liệu khôn ngoan

Mỗi lớp con này có một kết nối dư xung quanh nó, theo sau là chuẩn hóa lớp. Các kết nối dư giúp tránh vấn đề độ dốc biến mất trong các mạng sâu.

Đầu ra của mỗi lớp con là LayerNorm(x + Sublayer(x)) . Quá trình chuẩn hóa được thực hiện trên d_model (cuối cùng). Có N lớp mã hóa trong máy biến áp.

class EncoderLayer(tf.keras.layers.Layer):
  def __init__(self, d_model, num_heads, dff, rate=0.1):
    super(EncoderLayer, self).__init__()

    self.mha = MultiHeadAttention(d_model, num_heads)
    self.ffn = point_wise_feed_forward_network(d_model, dff)

    self.layernorm1 = tf.keras.layers.LayerNormalization(epsilon=1e-6)
    self.layernorm2 = tf.keras.layers.LayerNormalization(epsilon=1e-6)

    self.dropout1 = tf.keras.layers.Dropout(rate)
    self.dropout2 = tf.keras.layers.Dropout(rate)

  def call(self, x, training, mask):

    attn_output, _ = self.mha(x, x, x, mask)  # (batch_size, input_seq_len, d_model)
    attn_output = self.dropout1(attn_output, training=training)
    out1 = self.layernorm1(x + attn_output)  # (batch_size, input_seq_len, d_model)

    ffn_output = self.ffn(out1)  # (batch_size, input_seq_len, d_model)
    ffn_output = self.dropout2(ffn_output, training=training)
    out2 = self.layernorm2(out1 + ffn_output)  # (batch_size, input_seq_len, d_model)

    return out2
sample_encoder_layer = EncoderLayer(512, 8, 2048)

sample_encoder_layer_output = sample_encoder_layer(
    tf.random.uniform((64, 43, 512)), False, None)

sample_encoder_layer_output.shape  # (batch_size, input_seq_len, d_model)
TensorShape([64, 43, 512])

Lớp giải mã

Mỗi lớp bộ giải mã bao gồm các lớp con:

  1. Mặt nạ gây chú ý nhiều đầu (với mặt nạ nhìn trước và mặt nạ đệm)
  2. Chú ý nhiều đầu (có đệm mặt nạ). V (giá trị) và K (phím) nhận đầu ra bộ mã hóa làm đầu vào. Q (truy vấn) nhận đầu ra từ lớp con chú ý nhiều đầu được che mặt nạ.
  3. Chỉ ra các mạng chuyển tiếp nguồn cấp dữ liệu khôn ngoan

Mỗi lớp con này có một kết nối dư xung quanh nó, theo sau là chuẩn hóa lớp. Đầu ra của mỗi lớp con là LayerNorm(x + Sublayer(x)) . Quá trình chuẩn hóa được thực hiện trên d_model (cuối cùng).

Có N lớp giải mã trong máy biến áp.

Khi Q nhận đầu ra từ khối chú ý đầu tiên của bộ giải mã và K nhận đầu ra của bộ mã hóa, trọng số chú ý thể hiện tầm quan trọng đối với đầu vào của bộ giải mã dựa trên đầu ra của bộ mã hóa. Nói cách khác, bộ giải mã dự đoán từ tiếp theo bằng cách xem đầu ra của bộ mã hóa và tự tham gia vào đầu ra của chính nó. Xem phần minh họa ở trên trong phần chú ý sản phẩm chấm theo tỷ lệ.

class DecoderLayer(tf.keras.layers.Layer):
  def __init__(self, d_model, num_heads, dff, rate=0.1):
    super(DecoderLayer, self).__init__()

    self.mha1 = MultiHeadAttention(d_model, num_heads)
    self.mha2 = MultiHeadAttention(d_model, num_heads)

    self.ffn = point_wise_feed_forward_network(d_model, dff)

    self.layernorm1 = tf.keras.layers.LayerNormalization(epsilon=1e-6)
    self.layernorm2 = tf.keras.layers.LayerNormalization(epsilon=1e-6)
    self.layernorm3 = tf.keras.layers.LayerNormalization(epsilon=1e-6)

    self.dropout1 = tf.keras.layers.Dropout(rate)
    self.dropout2 = tf.keras.layers.Dropout(rate)
    self.dropout3 = tf.keras.layers.Dropout(rate)

  def call(self, x, enc_output, training,
           look_ahead_mask, padding_mask):
    # enc_output.shape == (batch_size, input_seq_len, d_model)

    attn1, attn_weights_block1 = self.mha1(x, x, x, look_ahead_mask)  # (batch_size, target_seq_len, d_model)
    attn1 = self.dropout1(attn1, training=training)
    out1 = self.layernorm1(attn1 + x)

    attn2, attn_weights_block2 = self.mha2(
        enc_output, enc_output, out1, padding_mask)  # (batch_size, target_seq_len, d_model)
    attn2 = self.dropout2(attn2, training=training)
    out2 = self.layernorm2(attn2 + out1)  # (batch_size, target_seq_len, d_model)

    ffn_output = self.ffn(out2)  # (batch_size, target_seq_len, d_model)
    ffn_output = self.dropout3(ffn_output, training=training)
    out3 = self.layernorm3(ffn_output + out2)  # (batch_size, target_seq_len, d_model)

    return out3, attn_weights_block1, attn_weights_block2
sample_decoder_layer = DecoderLayer(512, 8, 2048)

sample_decoder_layer_output, _, _ = sample_decoder_layer(
    tf.random.uniform((64, 50, 512)), sample_encoder_layer_output,
    False, None, None)

sample_decoder_layer_output.shape  # (batch_size, target_seq_len, d_model)
TensorShape([64, 50, 512])

Mã hoá

Bộ Encoder bao gồm:

  1. Nhúng đầu vào
  2. Mã hóa vị trí
  3. N lớp mã hóa

Đầu vào được đưa qua một phép nhúng được tổng hợp bằng mã hóa vị trí. Đầu ra của tổng kết này là đầu vào cho các lớp mã hóa. Đầu ra của bộ mã hóa là đầu vào cho bộ giải mã.

class Encoder(tf.keras.layers.Layer):
  def __init__(self, num_layers, d_model, num_heads, dff, input_vocab_size,
               maximum_position_encoding, rate=0.1):
    super(Encoder, self).__init__()

    self.d_model = d_model
    self.num_layers = num_layers

    self.embedding = tf.keras.layers.Embedding(input_vocab_size, d_model)
    self.pos_encoding = positional_encoding(maximum_position_encoding,
                                            self.d_model)

    self.enc_layers = [EncoderLayer(d_model, num_heads, dff, rate)
                       for _ in range(num_layers)]

    self.dropout = tf.keras.layers.Dropout(rate)

  def call(self, x, training, mask):

    seq_len = tf.shape(x)[1]

    # adding embedding and position encoding.
    x = self.embedding(x)  # (batch_size, input_seq_len, d_model)
    x *= tf.math.sqrt(tf.cast(self.d_model, tf.float32))
    x += self.pos_encoding[:, :seq_len, :]

    x = self.dropout(x, training=training)

    for i in range(self.num_layers):
      x = self.enc_layers[i](x, training, mask)

    return x  # (batch_size, input_seq_len, d_model)
sample_encoder = Encoder(num_layers=2, d_model=512, num_heads=8,
                         dff=2048, input_vocab_size=8500,
                         maximum_position_encoding=10000)
temp_input = tf.random.uniform((64, 62), dtype=tf.int64, minval=0, maxval=200)

sample_encoder_output = sample_encoder(temp_input, training=False, mask=None)

print(sample_encoder_output.shape)  # (batch_size, input_seq_len, d_model)
(64, 62, 512)

Người giải mã

Bộ Decoder bao gồm:

  1. Nhúng đầu ra
  2. Mã hóa vị trí
  3. N lớp bộ giải mã

Mục tiêu được đưa qua một phép nhúng được tổng hợp bằng mã hóa vị trí. Đầu ra của phép tổng kết này là đầu vào cho các lớp giải mã. Đầu ra của bộ giải mã là đầu vào của lớp tuyến tính cuối cùng.

class Decoder(tf.keras.layers.Layer):
  def __init__(self, num_layers, d_model, num_heads, dff, target_vocab_size,
               maximum_position_encoding, rate=0.1):
    super(Decoder, self).__init__()

    self.d_model = d_model
    self.num_layers = num_layers

    self.embedding = tf.keras.layers.Embedding(target_vocab_size, d_model)
    self.pos_encoding = positional_encoding(maximum_position_encoding, d_model)

    self.dec_layers = [DecoderLayer(d_model, num_heads, dff, rate)
                       for _ in range(num_layers)]
    self.dropout = tf.keras.layers.Dropout(rate)

  def call(self, x, enc_output, training,
           look_ahead_mask, padding_mask):

    seq_len = tf.shape(x)[1]
    attention_weights = {}

    x = self.embedding(x)  # (batch_size, target_seq_len, d_model)
    x *= tf.math.sqrt(tf.cast(self.d_model, tf.float32))
    x += self.pos_encoding[:, :seq_len, :]

    x = self.dropout(x, training=training)

    for i in range(self.num_layers):
      x, block1, block2 = self.dec_layers[i](x, enc_output, training,
                                             look_ahead_mask, padding_mask)

      attention_weights[f'decoder_layer{i+1}_block1'] = block1
      attention_weights[f'decoder_layer{i+1}_block2'] = block2

    # x.shape == (batch_size, target_seq_len, d_model)
    return x, attention_weights
sample_decoder = Decoder(num_layers=2, d_model=512, num_heads=8,
                         dff=2048, target_vocab_size=8000,
                         maximum_position_encoding=5000)
temp_input = tf.random.uniform((64, 26), dtype=tf.int64, minval=0, maxval=200)

output, attn = sample_decoder(temp_input,
                              enc_output=sample_encoder_output,
                              training=False,
                              look_ahead_mask=None,
                              padding_mask=None)

output.shape, attn['decoder_layer2_block2'].shape
(TensorShape([64, 26, 512]), TensorShape([64, 8, 26, 62]))

Tạo máy biến áp

Máy biến áp bao gồm bộ mã hóa, bộ giải mã và một lớp tuyến tính cuối cùng. Đầu ra của bộ giải mã là đầu vào của lớp tuyến tính và đầu ra của nó được trả về.

class Transformer(tf.keras.Model):
  def __init__(self, num_layers, d_model, num_heads, dff, input_vocab_size,
               target_vocab_size, pe_input, pe_target, rate=0.1):
    super(Transformer, self).__init__()

    self.tokenizer = Encoder(num_layers, d_model, num_heads, dff,
                             input_vocab_size, pe_input, rate)

    self.decoder = Decoder(num_layers, d_model, num_heads, dff,
                           target_vocab_size, pe_target, rate)

    self.final_layer = tf.keras.layers.Dense(target_vocab_size)

  def call(self, inp, tar, training, enc_padding_mask,
           look_ahead_mask, dec_padding_mask):

    enc_output = self.tokenizer(inp, training, enc_padding_mask)  # (batch_size, inp_seq_len, d_model)

    # dec_output.shape == (batch_size, tar_seq_len, d_model)
    dec_output, attention_weights = self.decoder(
        tar, enc_output, training, look_ahead_mask, dec_padding_mask)

    final_output = self.final_layer(dec_output)  # (batch_size, tar_seq_len, target_vocab_size)

    return final_output, attention_weights
sample_transformer = Transformer(
    num_layers=2, d_model=512, num_heads=8, dff=2048,
    input_vocab_size=8500, target_vocab_size=8000,
    pe_input=10000, pe_target=6000)

temp_input = tf.random.uniform((64, 38), dtype=tf.int64, minval=0, maxval=200)
temp_target = tf.random.uniform((64, 36), dtype=tf.int64, minval=0, maxval=200)

fn_out, _ = sample_transformer(temp_input, temp_target, training=False,
                               enc_padding_mask=None,
                               look_ahead_mask=None,
                               dec_padding_mask=None)

fn_out.shape  # (batch_size, tar_seq_len, target_vocab_size)
TensorShape([64, 36, 8000])

Đặt siêu tham số

Để giữ cho ví dụ này nhỏ và tương đối nhanh, các giá trị cho num_layers, d_model và dff đã được giảm bớt.

Các giá trị được sử dụng trong mô hình cơ sở của máy biến áp là; num_layers = 6 , d_model = 512 , dff = 2048 . Xem bài báo về tất cả các phiên bản khác của máy biến áp.

num_layers = 4
d_model = 128
dff = 512
num_heads = 8
dropout_rate = 0.1

Trình tối ưu hóa

Sử dụng trình tối ưu hóa Adam với công cụ lập lịch tốc độ học tập tùy chỉnh theo công thức trong bài báo .

$$\Large{lrate = d_{model}^{-0.5} * \min(step{\_}num^{-0.5}, step{\_}num \cdot warmup{\_}steps^{-1.5})}$$
class CustomSchedule(tf.keras.optimizers.schedules.LearningRateSchedule):
  def __init__(self, d_model, warmup_steps=4000):
    super(CustomSchedule, self).__init__()

    self.d_model = d_model
    self.d_model = tf.cast(self.d_model, tf.float32)

    self.warmup_steps = warmup_steps

  def __call__(self, step):
    arg1 = tf.math.rsqrt(step)
    arg2 = step * (self.warmup_steps ** -1.5)

    return tf.math.rsqrt(self.d_model) * tf.math.minimum(arg1, arg2)
learning_rate = CustomSchedule(d_model)

optimizer = tf.keras.optimizers.Adam(learning_rate, beta_1=0.9, beta_2=0.98,
                                     epsilon=1e-9)
temp_learning_rate_schedule = CustomSchedule(d_model)

plt.plot(temp_learning_rate_schedule(tf.range(40000, dtype=tf.float32)))
plt.ylabel("Learning Rate")
plt.xlabel("Train Step")
Text(0.5, 0, 'Train Step')

png

Mất mát và số liệu

Vì các chuỗi mục tiêu được đệm, điều quan trọng là phải áp dụng mặt nạ đệm khi tính toán tổn thất.

loss_object = tf.keras.losses.SparseCategoricalCrossentropy(
    from_logits=True, reduction='none')
def loss_function(real, pred):
  mask = tf.math.logical_not(tf.math.equal(real, 0))
  loss_ = loss_object(real, pred)

  mask = tf.cast(mask, dtype=loss_.dtype)
  loss_ *= mask

  return tf.reduce_sum(loss_)/tf.reduce_sum(mask)


def accuracy_function(real, pred):
  accuracies = tf.equal(real, tf.argmax(pred, axis=2))

  mask = tf.math.logical_not(tf.math.equal(real, 0))
  accuracies = tf.math.logical_and(mask, accuracies)

  accuracies = tf.cast(accuracies, dtype=tf.float32)
  mask = tf.cast(mask, dtype=tf.float32)
  return tf.reduce_sum(accuracies)/tf.reduce_sum(mask)
train_loss = tf.keras.metrics.Mean(name='train_loss')
train_accuracy = tf.keras.metrics.Mean(name='train_accuracy')

Đào tạo và kiểm tra

transformer = Transformer(
    num_layers=num_layers,
    d_model=d_model,
    num_heads=num_heads,
    dff=dff,
    input_vocab_size=tokenizers.pt.get_vocab_size(),
    target_vocab_size=tokenizers.en.get_vocab_size(),
    pe_input=1000,
    pe_target=1000,
    rate=dropout_rate)
def create_masks(inp, tar):
  # Encoder padding mask
  enc_padding_mask = create_padding_mask(inp)

  # Used in the 2nd attention block in the decoder.
  # This padding mask is used to mask the encoder outputs.
  dec_padding_mask = create_padding_mask(inp)

  # Used in the 1st attention block in the decoder.
  # It is used to pad and mask future tokens in the input received by
  # the decoder.
  look_ahead_mask = create_look_ahead_mask(tf.shape(tar)[1])
  dec_target_padding_mask = create_padding_mask(tar)
  combined_mask = tf.maximum(dec_target_padding_mask, look_ahead_mask)

  return enc_padding_mask, combined_mask, dec_padding_mask

Tạo đường dẫn điểm kiểm tra và trình quản lý điểm kiểm tra. Điều này sẽ được sử dụng để lưu các điểm kiểm tra sau mỗi n kỷ nguyên.

checkpoint_path = "./checkpoints/train"

ckpt = tf.train.Checkpoint(transformer=transformer,
                           optimizer=optimizer)

ckpt_manager = tf.train.CheckpointManager(ckpt, checkpoint_path, max_to_keep=5)

# if a checkpoint exists, restore the latest checkpoint.
if ckpt_manager.latest_checkpoint:
  ckpt.restore(ckpt_manager.latest_checkpoint)
  print('Latest checkpoint restored!!')

Mục tiêu được chia thành tar_inp và tar_real. tar_inp được chuyển như một đầu vào cho bộ giải mã. tar_real là cùng một đầu vào được dịch chuyển bằng 1: Tại mỗi vị trí trong tar_input , tar_real chứa mã thông báo tiếp theo cần được dự đoán.

Ví dụ: sentence = "SOS Một con sư tử trong rừng đang ngủ EOS"

tar_inp = "SOS Một con sư tử trong rừng đang ngủ"

tar_real = "Một con sư tử trong rừng đang ngủ EOS"

Máy biến áp là một mô hình tự động hồi quy: nó đưa ra dự đoán từng phần một và sử dụng kết quả đầu ra của nó cho đến nay để quyết định phải làm gì tiếp theo.

Trong quá trình đào tạo, ví dụ này sử dụng giáo viên ép buộc (như trong hướng dẫn tạo văn bản ). Giáo viên buộc phải chuyển đầu ra thực sự cho bước thời gian tiếp theo bất kể mô hình dự đoán những gì ở bước thời gian hiện tại.

Khi máy biến áp dự đoán từng từ, khả năng tự chú ý cho phép nó nhìn vào các từ trước đó trong chuỗi đầu vào để dự đoán tốt hơn từ tiếp theo.

Để ngăn mô hình nhìn trộm đầu ra dự kiến, mô hình sử dụng mặt nạ nhìn trước.

EPOCHS = 20
# The @tf.function trace-compiles train_step into a TF graph for faster
# execution. The function specializes to the precise shape of the argument
# tensors. To avoid re-tracing due to the variable sequence lengths or variable
# batch sizes (the last batch is smaller), use input_signature to specify
# more generic shapes.

train_step_signature = [
    tf.TensorSpec(shape=(None, None), dtype=tf.int64),
    tf.TensorSpec(shape=(None, None), dtype=tf.int64),
]


@tf.function(input_signature=train_step_signature)
def train_step(inp, tar):
  tar_inp = tar[:, :-1]
  tar_real = tar[:, 1:]

  enc_padding_mask, combined_mask, dec_padding_mask = create_masks(inp, tar_inp)

  with tf.GradientTape() as tape:
    predictions, _ = transformer(inp, tar_inp,
                                 True,
                                 enc_padding_mask,
                                 combined_mask,
                                 dec_padding_mask)
    loss = loss_function(tar_real, predictions)

  gradients = tape.gradient(loss, transformer.trainable_variables)
  optimizer.apply_gradients(zip(gradients, transformer.trainable_variables))

  train_loss(loss)
  train_accuracy(accuracy_function(tar_real, predictions))

Tiếng Bồ Đào Nha được sử dụng làm ngôn ngữ đầu vào và tiếng Anh là ngôn ngữ đích.

for epoch in range(EPOCHS):
  start = time.time()

  train_loss.reset_states()
  train_accuracy.reset_states()

  # inp -> portuguese, tar -> english
  for (batch, (inp, tar)) in enumerate(train_batches):
    train_step(inp, tar)

    if batch % 50 == 0:
      print(f'Epoch {epoch + 1} Batch {batch} Loss {train_loss.result():.4f} Accuracy {train_accuracy.result():.4f}')

  if (epoch + 1) % 5 == 0:
    ckpt_save_path = ckpt_manager.save()
    print(f'Saving checkpoint for epoch {epoch+1} at {ckpt_save_path}')

  print(f'Epoch {epoch + 1} Loss {train_loss.result():.4f} Accuracy {train_accuracy.result():.4f}')

  print(f'Time taken for 1 epoch: {time.time() - start:.2f} secs\n')
Epoch 1 Batch 0 Loss 8.8558 Accuracy 0.0000
Epoch 1 Batch 50 Loss 8.7941 Accuracy 0.0113
Epoch 1 Batch 100 Loss 8.6918 Accuracy 0.0303
Epoch 1 Batch 150 Loss 8.5788 Accuracy 0.0362
Epoch 1 Batch 200 Loss 8.4405 Accuracy 0.0396
Epoch 1 Batch 250 Loss 8.2736 Accuracy 0.0436
Epoch 1 Batch 300 Loss 8.0848 Accuracy 0.0498
Epoch 1 Batch 350 Loss 7.8871 Accuracy 0.0555
Epoch 1 Batch 400 Loss 7.6974 Accuracy 0.0618
Epoch 1 Batch 450 Loss 7.5298 Accuracy 0.0692
Epoch 1 Batch 500 Loss 7.3837 Accuracy 0.0765
Epoch 1 Batch 550 Loss 7.2525 Accuracy 0.0833
Epoch 1 Batch 600 Loss 7.1255 Accuracy 0.0906
Epoch 1 Batch 650 Loss 7.0100 Accuracy 0.0978
Epoch 1 Batch 700 Loss 6.9013 Accuracy 0.1048
Epoch 1 Batch 750 Loss 6.8035 Accuracy 0.1108
Epoch 1 Batch 800 Loss 6.7117 Accuracy 0.1166
Epoch 1 Loss 6.6949 Accuracy 0.1177
Time taken for 1 epoch: 66.94 secs

Epoch 2 Batch 0 Loss 5.2170 Accuracy 0.1997
Epoch 2 Batch 50 Loss 5.2086 Accuracy 0.2170
Epoch 2 Batch 100 Loss 5.1816 Accuracy 0.2212
Epoch 2 Batch 150 Loss 5.1665 Accuracy 0.2217
Epoch 2 Batch 200 Loss 5.1439 Accuracy 0.2243
Epoch 2 Batch 250 Loss 5.1148 Accuracy 0.2269
Epoch 2 Batch 300 Loss 5.0844 Accuracy 0.2301
Epoch 2 Batch 350 Loss 5.0592 Accuracy 0.2325
Epoch 2 Batch 400 Loss 5.0369 Accuracy 0.2347
Epoch 2 Batch 450 Loss 5.0130 Accuracy 0.2367
Epoch 2 Batch 500 Loss 4.9936 Accuracy 0.2385
Epoch 2 Batch 550 Loss 4.9717 Accuracy 0.2404
Epoch 2 Batch 600 Loss 4.9526 Accuracy 0.2420
Epoch 2 Batch 650 Loss 4.9339 Accuracy 0.2434
Epoch 2 Batch 700 Loss 4.9164 Accuracy 0.2448
Epoch 2 Batch 750 Loss 4.8998 Accuracy 0.2463
Epoch 2 Batch 800 Loss 4.8838 Accuracy 0.2475
Epoch 2 Loss 4.8815 Accuracy 0.2477
Time taken for 1 epoch: 51.61 secs

Epoch 3 Batch 0 Loss 4.6161 Accuracy 0.2493
Epoch 3 Batch 50 Loss 4.5871 Accuracy 0.2683
Epoch 3 Batch 100 Loss 4.5917 Accuracy 0.2699
Epoch 3 Batch 150 Loss 4.5765 Accuracy 0.2721
Epoch 3 Batch 200 Loss 4.5632 Accuracy 0.2742
Epoch 3 Batch 250 Loss 4.5445 Accuracy 0.2761
Epoch 3 Batch 300 Loss 4.5358 Accuracy 0.2769
Epoch 3 Batch 350 Loss 4.5199 Accuracy 0.2785
Epoch 3 Batch 400 Loss 4.5038 Accuracy 0.2802
Epoch 3 Batch 450 Loss 4.4889 Accuracy 0.2816
Epoch 3 Batch 500 Loss 4.4749 Accuracy 0.2829
Epoch 3 Batch 550 Loss 4.4626 Accuracy 0.2845
Epoch 3 Batch 600 Loss 4.4488 Accuracy 0.2861
Epoch 3 Batch 650 Loss 4.4349 Accuracy 0.2876
Epoch 3 Batch 700 Loss 4.4193 Accuracy 0.2894
Epoch 3 Batch 750 Loss 4.4037 Accuracy 0.2912
Epoch 3 Batch 800 Loss 4.3916 Accuracy 0.2926
Epoch 3 Loss 4.3878 Accuracy 0.2931
Time taken for 1 epoch: 50.36 secs

Epoch 4 Batch 0 Loss 4.1716 Accuracy 0.3411
Epoch 4 Batch 50 Loss 4.0858 Accuracy 0.3265
Epoch 4 Batch 100 Loss 4.0645 Accuracy 0.3278
Epoch 4 Batch 150 Loss 4.0457 Accuracy 0.3298
Epoch 4 Batch 200 Loss 4.0308 Accuracy 0.3320
Epoch 4 Batch 250 Loss 4.0184 Accuracy 0.3342
Epoch 4 Batch 300 Loss 4.0023 Accuracy 0.3367
Epoch 4 Batch 350 Loss 3.9890 Accuracy 0.3384
Epoch 4 Batch 400 Loss 3.9712 Accuracy 0.3407
Epoch 4 Batch 450 Loss 3.9585 Accuracy 0.3427
Epoch 4 Batch 500 Loss 3.9450 Accuracy 0.3443
Epoch 4 Batch 550 Loss 3.9288 Accuracy 0.3466
Epoch 4 Batch 600 Loss 3.9168 Accuracy 0.3485
Epoch 4 Batch 650 Loss 3.9013 Accuracy 0.3505
Epoch 4 Batch 700 Loss 3.8833 Accuracy 0.3531
Epoch 4 Batch 750 Loss 3.8668 Accuracy 0.3552
Epoch 4 Batch 800 Loss 3.8527 Accuracy 0.3570
Epoch 4 Loss 3.8494 Accuracy 0.3574
Time taken for 1 epoch: 50.26 secs

Epoch 5 Batch 0 Loss 3.8260 Accuracy 0.3580
Epoch 5 Batch 50 Loss 3.5539 Accuracy 0.3915
Epoch 5 Batch 100 Loss 3.5356 Accuracy 0.3944
Epoch 5 Batch 150 Loss 3.5221 Accuracy 0.3960
Epoch 5 Batch 200 Loss 3.5098 Accuracy 0.3984
Epoch 5 Batch 250 Loss 3.4993 Accuracy 0.4000
Epoch 5 Batch 300 Loss 3.4818 Accuracy 0.4023
Epoch 5 Batch 350 Loss 3.4718 Accuracy 0.4036
Epoch 5 Batch 400 Loss 3.4602 Accuracy 0.4054
Epoch 5 Batch 450 Loss 3.4553 Accuracy 0.4060
Epoch 5 Batch 500 Loss 3.4459 Accuracy 0.4072
Epoch 5 Batch 550 Loss 3.4369 Accuracy 0.4082
Epoch 5 Batch 600 Loss 3.4268 Accuracy 0.4095
Epoch 5 Batch 650 Loss 3.4180 Accuracy 0.4107
Epoch 5 Batch 700 Loss 3.4098 Accuracy 0.4116
Epoch 5 Batch 750 Loss 3.4001 Accuracy 0.4130
Epoch 5 Batch 800 Loss 3.3902 Accuracy 0.4144
Saving checkpoint for epoch 5 at ./checkpoints/train/ckpt-1
Epoch 5 Loss 3.3886 Accuracy 0.4145
Time taken for 1 epoch: 50.26 secs

Epoch 6 Batch 0 Loss 3.2305 Accuracy 0.4274
Epoch 6 Batch 50 Loss 3.1070 Accuracy 0.4469
Epoch 6 Batch 100 Loss 3.0989 Accuracy 0.4480
Epoch 6 Batch 150 Loss 3.0913 Accuracy 0.4503
Epoch 6 Batch 200 Loss 3.0827 Accuracy 0.4511
Epoch 6 Batch 250 Loss 3.0724 Accuracy 0.4526
Epoch 6 Batch 300 Loss 3.0657 Accuracy 0.4533
Epoch 6 Batch 350 Loss 3.0588 Accuracy 0.4540
Epoch 6 Batch 400 Loss 3.0501 Accuracy 0.4551
Epoch 6 Batch 450 Loss 3.0423 Accuracy 0.4563
Epoch 6 Batch 500 Loss 3.0329 Accuracy 0.4577
Epoch 6 Batch 550 Loss 3.0213 Accuracy 0.4593
Epoch 6 Batch 600 Loss 3.0136 Accuracy 0.4604
Epoch 6 Batch 650 Loss 3.0092 Accuracy 0.4609
Epoch 6 Batch 700 Loss 3.0018 Accuracy 0.4620
Epoch 6 Batch 750 Loss 2.9960 Accuracy 0.4629
Epoch 6 Batch 800 Loss 2.9876 Accuracy 0.4641
Epoch 6 Loss 2.9864 Accuracy 0.4643
Time taken for 1 epoch: 50.22 secs

Epoch 7 Batch 0 Loss 2.7779 Accuracy 0.4791
Epoch 7 Batch 50 Loss 2.6971 Accuracy 0.4990
Epoch 7 Batch 100 Loss 2.6964 Accuracy 0.4987
Epoch 7 Batch 150 Loss 2.7011 Accuracy 0.4986
Epoch 7 Batch 200 Loss 2.7005 Accuracy 0.4985
Epoch 7 Batch 250 Loss 2.7022 Accuracy 0.4986
Epoch 7 Batch 300 Loss 2.6984 Accuracy 0.4993
Epoch 7 Batch 350 Loss 2.6945 Accuracy 0.5000
Epoch 7 Batch 400 Loss 2.6895 Accuracy 0.5007
Epoch 7 Batch 450 Loss 2.6839 Accuracy 0.5016
Epoch 7 Batch 500 Loss 2.6769 Accuracy 0.5027
Epoch 7 Batch 550 Loss 2.6753 Accuracy 0.5029
Epoch 7 Batch 600 Loss 2.6712 Accuracy 0.5039
Epoch 7 Batch 650 Loss 2.6669 Accuracy 0.5047
Epoch 7 Batch 700 Loss 2.6619 Accuracy 0.5054
Epoch 7 Batch 750 Loss 2.6572 Accuracy 0.5063
Epoch 7 Batch 800 Loss 2.6542 Accuracy 0.5070
Epoch 7 Loss 2.6539 Accuracy 0.5071
Time taken for 1 epoch: 49.96 secs

Epoch 8 Batch 0 Loss 2.5908 Accuracy 0.4879
Epoch 8 Batch 50 Loss 2.4337 Accuracy 0.5354
Epoch 8 Batch 100 Loss 2.4194 Accuracy 0.5378
Epoch 8 Batch 150 Loss 2.4183 Accuracy 0.5373
Epoch 8 Batch 200 Loss 2.4275 Accuracy 0.5359
Epoch 8 Batch 250 Loss 2.4308 Accuracy 0.5353
Epoch 8 Batch 300 Loss 2.4289 Accuracy 0.5358
Epoch 8 Batch 350 Loss 2.4248 Accuracy 0.5366
Epoch 8 Batch 400 Loss 2.4211 Accuracy 0.5374
Epoch 8 Batch 450 Loss 2.4217 Accuracy 0.5374
Epoch 8 Batch 500 Loss 2.4201 Accuracy 0.5380
Epoch 8 Batch 550 Loss 2.4151 Accuracy 0.5391
Epoch 8 Batch 600 Loss 2.4141 Accuracy 0.5394
Epoch 8 Batch 650 Loss 2.4134 Accuracy 0.5394
Epoch 8 Batch 700 Loss 2.4146 Accuracy 0.5393
Epoch 8 Batch 750 Loss 2.4118 Accuracy 0.5399
Epoch 8 Batch 800 Loss 2.4128 Accuracy 0.5398
Epoch 8 Loss 2.4124 Accuracy 0.5398
Time taken for 1 epoch: 49.98 secs

Epoch 9 Batch 0 Loss 2.1669 Accuracy 0.5637
Epoch 9 Batch 50 Loss 2.2551 Accuracy 0.5606
Epoch 9 Batch 100 Loss 2.2500 Accuracy 0.5597
Epoch 9 Batch 150 Loss 2.2465 Accuracy 0.5600
Epoch 9 Batch 200 Loss 2.2423 Accuracy 0.5608
Epoch 9 Batch 250 Loss 2.2466 Accuracy 0.5603
Epoch 9 Batch 300 Loss 2.2484 Accuracy 0.5603
Epoch 9 Batch 350 Loss 2.2467 Accuracy 0.5609
Epoch 9 Batch 400 Loss 2.2387 Accuracy 0.5621
Epoch 9 Batch 450 Loss 2.2362 Accuracy 0.5630
Epoch 9 Batch 500 Loss 2.2346 Accuracy 0.5634
Epoch 9 Batch 550 Loss 2.2358 Accuracy 0.5631
Epoch 9 Batch 600 Loss 2.2359 Accuracy 0.5629
Epoch 9 Batch 650 Loss 2.2359 Accuracy 0.5631
Epoch 9 Batch 700 Loss 2.2352 Accuracy 0.5634
Epoch 9 Batch 750 Loss 2.2361 Accuracy 0.5634
Epoch 9 Batch 800 Loss 2.2351 Accuracy 0.5636
Epoch 9 Loss 2.2346 Accuracy 0.5637
Time taken for 1 epoch: 50.26 secs

Epoch 10 Batch 0 Loss 2.0434 Accuracy 0.5841
Epoch 10 Batch 50 Loss 2.0855 Accuracy 0.5830
Epoch 10 Batch 100 Loss 2.0920 Accuracy 0.5820
Epoch 10 Batch 150 Loss 2.0839 Accuracy 0.5837
Epoch 10 Batch 200 Loss 2.0908 Accuracy 0.5822
Epoch 10 Batch 250 Loss 2.0956 Accuracy 0.5817
Epoch 10 Batch 300 Loss 2.0962 Accuracy 0.5817
Epoch 10 Batch 350 Loss 2.0950 Accuracy 0.5823
Epoch 10 Batch 400 Loss 2.0947 Accuracy 0.5824
Epoch 10 Batch 450 Loss 2.0947 Accuracy 0.5824
Epoch 10 Batch 500 Loss 2.0949 Accuracy 0.5826
Epoch 10 Batch 550 Loss 2.0923 Accuracy 0.5831
Epoch 10 Batch 600 Loss 2.0923 Accuracy 0.5832
Epoch 10 Batch 650 Loss 2.0930 Accuracy 0.5833
Epoch 10 Batch 700 Loss 2.0960 Accuracy 0.5830
Epoch 10 Batch 750 Loss 2.0973 Accuracy 0.5828
Epoch 10 Batch 800 Loss 2.0972 Accuracy 0.5829
Saving checkpoint for epoch 10 at ./checkpoints/train/ckpt-2
Epoch 10 Loss 2.0972 Accuracy 0.5829
Time taken for 1 epoch: 49.71 secs

Epoch 11 Batch 0 Loss 2.2026 Accuracy 0.5518
Epoch 11 Batch 50 Loss 1.9669 Accuracy 0.5998
Epoch 11 Batch 100 Loss 1.9626 Accuracy 0.6002
Epoch 11 Batch 150 Loss 1.9582 Accuracy 0.6014
Epoch 11 Batch 200 Loss 1.9593 Accuracy 0.6015
Epoch 11 Batch 250 Loss 1.9649 Accuracy 0.6008
Epoch 11 Batch 300 Loss 1.9684 Accuracy 0.6005
Epoch 11 Batch 350 Loss 1.9682 Accuracy 0.6009
Epoch 11 Batch 400 Loss 1.9685 Accuracy 0.6013
Epoch 11 Batch 450 Loss 1.9690 Accuracy 0.6011
Epoch 11 Batch 500 Loss 1.9720 Accuracy 0.6007
Epoch 11 Batch 550 Loss 1.9741 Accuracy 0.6003
Epoch 11 Batch 600 Loss 1.9763 Accuracy 0.6001
Epoch 11 Batch 650 Loss 1.9734 Accuracy 0.6006
Epoch 11 Batch 700 Loss 1.9774 Accuracy 0.6002
Epoch 11 Batch 750 Loss 1.9795 Accuracy 0.5999
Epoch 11 Batch 800 Loss 1.9842 Accuracy 0.5993
Epoch 11 Loss 1.9846 Accuracy 0.5993
Time taken for 1 epoch: 49.89 secs

Epoch 12 Batch 0 Loss 1.8384 Accuracy 0.6058
Epoch 12 Batch 50 Loss 1.8900 Accuracy 0.6093
Epoch 12 Batch 100 Loss 1.8634 Accuracy 0.6140
Epoch 12 Batch 150 Loss 1.8703 Accuracy 0.6141
Epoch 12 Batch 200 Loss 1.8669 Accuracy 0.6152
Epoch 12 Batch 250 Loss 1.8709 Accuracy 0.6149
Epoch 12 Batch 300 Loss 1.8742 Accuracy 0.6144
Epoch 12 Batch 350 Loss 1.8771 Accuracy 0.6142
Epoch 12 Batch 400 Loss 1.8820 Accuracy 0.6134
Epoch 12 Batch 450 Loss 1.8790 Accuracy 0.6139
Epoch 12 Batch 500 Loss 1.8782 Accuracy 0.6141
Epoch 12 Batch 550 Loss 1.8797 Accuracy 0.6141
Epoch 12 Batch 600 Loss 1.8820 Accuracy 0.6137
Epoch 12 Batch 650 Loss 1.8829 Accuracy 0.6136
Epoch 12 Batch 700 Loss 1.8849 Accuracy 0.6133
Epoch 12 Batch 750 Loss 1.8867 Accuracy 0.6131
Epoch 12 Batch 800 Loss 1.8896 Accuracy 0.6127
Epoch 12 Loss 1.8903 Accuracy 0.6126
Time taken for 1 epoch: 50.06 secs

Epoch 13 Batch 0 Loss 1.6479 Accuracy 0.6608
Epoch 13 Batch 50 Loss 1.7716 Accuracy 0.6323
Epoch 13 Batch 100 Loss 1.7785 Accuracy 0.6293
Epoch 13 Batch 150 Loss 1.7795 Accuracy 0.6284
Epoch 13 Batch 200 Loss 1.7808 Accuracy 0.6280
Epoch 13 Batch 250 Loss 1.7800 Accuracy 0.6286
Epoch 13 Batch 300 Loss 1.7849 Accuracy 0.6281
Epoch 13 Batch 350 Loss 1.7904 Accuracy 0.6273
Epoch 13 Batch 400 Loss 1.7904 Accuracy 0.6273
Epoch 13 Batch 450 Loss 1.7908 Accuracy 0.6275
Epoch 13 Batch 500 Loss 1.7919 Accuracy 0.6274
Epoch 13 Batch 550 Loss 1.7948 Accuracy 0.6270
Epoch 13 Batch 600 Loss 1.7991 Accuracy 0.6262
Epoch 13 Batch 650 Loss 1.8030 Accuracy 0.6257
Epoch 13 Batch 700 Loss 1.8050 Accuracy 0.6255
Epoch 13 Batch 750 Loss 1.8068 Accuracy 0.6252
Epoch 13 Batch 800 Loss 1.8086 Accuracy 0.6250
Epoch 13 Loss 1.8083 Accuracy 0.6251
Time taken for 1 epoch: 49.99 secs

Epoch 14 Batch 0 Loss 1.6837 Accuracy 0.6499
Epoch 14 Batch 50 Loss 1.6870 Accuracy 0.6426
Epoch 14 Batch 100 Loss 1.6901 Accuracy 0.6426
Epoch 14 Batch 150 Loss 1.6884 Accuracy 0.6427
Epoch 14 Batch 200 Loss 1.6995 Accuracy 0.6410
Epoch 14 Batch 250 Loss 1.7016 Accuracy 0.6413
Epoch 14 Batch 300 Loss 1.7053 Accuracy 0.6402
Epoch 14 Batch 350 Loss 1.7088 Accuracy 0.6395
Epoch 14 Batch 400 Loss 1.7150 Accuracy 0.6386
Epoch 14 Batch 450 Loss 1.7183 Accuracy 0.6380
Epoch 14 Batch 500 Loss 1.7208 Accuracy 0.6376
Epoch 14 Batch 550 Loss 1.7244 Accuracy 0.6372
Epoch 14 Batch 600 Loss 1.7274 Accuracy 0.6369
Epoch 14 Batch 650 Loss 1.7294 Accuracy 0.6367
Epoch 14 Batch 700 Loss 1.7325 Accuracy 0.6363
Epoch 14 Batch 750 Loss 1.7354 Accuracy 0.6359
Epoch 14 Batch 800 Loss 1.7379 Accuracy 0.6356
Epoch 14 Loss 1.7380 Accuracy 0.6356
Time taken for 1 epoch: 49.59 secs

Epoch 15 Batch 0 Loss 1.5566 Accuracy 0.6724
Epoch 15 Batch 50 Loss 1.6414 Accuracy 0.6479
Epoch 15 Batch 100 Loss 1.6533 Accuracy 0.6476
Epoch 15 Batch 150 Loss 1.6563 Accuracy 0.6472
Epoch 15 Batch 200 Loss 1.6639 Accuracy 0.6460
Epoch 15 Batch 250 Loss 1.6653 Accuracy 0.6456
Epoch 15 Batch 300 Loss 1.6642 Accuracy 0.6459
Epoch 15 Batch 350 Loss 1.6668 Accuracy 0.6455
Epoch 15 Batch 400 Loss 1.6649 Accuracy 0.6459
Epoch 15 Batch 450 Loss 1.6646 Accuracy 0.6458
Epoch 15 Batch 500 Loss 1.6688 Accuracy 0.6451
Epoch 15 Batch 550 Loss 1.6714 Accuracy 0.6445
Epoch 15 Batch 600 Loss 1.6716 Accuracy 0.6446
Epoch 15 Batch 650 Loss 1.6741 Accuracy 0.6444
Epoch 15 Batch 700 Loss 1.6760 Accuracy 0.6442
Epoch 15 Batch 750 Loss 1.6776 Accuracy 0.6440
Epoch 15 Batch 800 Loss 1.6784 Accuracy 0.6440
Saving checkpoint for epoch 15 at ./checkpoints/train/ckpt-3
Epoch 15 Loss 1.6787 Accuracy 0.6440
Time taken for 1 epoch: 49.62 secs

Epoch 16 Batch 0 Loss 1.5110 Accuracy 0.6664
Epoch 16 Batch 50 Loss 1.5818 Accuracy 0.6597
Epoch 16 Batch 100 Loss 1.5850 Accuracy 0.6585
Epoch 16 Batch 150 Loss 1.5859 Accuracy 0.6581
Epoch 16 Batch 200 Loss 1.5872 Accuracy 0.6579
Epoch 16 Batch 250 Loss 1.5946 Accuracy 0.6570
Epoch 16 Batch 300 Loss 1.5954 Accuracy 0.6568
Epoch 16 Batch 350 Loss 1.5995 Accuracy 0.6565
Epoch 16 Batch 400 Loss 1.6033 Accuracy 0.6558
Epoch 16 Batch 450 Loss 1.6056 Accuracy 0.6556
Epoch 16 Batch 500 Loss 1.6083 Accuracy 0.6552
Epoch 16 Batch 550 Loss 1.6087 Accuracy 0.6551
Epoch 16 Batch 600 Loss 1.6140 Accuracy 0.6542
Epoch 16 Batch 650 Loss 1.6166 Accuracy 0.6538
Epoch 16 Batch 700 Loss 1.6188 Accuracy 0.6535
Epoch 16 Batch 750 Loss 1.6223 Accuracy 0.6529
Epoch 16 Batch 800 Loss 1.6248 Accuracy 0.6524
Epoch 16 Loss 1.6252 Accuracy 0.6524
Time taken for 1 epoch: 49.52 secs

Epoch 17 Batch 0 Loss 1.5022 Accuracy 0.6761
Epoch 17 Batch 50 Loss 1.5280 Accuracy 0.6678
Epoch 17 Batch 100 Loss 1.5414 Accuracy 0.6649
Epoch 17 Batch 150 Loss 1.5421 Accuracy 0.6650
Epoch 17 Batch 200 Loss 1.5400 Accuracy 0.6652
Epoch 17 Batch 250 Loss 1.5464 Accuracy 0.6645
Epoch 17 Batch 300 Loss 1.5472 Accuracy 0.6645
Epoch 17 Batch 350 Loss 1.5531 Accuracy 0.6633
Epoch 17 Batch 400 Loss 1.5560 Accuracy 0.6627
Epoch 17 Batch 450 Loss 1.5598 Accuracy 0.6620
Epoch 17 Batch 500 Loss 1.5594 Accuracy 0.6622
Epoch 17 Batch 550 Loss 1.5632 Accuracy 0.6616
Epoch 17 Batch 600 Loss 1.5631 Accuracy 0.6618
Epoch 17 Batch 650 Loss 1.5649 Accuracy 0.6615
Epoch 17 Batch 700 Loss 1.5669 Accuracy 0.6613
Epoch 17 Batch 750 Loss 1.5699 Accuracy 0.6608
Epoch 17 Batch 800 Loss 1.5736 Accuracy 0.6602
Epoch 17 Loss 1.5745 Accuracy 0.6602
Time taken for 1 epoch: 49.84 secs

Epoch 18 Batch 0 Loss 1.5577 Accuracy 0.6591
Epoch 18 Batch 50 Loss 1.4857 Accuracy 0.6738
Epoch 18 Batch 100 Loss 1.4816 Accuracy 0.6751
Epoch 18 Batch 150 Loss 1.4805 Accuracy 0.6756
Epoch 18 Batch 200 Loss 1.4917 Accuracy 0.6734
Epoch 18 Batch 250 Loss 1.4963 Accuracy 0.6724
Epoch 18 Batch 300 Loss 1.5066 Accuracy 0.6707
Epoch 18 Batch 350 Loss 1.5111 Accuracy 0.6699
Epoch 18 Batch 400 Loss 1.5117 Accuracy 0.6696
Epoch 18 Batch 450 Loss 1.5146 Accuracy 0.6691
Epoch 18 Batch 500 Loss 1.5179 Accuracy 0.6686
Epoch 18 Batch 550 Loss 1.5192 Accuracy 0.6687
Epoch 18 Batch 600 Loss 1.5218 Accuracy 0.6682
Epoch 18 Batch 650 Loss 1.5245 Accuracy 0.6678
Epoch 18 Batch 700 Loss 1.5266 Accuracy 0.6674
Epoch 18 Batch 750 Loss 1.5294 Accuracy 0.6670
Epoch 18 Batch 800 Loss 1.5304 Accuracy 0.6670
Epoch 18 Loss 1.5313 Accuracy 0.6668
Time taken for 1 epoch: 49.40 secs

Epoch 19 Batch 0 Loss 1.6217 Accuracy 0.6528
Epoch 19 Batch 50 Loss 1.4279 Accuracy 0.6837
Epoch 19 Batch 100 Loss 1.4346 Accuracy 0.6831
Epoch 19 Batch 150 Loss 1.4409 Accuracy 0.6818
Epoch 19 Batch 200 Loss 1.4469 Accuracy 0.6808
Epoch 19 Batch 250 Loss 1.4542 Accuracy 0.6799
Epoch 19 Batch 300 Loss 1.4619 Accuracy 0.6784
Epoch 19 Batch 350 Loss 1.4641 Accuracy 0.6780
Epoch 19 Batch 400 Loss 1.4661 Accuracy 0.6775
Epoch 19 Batch 450 Loss 1.4688 Accuracy 0.6770
Epoch 19 Batch 500 Loss 1.4737 Accuracy 0.6761
Epoch 19 Batch 550 Loss 1.4764 Accuracy 0.6757
Epoch 19 Batch 600 Loss 1.4800 Accuracy 0.6750
Epoch 19 Batch 650 Loss 1.4839 Accuracy 0.6743
Epoch 19 Batch 700 Loss 1.4857 Accuracy 0.6740
Epoch 19 Batch 750 Loss 1.4896 Accuracy 0.6736
Epoch 19 Batch 800 Loss 1.4909 Accuracy 0.6735
Epoch 19 Loss 1.4912 Accuracy 0.6736
Time taken for 1 epoch: 49.29 secs

Epoch 20 Batch 0 Loss 1.3881 Accuracy 0.6962
Epoch 20 Batch 50 Loss 1.4189 Accuracy 0.6832
Epoch 20 Batch 100 Loss 1.4183 Accuracy 0.6848
Epoch 20 Batch 150 Loss 1.4153 Accuracy 0.6862
Epoch 20 Batch 200 Loss 1.4144 Accuracy 0.6865
Epoch 20 Batch 250 Loss 1.4187 Accuracy 0.6851
Epoch 20 Batch 300 Loss 1.4236 Accuracy 0.6840
Epoch 20 Batch 350 Loss 1.4297 Accuracy 0.6826
Epoch 20 Batch 400 Loss 1.4299 Accuracy 0.6826
Epoch 20 Batch 450 Loss 1.4331 Accuracy 0.6822
Epoch 20 Batch 500 Loss 1.4347 Accuracy 0.6820
Epoch 20 Batch 550 Loss 1.4376 Accuracy 0.6815
Epoch 20 Batch 600 Loss 1.4409 Accuracy 0.6810
Epoch 20 Batch 650 Loss 1.4433 Accuracy 0.6807
Epoch 20 Batch 700 Loss 1.4445 Accuracy 0.6806
Epoch 20 Batch 750 Loss 1.4505 Accuracy 0.6798
Epoch 20 Batch 800 Loss 1.4537 Accuracy 0.6791
Saving checkpoint for epoch 20 at ./checkpoints/train/ckpt-4
Epoch 20 Loss 1.4541 Accuracy 0.6791
Time taken for 1 epoch: 49.55 secs

Đánh giá

Các bước sau được sử dụng để đánh giá:

  • Mã hóa câu đầu vào bằng trình mã hóa tiếng Bồ Đào Nha ( tokenizers.pt ). Đây là đầu vào của bộ mã hóa.
  • Đầu vào của bộ giải mã được khởi tạo thành mã thông báo [START] .
  • Tính toán mặt nạ đệm và mặt nạ nhìn trước.
  • Sau đó, decoder sẽ đưa ra các dự đoán bằng cách xem encoder outputencoder output của chính nó (tự chú ý).
  • Mô hình đưa ra dự đoán của từ tiếp theo cho mỗi từ trong đầu ra. Hầu hết những thứ này là thừa. Sử dụng các dự đoán từ cuối cùng.
  • Nối từ dự đoán với đầu vào của bộ giải mã và chuyển nó đến bộ giải mã.
  • Trong cách tiếp cận này, bộ giải mã dự đoán từ tiếp theo dựa trên những từ trước đó nó đã dự đoán.
def evaluate(sentence, max_length=40):
  # inp sentence is portuguese, hence adding the start and end token
  sentence = tf.convert_to_tensor([sentence])
  sentence = tokenizers.pt.tokenize(sentence).to_tensor()

  encoder_input = sentence

  # as the target is english, the first word to the transformer should be the
  # english start token.
  start, end = tokenizers.en.tokenize([''])[0]
  output = tf.convert_to_tensor([start])
  output = tf.expand_dims(output, 0)

  for i in range(max_length):
    enc_padding_mask, combined_mask, dec_padding_mask = create_masks(
        encoder_input, output)

    # predictions.shape == (batch_size, seq_len, vocab_size)
    predictions, attention_weights = transformer(encoder_input,
                                                 output,
                                                 False,
                                                 enc_padding_mask,
                                                 combined_mask,
                                                 dec_padding_mask)

    # select the last word from the seq_len dimension
    predictions = predictions[:, -1:, :]  # (batch_size, 1, vocab_size)

    predicted_id = tf.argmax(predictions, axis=-1)

    # concatentate the predicted_id to the output which is given to the decoder
    # as its input.
    output = tf.concat([output, predicted_id], axis=-1)

    # return the result if the predicted_id is equal to the end token
    if predicted_id == end:
      break

  # output.shape (1, tokens)
  text = tokenizers.en.detokenize(output)[0]  # shape: ()

  tokens = tokenizers.en.lookup(output)[0]

  return text, tokens, attention_weights
def print_translation(sentence, tokens, ground_truth):
  print(f'{"Input:":15s}: {sentence}')
  print(f'{"Prediction":15s}: {tokens.numpy().decode("utf-8")}')
  print(f'{"Ground truth":15s}: {ground_truth}')
sentence = "este é um problema que temos que resolver."
ground_truth = "this is a problem we have to solve ."

translated_text, translated_tokens, attention_weights = evaluate(sentence)
print_translation(sentence, translated_text, ground_truth)
Input:         : este é um problema que temos que resolver.
Prediction     : this is a problem that we have to solve .
Ground truth   : this is a problem we have to solve .
sentence = "os meus vizinhos ouviram sobre esta ideia."
ground_truth = "and my neighboring homes heard about this idea ."

translated_text, translated_tokens, attention_weights = evaluate(sentence)
print_translation(sentence, translated_text, ground_truth)
Input:         : os meus vizinhos ouviram sobre esta ideia.
Prediction     : my neighbors have heard about this idea .
Ground truth   : and my neighboring homes heard about this idea .
sentence = "vou então muito rapidamente partilhar convosco algumas histórias de algumas coisas mágicas que aconteceram."
ground_truth = "so i \'ll just share with you some stories very quickly of some magical things that have happened ."

translated_text, translated_tokens, attention_weights = evaluate(sentence)
print_translation(sentence, translated_text, ground_truth)
Input:         : vou então muito rapidamente partilhar convosco algumas histórias de algumas coisas mágicas que aconteceram.
Prediction     : so i ' m so quickly share with you some magical stories of some magic things that happened .
Ground truth   : so i 'll just share with you some stories very quickly of some magical things that have happened .

Bạn có thể chuyển các lớp và khối chú ý khác nhau của bộ giải mã vào tham số plot .

Âm mưu chú ý

Hàm evaluate cũng trả về một từ điển bản đồ chú ý mà bạn có thể sử dụng để hình dung hoạt động bên trong của mô hình:

sentence = "este é o primeiro livro que eu fiz."
ground_truth = "this is the first book i've ever done."

translated_text, translated_tokens, attention_weights = evaluate(sentence)
print_translation(sentence, translated_text, ground_truth)
Input:         : este é o primeiro livro que eu fiz.
Prediction     : this is the first book that i did .
Ground truth   : this is the first book i've ever done.
def plot_attention_head(in_tokens, translated_tokens, attention):
  # The plot is of the attention when a token was generated.
  # The model didn't generate `<START>` in the output. Skip it.
  translated_tokens = translated_tokens[1:]

  ax = plt.gca()
  ax.matshow(attention)
  ax.set_xticks(range(len(in_tokens)))
  ax.set_yticks(range(len(translated_tokens)))

  labels = [label.decode('utf-8') for label in in_tokens.numpy()]
  ax.set_xticklabels(
      labels, rotation=90)

  labels = [label.decode('utf-8') for label in translated_tokens.numpy()]
  ax.set_yticklabels(labels)
head = 0
# shape: (batch=1, num_heads, seq_len_q, seq_len_k)
attention_heads = tf.squeeze(
  attention_weights['decoder_layer4_block2'], 0)
attention = attention_heads[head]
attention.shape
TensorShape([10, 11])
in_tokens = tf.convert_to_tensor([sentence])
in_tokens = tokenizers.pt.tokenize(in_tokens).to_tensor()
in_tokens = tokenizers.pt.lookup(in_tokens)[0]
in_tokens
<tf.Tensor: shape=(11,), dtype=string, numpy=
array([b'[START]', b'este', b'e', b'o', b'primeiro', b'livro', b'que',
       b'eu', b'fiz', b'.', b'[END]'], dtype=object)>
translated_tokens
<tf.Tensor: shape=(11,), dtype=string, numpy=
array([b'[START]', b'this', b'is', b'the', b'first', b'book', b'that',
       b'i', b'did', b'.', b'[END]'], dtype=object)>
plot_attention_head(in_tokens, translated_tokens, attention)

png

def plot_attention_weights(sentence, translated_tokens, attention_heads):
  in_tokens = tf.convert_to_tensor([sentence])
  in_tokens = tokenizers.pt.tokenize(in_tokens).to_tensor()
  in_tokens = tokenizers.pt.lookup(in_tokens)[0]
  in_tokens

  fig = plt.figure(figsize=(16, 8))

  for h, head in enumerate(attention_heads):
    ax = fig.add_subplot(2, 4, h+1)

    plot_attention_head(in_tokens, translated_tokens, head)

    ax.set_xlabel(f'Head {h+1}')

  plt.tight_layout()
  plt.show()
plot_attention_weights(sentence, translated_tokens,
                       attention_weights['decoder_layer4_block2'][0])

png

Mô hình không ổn đối với các từ không quen thuộc. Cả "triceratops" hoặc "bách khoa toàn thư" đều không có trong tập dữ liệu đầu vào và mô hình gần như học cách chuyển ngữ chúng, ngay cả khi không có từ vựng được chia sẻ:

sentence = "Eu li sobre triceratops na enciclopédia."
ground_truth = "I read about triceratops in the encyclopedia."

translated_text, translated_tokens, attention_weights = evaluate(sentence)
print_translation(sentence, translated_text, ground_truth)

plot_attention_weights(sentence, translated_tokens,
                       attention_weights['decoder_layer4_block2'][0])
Input:         : Eu li sobre triceratops na enciclopédia.
Prediction     : i read about triel - encompperate in the encyclopedia .
Ground truth   : I read about triceratops in the encyclopedia.

png

Tóm lược

Trong hướng dẫn này, bạn đã học về mã hóa vị trí, sự chú ý nhiều đầu, tầm quan trọng của việc che và cách tạo một máy biến áp.

Hãy thử sử dụng một tập dữ liệu khác để huấn luyện máy biến áp. Bạn cũng có thể tạo biến áp cơ sở hoặc biến áp XL bằng cách thay đổi các siêu tham số ở trên. Bạn cũng có thể sử dụng các lớp được xác định ở đây để tạo BERT và huấn luyện các mô hình hiện đại. Hơn nữa, bạn có thể triển khai tìm kiếm chùm tia để có được những dự đoán tốt hơn.