言語理解のためのTransformerモデル

TensorFlow.orgで表示 GoogleColabで実行 GitHubでソースを表示ノートブックをダウンロードする

このチュートリアルで列車はTransformerモデルを変換するポルトガル語、英語へのデータセットを。これは、の知識を前提と高度な例であるテキスト生成注意を

Transformerモデルの背後にある核となるアイデアは、その配列の表現を計算する入力シーケンスの異なる位置に出席するために-the能力自己注目です。変圧器は、自己の注目層のスタックを作成し、製品の注意マルチヘッドの注目ドットスケーリングのセクションで説明します。

代わりの自己注目層のスタックを用いて変圧器モデルハンドルの可変サイズ入力のRNN又はCNNsを。この一般的なアーキテクチャには、いくつかの利点があります。

  • データ全体の時間的/空間的関係については何も想定していません。これは、オブジェクトのセット(例えば、処理のために理想的であるスタークラフト単位)。
  • レイヤー出力は、RNNのような一連の出力ではなく、並列で計算できます。
  • 遠くの項目は、(参照、多くのRNN-段階、またはコンボリューション層を通過することなく、互いの出力に影響を与えることができますシーンメモリートランスなど)。
  • 長期的な依存関係を学習できます。これは、多くのシーケンスタスクでの課題です。

このアーキテクチャの欠点は次のとおりです。

  • 時系列のために、時間ステップの出力ではなく入力のみと現在の隠された状態の全体の履歴から計算されます。これはあまり効率的ではあります。
  • 入力は、時間的/空間的な関係を持っいる場合は、テキストのように、いくつかの位置エンコーディングが追加されなければならないか、モデルが効果的に言葉のバッグが表示されます。

このノートブックでモデルをトレーニングした後、ポルトガル語の文を入力して英語の翻訳を返すことができるようになります。

注意ヒートマップ

セットアップ

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
2021-07-08 11:06:56.882101: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcudart.so.11.0
logging.getLogger('tensorflow').setLevel(logging.ERROR)  # suppress warnings

データセットをダウンロードする

使用TensorFlowデータセットをロードするためにポルトガル語-英語の翻訳データセットからのTEDトークオープン翻訳プロジェクトを

このデータセットには、約50000のトレーニング例、1100の検証例、および2000のテスト例が含まれています。

examples, metadata = tfds.load('ted_hrlr_translate/pt_to_en', with_info=True,
                               as_supervised=True)
train_examples, val_examples = examples['train'], examples['validation']
2021-07-08 11:07:01.891325: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcuda.so.1
2021-07-08 11:07:02.567479: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-07-08 11:07:02.568175: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1733] Found device 0 with properties: 
pciBusID: 0000:00:05.0 name: NVIDIA Tesla V100-SXM2-16GB computeCapability: 7.0
coreClock: 1.53GHz coreCount: 80 deviceMemorySize: 15.78GiB deviceMemoryBandwidth: 836.37GiB/s
2021-07-08 11:07:02.568215: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcudart.so.11.0
2021-07-08 11:07:02.571596: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcublas.so.11
2021-07-08 11:07:02.571723: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcublasLt.so.11
2021-07-08 11:07:02.572867: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcufft.so.10
2021-07-08 11:07:02.573248: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcurand.so.10
2021-07-08 11:07:02.574372: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcusolver.so.11
2021-07-08 11:07:02.575325: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcusparse.so.11
2021-07-08 11:07:02.575514: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcudnn.so.8
2021-07-08 11:07:02.575612: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-07-08 11:07:02.576333: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-07-08 11:07:02.576942: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1871] Adding visible gpu devices: 0
2021-07-08 11:07:02.577664: I tensorflow/core/platform/cpu_feature_guard.cc:142] This TensorFlow binary is optimized with oneAPI Deep Neural Network Library (oneDNN) to use the following CPU instructions in performance-critical operations:  AVX2 AVX512F FMA
To enable them in other operations, rebuild TensorFlow with the appropriate compiler flags.
2021-07-08 11:07:02.578246: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-07-08 11:07:02.578904: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1733] Found device 0 with properties: 
pciBusID: 0000:00:05.0 name: NVIDIA Tesla V100-SXM2-16GB computeCapability: 7.0
coreClock: 1.53GHz coreCount: 80 deviceMemorySize: 15.78GiB deviceMemoryBandwidth: 836.37GiB/s
2021-07-08 11:07:02.578980: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-07-08 11:07:02.579656: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-07-08 11:07:02.580279: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1871] Adding visible gpu devices: 0
2021-07-08 11:07:02.580323: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcudart.so.11.0
2021-07-08 11:07:03.190409: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1258] Device interconnect StreamExecutor with strength 1 edge matrix:
2021-07-08 11:07:03.190462: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1264]      0 
2021-07-08 11:07:03.190470: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1277] 0:   N 
2021-07-08 11:07:03.190677: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-07-08 11:07:03.191419: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-07-08 11:07:03.192079: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-07-08 11:07:03.192729: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1418] Created TensorFlow device (/job:localhost/replica:0/task:0/device:GPU:0 with 14646 MB memory) -> physical GPU (device: 0, name: NVIDIA Tesla V100-SXM2-16GB, pci bus id: 0000:00:05.0, compute capability: 7.0)

tf.data.Datasetテキスト例のTensorFlowデータセット利回り対によって返されるオブジェクト:

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'))
2021-07-08 11:07:03.295521: I tensorflow/compiler/mlir/mlir_graph_optimization_pass.cc:176] None of the MLIR Optimization Passes are enabled (registered 2)
2021-07-08 11:07:03.296195: I tensorflow/core/platform/profile_utils/cpu_utils.cc:114] CPU Frequency: 2000170000 Hz
e quando melhoramos a procura , tiramos a \xfanica vantagem da impress\xe3o , que \xe9 a serendipidade .
mas e se estes fatores fossem ativos ?
mas eles n\xe3o 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 .

テキストのトークン化とトークン化解除

テキストでモデルを直接トレーニングすることはできません。最初に、テキストを何らかの数値表現に変換する必要があります。通常、テキストをトークンIDのシーケンスに変換します。これは、埋め込みへのインデックスとして使用されます。

1つの一般的な実装がで実証されたチュートリアルでは、トークナイザサブワードサブワードトークナイザ(ビルドをtext.BertTokenizerこのデータセットと、輸出、それらをするために最適化) saved_modelを

ダウンロードして解凍して、インポート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 2枚のテキストトークナイザ、英語用とポルトガル語のための1つを含んでいます。どちらも同じ方法です。

[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']

tokenize方法は、トークンIDのパディングされたバッチに文字列の一括変換します。このメソッドは、句読点、小文字、およびユニコードを分割します-トークン化する前に入力を正規化します。入力データはすでに標準化されているため、この標準化はここには表示されません。

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]

detokenizeバック人間が読めるテキストにこれらのトークンIDを変換するための方法を試み:

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 .

低いレベルlookupトークンテキストにトークンIDとは法の変換:

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]']]>

ここでは、トークナイザーの「サブワード」の側面を見ることができます。 「検索可能性」という単語は「検索##可能性」に分解され、「セリンディピティ」という単語は「s ## ere ## nd ## ip ## ity」に分解されます。

入力パイプラインを設定する

トレーニングに適した入力パイプラインを構築するには、データセットにいくつかの変換を適用します。

この関数は、生のテキストのバッチをエンコードするために使用されます。

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

データを処理、シャッフル、バッチ処理する単純な入力パイプラインは次のとおりです。

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)

位置エンコーディング

このモデルには漸化式や畳み込みが含まれていないため、文内の単語の相対位置に関する情報をモデルに提供するために、位置エンコードが追加されます。

位置符号化ベクトルが埋め込みベクトルに追加されます。埋め込みは、d次元空間内のトークンを表し、同様の意味を持つトークンが互いに近くなります。ただし、埋め込みは、文内の単語の相対位置をエンコードしません。そう位置エンコーディングを添加した後、単語はd次元空間において、その意味の類似性および文章中のそれらの位置に基づいて相互に近くなります。

位置エンコーディングの計算式は次のとおりです。

$$\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

マスキング

シーケンスのバッチ内のすべてのパッドトークンをマスクします。これにより、モデルがパディングを入力として扱わないことが保証されます。パッド値場所マスク示す0存在している:それは出力1それらの位置に、及び0そうでありません。

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)>

先読みマスクは、シーケンス内の将来のトークンをマスクするために使用されます。つまり、マスクはどのエントリを使用しないかを示します。

これは、3番目の単語を予測するために、最初と2番目の単語のみが使用されることを意味します。同様に、4番目の単語を予測するために、1番目、2番目、3番目の単語のみが使用されます。

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)>

スケーリングされたドット製品の注目

scaled_dot_product_attention

トランスフォーマーが使用するアテンション関数は、Q(クエリ)、K(キー)、V(値)の3つの入力を取ります。注意の重みを計算するために使用される式は次のとおりです。

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

内積の注意は、深さの平方根の係数でスケーリングされます。これが行われるのは、深さの値が大きい場合、ドット積が大きくなり、勾配が小さいソフトマックス関数を押して、非常にハードなソフトマックスになるためです。

例えば、と考えてQK平均0と1の分散彼らの行列乗算が0との分散の平均値になります持ってdk 。だから、の平方根dkあなたがの値に関係なく、一貫した分散を得るため、スケーリングのために使用されているdk 。分散が小さすぎると、出力が平坦すぎて効果的に最適化できない可能性があります。分散が大きすぎると、ソフトマックスが初期化で飽和し、学習が困難になる可能性があります。

マスクは-1e9(負の無限大に近い)で乗算されます。これは、マスクがQとKのスケーリングされた行列乗算で合計され、ソフトマックスの直前に適用されるために行われます。目標はこれらのセルをゼロにすることであり、softmaxへの大きな負の入力は出力でほぼゼロになります。

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

ソフトマックス正規化はKで行われるため、その値によってQに与えられる重要度が決まります。

出力は、注意の重みとV(値)ベクトルの乗算を表します。これにより、焦点を当てたい単語がそのまま保持され、無関係な単語がフラッシュされます。

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)
2021-07-08 11:07:08.703095: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcublas.so.11
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)
2021-07-08 11:07:09.081686: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcublasLt.so.11
# 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)

すべてのクエリを一緒に渡します。

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)

マルチヘッドアテンション

マルチヘッドアテンション

マルチヘッドアテンションは、次の4つの部分で構成されます。

  • 線形レイヤーとヘッドに分割。
  • スケーリングされたドット製品の注意。
  • 頭の連結。
  • 最終的な線形レイヤー。

各マルチヘッドアテンションブロックは3つの入力を取得します。 Q(クエリ)、K(キー)、V(値)。これらは線形(高密度)レイヤーを通過し、複数のヘッドに分割されます。

scaled_dot_product_attention上記で定義は、(効率のためにブロードキャスト)各ヘッドに適用されます。注意ステップでは、適切なマスクを使用する必要があります。各ヘッドの注目出力は、次に、(使用して連結されtf.transpose 、そしてtf.reshape )および最終通さDense層。

単一のアテンションヘッドの代わりに、Q、K、およびVは複数のヘッドに分割されます。これにより、モデルは、異なる位置にある異なる表現部分空間からの情報に共同で対応できるようになります。分割後、各ヘッドの次元が減少するため、計算コストの合計は、完全な次元の単一ヘッドの注意と同じになります。

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

作成MultiHeadAttention試して層を。シーケンス内の各位置で、 yMultiHeadAttention各位置で同じ長さの新しいベクトルを返し、シーケンス内の他のすべての場所にわたって全8つの注意ヘッドを実行します。

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]))

ポイントワイズフィードフォワードネットワーク

ポイントワイズフィードフォワードネットワークは、2つの完全に接続された層で構成され、その間にReLUアクティベーションがあります。

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])

エンコーダーとデコーダー

変成器

変圧器モデルは標準と同じ一般的なパターンは以下の注意モデルとシーケンスにシーケンスを

  • 入力文を通過させるNシーケンスにおけるトークン各単語/用の出力を生成するエンコーダ層。
  • デコーダーは、エンコーダーの出力とそれ自体の入力(自己注意)に注意を払い、次の単語を予測します。

エンコーダーレイヤー

各エンコーダーレイヤーは、サブレイヤーで構成されています。

  1. マルチヘッドアテンション(パディングマスク付き)
  2. ポイントワイズフィードフォワードネットワーク。

これらの各サブレイヤーには、その周囲に残りの接続があり、その後にレイヤーの正規化が続きます。残余接続は、深いネットワークでの勾配消失問題を回避するのに役立ちます。

各サブレイヤの出力はLayerNorm(x + Sublayer(x))正規化で行われd_model (最後)の軸。トランスにはN個のエンコーダ層があります。

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])

デコーダーレイヤー

各デコーダーレイヤーは、サブレイヤーで構成されています。

  1. マスクされたマルチヘッドアテンション(先読みマスクとパディングマスク付き)
  2. マルチヘッドアテンション(パディングマスク付き)。 V(値)とK(キー)を入力として、エンコーダの出力を受け取ります。 Q(クエリ)がマスクされたマルチヘッドの注目サブレイヤからの出力を受けます
  3. ポイントワイズフィードフォワードネットワーク

これらの各サブレイヤーには、その周囲に残りの接続があり、その後にレイヤーの正規化が続きます。各サブレイヤの出力はLayerNorm(x + Sublayer(x))正規化で行われd_model (最後)の軸。

トランスにはN個のデコーダ層があります。

Qがデコーダーの最初のアテンションブロックからの出力を受け取り、Kがエンコーダー出力を受け取るとき、アテンションウェイトはエンコーダーの出力に基づいてデコーダーの入力に与えられる重要性を表します。言い換えると、デコーダーは、エンコーダーの出力を調べて、自身の出力に自己応答することにより、次の単語を予測します。上記のスケーリングされたドット製品の注意セクションのデモンストレーションを参照してください。

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])

エンコーダー

Encoderで構成されています。

  1. 入力埋め込み
  2. 位置エンコーディング
  3. N個のエンコーダーレイヤー

入力は、位置エンコーディングと合計される埋め込みを通過します。この合計の出力は、エンコーダーレイヤーへの入力です。エンコーダーの出力はデコーダーへの入力です。

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)

デコーダ

Decoderで構成されています。

  1. 出力埋め込み
  2. 位置エンコーディング
  3. N個のデコーダーレイヤー

ターゲットは、位置エンコーディングと合計される埋め込みを通過します。この合計の出力は、デコーダー層への入力です。デコーダーの出力は、最終的な線形層への入力です。

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]))

トランスフォーマーを作成する

トランスフォーマーは、エンコーダー、デコーダー、および最終的な線形レイヤーで構成されます。デコーダーの出力は線形層への入力であり、その出力が返されます。

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.encoder = 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.encoder(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])

ハイパーパラメータを設定する

小型で比較的速い、num_layers、d_model、およびDFFの値が減少している。この例を維持すること。

変圧器の基本モデルで使用された値は次のとおりです。 num_layers = 6、d_model = 512、DFF = 2048。参照してください紙の変圧器の他のすべてのバージョンのために。

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

オプティマイザ

中式に従ってカスタム学習率スケジューラとアダム・オプティマイザを使用した紙

$$\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

損失と指標

ターゲットシーケンスはパディングされるため、損失を計算するときにパディングマスクを適用することが重要です。

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')

トレーニングとチェックポイント

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

チェックポイントパスとチェックポイントマネージャーを作成します。これは、チェックポイントごとに保存するために使用される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!!')

ターゲットはtar_inpとtar_realに分けられます。 tar_inpは、デコーダーへの入力として渡されます。 tar_real同じ入力が1だけシフトすることである:の各位置でtar_inputtar_real予測されるべき次のトークンを含みます。

例えば、 sentence =「ジャングルの中でSOS AライオンはEOSに眠っています」

tar_inp =「ジャングルの中でSOS Aライオンは寝ています」

tar_real =「ジャングルの中でライオンがEOSに眠っています」

トランスフォーマーは自己回帰モデルです。一度に1つの部分で予測を行い、これまでの出力を使用して次に何をするかを決定します。

この例を、トレーニング中に教師強制的に(のように使用するテキスト生成チュートリアル)。教師の強制は、モデルが現在のタイムステップで何を予測しているかに関係なく、真の出力を次のタイムステップに渡します。

変圧器は、それぞれの単語を予測したように、自己の注目は、それがより良い次の単語を予測するために、入力シーケンス内の前の単語を見ることができます。

モデルが期待される出力を覗き見するのを防ぐために、モデルは先読みマスクを使用します。

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))

入力言語としてポルトガル語が使用され、ターゲット言語は英語です。

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.8707 Accuracy 0.0000
Epoch 1 Batch 50 Loss 8.8072 Accuracy 0.0017
Epoch 1 Batch 100 Loss 8.6996 Accuracy 0.0249
Epoch 1 Batch 150 Loss 8.5796 Accuracy 0.0330
Epoch 1 Batch 200 Loss 8.4349 Accuracy 0.0369
Epoch 1 Batch 250 Loss 8.2633 Accuracy 0.0401
Epoch 1 Batch 300 Loss 8.0702 Accuracy 0.0488
Epoch 1 Batch 350 Loss 7.8725 Accuracy 0.0566
Epoch 1 Batch 400 Loss 7.6858 Accuracy 0.0646
Epoch 1 Batch 450 Loss 7.5170 Accuracy 0.0724
Epoch 1 Batch 500 Loss 7.3676 Accuracy 0.0796
Epoch 1 Batch 550 Loss 7.2332 Accuracy 0.0864
Epoch 1 Batch 600 Loss 7.1098 Accuracy 0.0936
Epoch 1 Batch 650 Loss 6.9939 Accuracy 0.1007
Epoch 1 Batch 700 Loss 6.8868 Accuracy 0.1073
Epoch 1 Batch 750 Loss 6.7882 Accuracy 0.1131
Epoch 1 Batch 800 Loss 6.6971 Accuracy 0.1187
Epoch 1 Loss 6.6815 Accuracy 0.1196
Time taken for 1 epoch: 62.90 secs

Epoch 2 Batch 0 Loss 5.3044 Accuracy 0.1971
Epoch 2 Batch 50 Loss 5.2654 Accuracy 0.2064
Epoch 2 Batch 100 Loss 5.2081 Accuracy 0.2128
Epoch 2 Batch 150 Loss 5.1838 Accuracy 0.2158
Epoch 2 Batch 200 Loss 5.1464 Accuracy 0.2194
Epoch 2 Batch 250 Loss 5.1202 Accuracy 0.2223
Epoch 2 Batch 300 Loss 5.1010 Accuracy 0.2243
Epoch 2 Batch 350 Loss 5.0770 Accuracy 0.2268
Epoch 2 Batch 400 Loss 5.0576 Accuracy 0.2290
Epoch 2 Batch 450 Loss 5.0360 Accuracy 0.2310
Epoch 2 Batch 500 Loss 5.0142 Accuracy 0.2332
Epoch 2 Batch 550 Loss 4.9944 Accuracy 0.2353
Epoch 2 Batch 600 Loss 4.9748 Accuracy 0.2370
Epoch 2 Batch 650 Loss 4.9564 Accuracy 0.2387
Epoch 2 Batch 700 Loss 4.9403 Accuracy 0.2404
Epoch 2 Batch 750 Loss 4.9225 Accuracy 0.2421
Epoch 2 Batch 800 Loss 4.9034 Accuracy 0.2440
Epoch 2 Loss 4.8998 Accuracy 0.2444
Time taken for 1 epoch: 49.91 secs

Epoch 3 Batch 0 Loss 4.7305 Accuracy 0.2408
Epoch 3 Batch 50 Loss 4.5827 Accuracy 0.2703
Epoch 3 Batch 100 Loss 4.5608 Accuracy 0.2727
Epoch 3 Batch 150 Loss 4.5528 Accuracy 0.2748
Epoch 3 Batch 200 Loss 4.5467 Accuracy 0.2765
Epoch 3 Batch 250 Loss 4.5297 Accuracy 0.2784
Epoch 3 Batch 300 Loss 4.5212 Accuracy 0.2795
Epoch 3 Batch 350 Loss 4.5021 Accuracy 0.2816
Epoch 3 Batch 400 Loss 4.4806 Accuracy 0.2840
Epoch 3 Batch 450 Loss 4.4646 Accuracy 0.2861
Epoch 3 Batch 500 Loss 4.4517 Accuracy 0.2876
Epoch 3 Batch 550 Loss 4.4381 Accuracy 0.2891
Epoch 3 Batch 600 Loss 4.4239 Accuracy 0.2908
Epoch 3 Batch 650 Loss 4.4090 Accuracy 0.2927
Epoch 3 Batch 700 Loss 4.3931 Accuracy 0.2944
Epoch 3 Batch 750 Loss 4.3753 Accuracy 0.2965
Epoch 3 Batch 800 Loss 4.3579 Accuracy 0.2987
Epoch 3 Loss 4.3555 Accuracy 0.2990
Time taken for 1 epoch: 50.01 secs

Epoch 4 Batch 0 Loss 4.0721 Accuracy 0.3377
Epoch 4 Batch 50 Loss 3.9834 Accuracy 0.3413
Epoch 4 Batch 100 Loss 3.9864 Accuracy 0.3406
Epoch 4 Batch 150 Loss 3.9786 Accuracy 0.3416
Epoch 4 Batch 200 Loss 3.9657 Accuracy 0.3439
Epoch 4 Batch 250 Loss 3.9558 Accuracy 0.3455
Epoch 4 Batch 300 Loss 3.9431 Accuracy 0.3475
Epoch 4 Batch 350 Loss 3.9333 Accuracy 0.3486
Epoch 4 Batch 400 Loss 3.9178 Accuracy 0.3504
Epoch 4 Batch 450 Loss 3.9007 Accuracy 0.3528
Epoch 4 Batch 500 Loss 3.8905 Accuracy 0.3541
Epoch 4 Batch 550 Loss 3.8733 Accuracy 0.3562
Epoch 4 Batch 600 Loss 3.8643 Accuracy 0.3571
Epoch 4 Batch 650 Loss 3.8486 Accuracy 0.3593
Epoch 4 Batch 700 Loss 3.8361 Accuracy 0.3609
Epoch 4 Batch 750 Loss 3.8247 Accuracy 0.3624
Epoch 4 Batch 800 Loss 3.8103 Accuracy 0.3644
Epoch 4 Loss 3.8085 Accuracy 0.3646
Time taken for 1 epoch: 49.71 secs

Epoch 5 Batch 0 Loss 3.7110 Accuracy 0.3674
Epoch 5 Batch 50 Loss 3.4971 Accuracy 0.3997
Epoch 5 Batch 100 Loss 3.4753 Accuracy 0.4034
Epoch 5 Batch 150 Loss 3.4749 Accuracy 0.4028
Epoch 5 Batch 200 Loss 3.4689 Accuracy 0.4033
Epoch 5 Batch 250 Loss 3.4604 Accuracy 0.4048
Epoch 5 Batch 300 Loss 3.4442 Accuracy 0.4071
Epoch 5 Batch 350 Loss 3.4375 Accuracy 0.4080
Epoch 5 Batch 400 Loss 3.4288 Accuracy 0.4094
Epoch 5 Batch 450 Loss 3.4218 Accuracy 0.4104
Epoch 5 Batch 500 Loss 3.4095 Accuracy 0.4120
Epoch 5 Batch 550 Loss 3.4026 Accuracy 0.4128
Epoch 5 Batch 600 Loss 3.3927 Accuracy 0.4140
Epoch 5 Batch 650 Loss 3.3852 Accuracy 0.4149
Epoch 5 Batch 700 Loss 3.3768 Accuracy 0.4163
Epoch 5 Batch 750 Loss 3.3687 Accuracy 0.4174
Epoch 5 Batch 800 Loss 3.3597 Accuracy 0.4187
Saving checkpoint for epoch 5 at ./checkpoints/train/ckpt-1
Epoch 5 Loss 3.3582 Accuracy 0.4189
Time taken for 1 epoch: 49.90 secs

Epoch 6 Batch 0 Loss 3.4475 Accuracy 0.3957
Epoch 6 Batch 50 Loss 3.0962 Accuracy 0.4477
Epoch 6 Batch 100 Loss 3.0798 Accuracy 0.4508
Epoch 6 Batch 150 Loss 3.0787 Accuracy 0.4510
Epoch 6 Batch 200 Loss 3.0601 Accuracy 0.4530
Epoch 6 Batch 250 Loss 3.0577 Accuracy 0.4536
Epoch 6 Batch 300 Loss 3.0457 Accuracy 0.4554
Epoch 6 Batch 350 Loss 3.0400 Accuracy 0.4561
Epoch 6 Batch 400 Loss 3.0303 Accuracy 0.4576
Epoch 6 Batch 450 Loss 3.0230 Accuracy 0.4587
Epoch 6 Batch 500 Loss 3.0081 Accuracy 0.4610
Epoch 6 Batch 550 Loss 3.0013 Accuracy 0.4621
Epoch 6 Batch 600 Loss 2.9921 Accuracy 0.4635
Epoch 6 Batch 650 Loss 2.9814 Accuracy 0.4653
Epoch 6 Batch 700 Loss 2.9738 Accuracy 0.4663
Epoch 6 Batch 750 Loss 2.9645 Accuracy 0.4676
Epoch 6 Batch 800 Loss 2.9575 Accuracy 0.4687
Epoch 6 Loss 2.9559 Accuracy 0.4690
Time taken for 1 epoch: 49.51 secs

Epoch 7 Batch 0 Loss 2.9116 Accuracy 0.4652
Epoch 7 Batch 50 Loss 2.6920 Accuracy 0.5008
Epoch 7 Batch 100 Loss 2.6726 Accuracy 0.5045
Epoch 7 Batch 150 Loss 2.6776 Accuracy 0.5042
Epoch 7 Batch 200 Loss 2.6715 Accuracy 0.5049
Epoch 7 Batch 250 Loss 2.6665 Accuracy 0.5056
Epoch 7 Batch 300 Loss 2.6618 Accuracy 0.5067
Epoch 7 Batch 350 Loss 2.6560 Accuracy 0.5075
Epoch 7 Batch 400 Loss 2.6515 Accuracy 0.5084
Epoch 7 Batch 450 Loss 2.6440 Accuracy 0.5092
Epoch 7 Batch 500 Loss 2.6372 Accuracy 0.5101
Epoch 7 Batch 550 Loss 2.6334 Accuracy 0.5108
Epoch 7 Batch 600 Loss 2.6284 Accuracy 0.5115
Epoch 7 Batch 650 Loss 2.6249 Accuracy 0.5122
Epoch 7 Batch 700 Loss 2.6191 Accuracy 0.5131
Epoch 7 Batch 750 Loss 2.6154 Accuracy 0.5137
Epoch 7 Batch 800 Loss 2.6133 Accuracy 0.5140
Epoch 7 Loss 2.6122 Accuracy 0.5142
Time taken for 1 epoch: 50.79 secs

Epoch 8 Batch 0 Loss 2.2190 Accuracy 0.5521
Epoch 8 Batch 50 Loss 2.3789 Accuracy 0.5434
Epoch 8 Batch 100 Loss 2.4058 Accuracy 0.5404
Epoch 8 Batch 150 Loss 2.3813 Accuracy 0.5438
Epoch 8 Batch 200 Loss 2.3857 Accuracy 0.5428
Epoch 8 Batch 250 Loss 2.3861 Accuracy 0.5430
Epoch 8 Batch 300 Loss 2.3847 Accuracy 0.5432
Epoch 8 Batch 350 Loss 2.3804 Accuracy 0.5441
Epoch 8 Batch 400 Loss 2.3820 Accuracy 0.5437
Epoch 8 Batch 450 Loss 2.3807 Accuracy 0.5442
Epoch 8 Batch 500 Loss 2.3789 Accuracy 0.5446
Epoch 8 Batch 550 Loss 2.3779 Accuracy 0.5448
Epoch 8 Batch 600 Loss 2.3762 Accuracy 0.5452
Epoch 8 Batch 650 Loss 2.3746 Accuracy 0.5456
Epoch 8 Batch 700 Loss 2.3757 Accuracy 0.5455
Epoch 8 Batch 750 Loss 2.3760 Accuracy 0.5456
Epoch 8 Batch 800 Loss 2.3746 Accuracy 0.5459
Epoch 8 Loss 2.3733 Accuracy 0.5461
Time taken for 1 epoch: 49.50 secs

Epoch 9 Batch 0 Loss 2.0450 Accuracy 0.5789
Epoch 9 Batch 50 Loss 2.1817 Accuracy 0.5704
Epoch 9 Batch 100 Loss 2.1819 Accuracy 0.5716
Epoch 9 Batch 150 Loss 2.1817 Accuracy 0.5717
Epoch 9 Batch 200 Loss 2.1886 Accuracy 0.5702
Epoch 9 Batch 250 Loss 2.1971 Accuracy 0.5694
Epoch 9 Batch 300 Loss 2.1957 Accuracy 0.5695
Epoch 9 Batch 350 Loss 2.1913 Accuracy 0.5704
Epoch 9 Batch 400 Loss 2.1918 Accuracy 0.5704
Epoch 9 Batch 450 Loss 2.1886 Accuracy 0.5709
Epoch 9 Batch 500 Loss 2.1903 Accuracy 0.5707
Epoch 9 Batch 550 Loss 2.1898 Accuracy 0.5708
Epoch 9 Batch 600 Loss 2.1901 Accuracy 0.5707
Epoch 9 Batch 650 Loss 2.1903 Accuracy 0.5707
Epoch 9 Batch 700 Loss 2.1919 Accuracy 0.5706
Epoch 9 Batch 750 Loss 2.1929 Accuracy 0.5708
Epoch 9 Batch 800 Loss 2.1940 Accuracy 0.5707
Epoch 9 Loss 2.1945 Accuracy 0.5706
Time taken for 1 epoch: 49.36 secs

Epoch 10 Batch 0 Loss 2.2947 Accuracy 0.5558
Epoch 10 Batch 50 Loss 2.0508 Accuracy 0.5876
Epoch 10 Batch 100 Loss 2.0412 Accuracy 0.5909
Epoch 10 Batch 150 Loss 2.0439 Accuracy 0.5906
Epoch 10 Batch 200 Loss 2.0526 Accuracy 0.5896
Epoch 10 Batch 250 Loss 2.0444 Accuracy 0.5909
Epoch 10 Batch 300 Loss 2.0418 Accuracy 0.5914
Epoch 10 Batch 350 Loss 2.0433 Accuracy 0.5910
Epoch 10 Batch 400 Loss 2.0449 Accuracy 0.5906
Epoch 10 Batch 450 Loss 2.0450 Accuracy 0.5907
Epoch 10 Batch 500 Loss 2.0477 Accuracy 0.5905
Epoch 10 Batch 550 Loss 2.0502 Accuracy 0.5902
Epoch 10 Batch 600 Loss 2.0516 Accuracy 0.5901
Epoch 10 Batch 650 Loss 2.0531 Accuracy 0.5901
Epoch 10 Batch 700 Loss 2.0548 Accuracy 0.5900
Epoch 10 Batch 750 Loss 2.0560 Accuracy 0.5899
Epoch 10 Batch 800 Loss 2.0573 Accuracy 0.5900
Saving checkpoint for epoch 10 at ./checkpoints/train/ckpt-2
Epoch 10 Loss 2.0580 Accuracy 0.5899
Time taken for 1 epoch: 50.74 secs

Epoch 11 Batch 0 Loss 1.9999 Accuracy 0.5880
Epoch 11 Batch 50 Loss 1.9237 Accuracy 0.6101
Epoch 11 Batch 100 Loss 1.9318 Accuracy 0.6070
Epoch 11 Batch 150 Loss 1.9259 Accuracy 0.6077
Epoch 11 Batch 200 Loss 1.9252 Accuracy 0.6076
Epoch 11 Batch 250 Loss 1.9257 Accuracy 0.6081
Epoch 11 Batch 300 Loss 1.9273 Accuracy 0.6079
Epoch 11 Batch 350 Loss 1.9323 Accuracy 0.6073
Epoch 11 Batch 400 Loss 1.9311 Accuracy 0.6079
Epoch 11 Batch 450 Loss 1.9344 Accuracy 0.6073
Epoch 11 Batch 500 Loss 1.9359 Accuracy 0.6070
Epoch 11 Batch 550 Loss 1.9357 Accuracy 0.6072
Epoch 11 Batch 600 Loss 1.9351 Accuracy 0.6074
Epoch 11 Batch 650 Loss 1.9375 Accuracy 0.6072
Epoch 11 Batch 700 Loss 1.9402 Accuracy 0.6069
Epoch 11 Batch 750 Loss 1.9411 Accuracy 0.6068
Epoch 11 Batch 800 Loss 1.9437 Accuracy 0.6065
Epoch 11 Loss 1.9444 Accuracy 0.6063
Time taken for 1 epoch: 49.69 secs

Epoch 12 Batch 0 Loss 1.8838 Accuracy 0.6104
Epoch 12 Batch 50 Loss 1.8113 Accuracy 0.6233
Epoch 12 Batch 100 Loss 1.8283 Accuracy 0.6208
Epoch 12 Batch 150 Loss 1.8255 Accuracy 0.6225
Epoch 12 Batch 200 Loss 1.8361 Accuracy 0.6209
Epoch 12 Batch 250 Loss 1.8375 Accuracy 0.6207
Epoch 12 Batch 300 Loss 1.8418 Accuracy 0.6201
Epoch 12 Batch 350 Loss 1.8439 Accuracy 0.6198
Epoch 12 Batch 400 Loss 1.8457 Accuracy 0.6198
Epoch 12 Batch 450 Loss 1.8468 Accuracy 0.6196
Epoch 12 Batch 500 Loss 1.8463 Accuracy 0.6198
Epoch 12 Batch 550 Loss 1.8468 Accuracy 0.6199
Epoch 12 Batch 600 Loss 1.8486 Accuracy 0.6197
Epoch 12 Batch 650 Loss 1.8492 Accuracy 0.6198
Epoch 12 Batch 700 Loss 1.8494 Accuracy 0.6199
Epoch 12 Batch 750 Loss 1.8515 Accuracy 0.6195
Epoch 12 Batch 800 Loss 1.8527 Accuracy 0.6194
Epoch 12 Loss 1.8535 Accuracy 0.6193
Time taken for 1 epoch: 49.50 secs

Epoch 13 Batch 0 Loss 1.6777 Accuracy 0.6374
Epoch 13 Batch 50 Loss 1.7137 Accuracy 0.6387
Epoch 13 Batch 100 Loss 1.7346 Accuracy 0.6352
Epoch 13 Batch 150 Loss 1.7383 Accuracy 0.6348
Epoch 13 Batch 200 Loss 1.7402 Accuracy 0.6349
Epoch 13 Batch 250 Loss 1.7442 Accuracy 0.6345
Epoch 13 Batch 300 Loss 1.7496 Accuracy 0.6340
Epoch 13 Batch 350 Loss 1.7529 Accuracy 0.6332
Epoch 13 Batch 400 Loss 1.7565 Accuracy 0.6324
Epoch 13 Batch 450 Loss 1.7574 Accuracy 0.6324
Epoch 13 Batch 500 Loss 1.7596 Accuracy 0.6321
Epoch 13 Batch 550 Loss 1.7597 Accuracy 0.6322
Epoch 13 Batch 600 Loss 1.7586 Accuracy 0.6326
Epoch 13 Batch 650 Loss 1.7634 Accuracy 0.6320
Epoch 13 Batch 700 Loss 1.7669 Accuracy 0.6315
Epoch 13 Batch 750 Loss 1.7693 Accuracy 0.6313
Epoch 13 Batch 800 Loss 1.7714 Accuracy 0.6312
Epoch 13 Loss 1.7726 Accuracy 0.6310
Time taken for 1 epoch: 49.98 secs

Epoch 14 Batch 0 Loss 1.6842 Accuracy 0.6471
Epoch 14 Batch 50 Loss 1.6872 Accuracy 0.6433
Epoch 14 Batch 100 Loss 1.6708 Accuracy 0.6463
Epoch 14 Batch 150 Loss 1.6705 Accuracy 0.6459
Epoch 14 Batch 200 Loss 1.6734 Accuracy 0.6454
Epoch 14 Batch 250 Loss 1.6748 Accuracy 0.6455
Epoch 14 Batch 300 Loss 1.6773 Accuracy 0.6451
Epoch 14 Batch 350 Loss 1.6787 Accuracy 0.6450
Epoch 14 Batch 400 Loss 1.6830 Accuracy 0.6446
Epoch 14 Batch 450 Loss 1.6830 Accuracy 0.6446
Epoch 14 Batch 500 Loss 1.6862 Accuracy 0.6440
Epoch 14 Batch 550 Loss 1.6862 Accuracy 0.6440
Epoch 14 Batch 600 Loss 1.6871 Accuracy 0.6441
Epoch 14 Batch 650 Loss 1.6900 Accuracy 0.6436
Epoch 14 Batch 700 Loss 1.6950 Accuracy 0.6429
Epoch 14 Batch 750 Loss 1.6996 Accuracy 0.6423
Epoch 14 Batch 800 Loss 1.7041 Accuracy 0.6417
Epoch 14 Loss 1.7045 Accuracy 0.6416
Time taken for 1 epoch: 50.59 secs

Epoch 15 Batch 0 Loss 1.6510 Accuracy 0.6451
Epoch 15 Batch 50 Loss 1.6027 Accuracy 0.6561
Epoch 15 Batch 100 Loss 1.6035 Accuracy 0.6564
Epoch 15 Batch 150 Loss 1.6128 Accuracy 0.6549
Epoch 15 Batch 200 Loss 1.6139 Accuracy 0.6543
Epoch 15 Batch 250 Loss 1.6123 Accuracy 0.6548
Epoch 15 Batch 300 Loss 1.6125 Accuracy 0.6550
Epoch 15 Batch 350 Loss 1.6196 Accuracy 0.6537
Epoch 15 Batch 400 Loss 1.6209 Accuracy 0.6536
Epoch 15 Batch 450 Loss 1.6243 Accuracy 0.6531
Epoch 15 Batch 500 Loss 1.6269 Accuracy 0.6526
Epoch 15 Batch 550 Loss 1.6300 Accuracy 0.6522
Epoch 15 Batch 600 Loss 1.6316 Accuracy 0.6519
Epoch 15 Batch 650 Loss 1.6329 Accuracy 0.6519
Epoch 15 Batch 700 Loss 1.6354 Accuracy 0.6517
Epoch 15 Batch 750 Loss 1.6378 Accuracy 0.6513
Epoch 15 Batch 800 Loss 1.6422 Accuracy 0.6507
Saving checkpoint for epoch 15 at ./checkpoints/train/ckpt-3
Epoch 15 Loss 1.6425 Accuracy 0.6506
Time taken for 1 epoch: 51.91 secs

Epoch 16 Batch 0 Loss 1.2860 Accuracy 0.7074
Epoch 16 Batch 50 Loss 1.5397 Accuracy 0.6670
Epoch 16 Batch 100 Loss 1.5438 Accuracy 0.6663
Epoch 16 Batch 150 Loss 1.5483 Accuracy 0.6653
Epoch 16 Batch 200 Loss 1.5520 Accuracy 0.6650
Epoch 16 Batch 250 Loss 1.5540 Accuracy 0.6643
Epoch 16 Batch 300 Loss 1.5614 Accuracy 0.6628
Epoch 16 Batch 350 Loss 1.5640 Accuracy 0.6621
Epoch 16 Batch 400 Loss 1.5692 Accuracy 0.6611
Epoch 16 Batch 450 Loss 1.5721 Accuracy 0.6607
Epoch 16 Batch 500 Loss 1.5720 Accuracy 0.6607
Epoch 16 Batch 550 Loss 1.5754 Accuracy 0.6603
Epoch 16 Batch 600 Loss 1.5768 Accuracy 0.6600
Epoch 16 Batch 650 Loss 1.5785 Accuracy 0.6600
Epoch 16 Batch 700 Loss 1.5822 Accuracy 0.6596
Epoch 16 Batch 750 Loss 1.5858 Accuracy 0.6589
Epoch 16 Batch 800 Loss 1.5890 Accuracy 0.6585
Epoch 16 Loss 1.5895 Accuracy 0.6585
Time taken for 1 epoch: 51.78 secs

Epoch 17 Batch 0 Loss 1.5084 Accuracy 0.6485
Epoch 17 Batch 50 Loss 1.4844 Accuracy 0.6755
Epoch 17 Batch 100 Loss 1.4821 Accuracy 0.6752
Epoch 17 Batch 150 Loss 1.4926 Accuracy 0.6736
Epoch 17 Batch 200 Loss 1.5024 Accuracy 0.6724
Epoch 17 Batch 250 Loss 1.5022 Accuracy 0.6726
Epoch 17 Batch 300 Loss 1.5114 Accuracy 0.6711
Epoch 17 Batch 350 Loss 1.5145 Accuracy 0.6705
Epoch 17 Batch 400 Loss 1.5176 Accuracy 0.6701
Epoch 17 Batch 450 Loss 1.5205 Accuracy 0.6696
Epoch 17 Batch 500 Loss 1.5215 Accuracy 0.6696
Epoch 17 Batch 550 Loss 1.5245 Accuracy 0.6690
Epoch 17 Batch 600 Loss 1.5274 Accuracy 0.6684
Epoch 17 Batch 650 Loss 1.5304 Accuracy 0.6680
Epoch 17 Batch 700 Loss 1.5326 Accuracy 0.6677
Epoch 17 Batch 750 Loss 1.5372 Accuracy 0.6670
Epoch 17 Batch 800 Loss 1.5418 Accuracy 0.6661
Epoch 17 Loss 1.5420 Accuracy 0.6662
Time taken for 1 epoch: 51.36 secs

Epoch 18 Batch 0 Loss 1.2714 Accuracy 0.7098
Epoch 18 Batch 50 Loss 1.4713 Accuracy 0.6796
Epoch 18 Batch 100 Loss 1.4666 Accuracy 0.6791
Epoch 18 Batch 150 Loss 1.4654 Accuracy 0.6788
Epoch 18 Batch 200 Loss 1.4648 Accuracy 0.6787
Epoch 18 Batch 250 Loss 1.4658 Accuracy 0.6783
Epoch 18 Batch 300 Loss 1.4673 Accuracy 0.6782
Epoch 18 Batch 350 Loss 1.4720 Accuracy 0.6772
Epoch 18 Batch 400 Loss 1.4728 Accuracy 0.6772
Epoch 18 Batch 450 Loss 1.4752 Accuracy 0.6768
Epoch 18 Batch 500 Loss 1.4774 Accuracy 0.6767
Epoch 18 Batch 550 Loss 1.4805 Accuracy 0.6761
Epoch 18 Batch 600 Loss 1.4834 Accuracy 0.6756
Epoch 18 Batch 650 Loss 1.4881 Accuracy 0.6750
Epoch 18 Batch 700 Loss 1.4922 Accuracy 0.6743
Epoch 18 Batch 750 Loss 1.4945 Accuracy 0.6740
Epoch 18 Batch 800 Loss 1.4965 Accuracy 0.6736
Epoch 18 Loss 1.4969 Accuracy 0.6735
Time taken for 1 epoch: 51.68 secs

Epoch 19 Batch 0 Loss 1.3652 Accuracy 0.7007
Epoch 19 Batch 50 Loss 1.3857 Accuracy 0.6900
Epoch 19 Batch 100 Loss 1.4049 Accuracy 0.6869
Epoch 19 Batch 150 Loss 1.4164 Accuracy 0.6854
Epoch 19 Batch 200 Loss 1.4223 Accuracy 0.6842
Epoch 19 Batch 250 Loss 1.4252 Accuracy 0.6836
Epoch 19 Batch 300 Loss 1.4288 Accuracy 0.6832
Epoch 19 Batch 350 Loss 1.4327 Accuracy 0.6829
Epoch 19 Batch 400 Loss 1.4351 Accuracy 0.6823
Epoch 19 Batch 450 Loss 1.4395 Accuracy 0.6815
Epoch 19 Batch 500 Loss 1.4425 Accuracy 0.6812
Epoch 19 Batch 550 Loss 1.4472 Accuracy 0.6805
Epoch 19 Batch 600 Loss 1.4476 Accuracy 0.6806
Epoch 19 Batch 650 Loss 1.4503 Accuracy 0.6802
Epoch 19 Batch 700 Loss 1.4532 Accuracy 0.6797
Epoch 19 Batch 750 Loss 1.4549 Accuracy 0.6796
Epoch 19 Batch 800 Loss 1.4587 Accuracy 0.6792
Epoch 19 Loss 1.4595 Accuracy 0.6791
Time taken for 1 epoch: 51.77 secs

Epoch 20 Batch 0 Loss 1.2816 Accuracy 0.7223
Epoch 20 Batch 50 Loss 1.3843 Accuracy 0.6913
Epoch 20 Batch 100 Loss 1.3764 Accuracy 0.6929
Epoch 20 Batch 150 Loss 1.3833 Accuracy 0.6913
Epoch 20 Batch 200 Loss 1.3916 Accuracy 0.6900
Epoch 20 Batch 250 Loss 1.3963 Accuracy 0.6893
Epoch 20 Batch 300 Loss 1.4006 Accuracy 0.6886
Epoch 20 Batch 350 Loss 1.4011 Accuracy 0.6884
Epoch 20 Batch 400 Loss 1.4031 Accuracy 0.6881
Epoch 20 Batch 450 Loss 1.4064 Accuracy 0.6873
Epoch 20 Batch 500 Loss 1.4080 Accuracy 0.6872
Epoch 20 Batch 550 Loss 1.4076 Accuracy 0.6873
Epoch 20 Batch 600 Loss 1.4094 Accuracy 0.6872
Epoch 20 Batch 650 Loss 1.4153 Accuracy 0.6862
Epoch 20 Batch 700 Loss 1.4170 Accuracy 0.6859
Epoch 20 Batch 750 Loss 1.4208 Accuracy 0.6854
Epoch 20 Batch 800 Loss 1.4242 Accuracy 0.6848
Saving checkpoint for epoch 20 at ./checkpoints/train/ckpt-4
Epoch 20 Loss 1.4252 Accuracy 0.6846
Time taken for 1 epoch: 52.57 secs

評価する

評価には、次の手順が使用されます。

  • ポルトガルトークナイザ(使用して入力文をエンコードtokenizers.pt )。これはエンコーダ入力です。
  • デコーダ入力がに初期化される[START]トークン。
  • パディングマスクと先読みマスクを計算します。
  • decoder次にを見て予測を出力するencoder outputと、自身の出力(自己注目)。
  • モデルは、出力内の各単語の次の単語を予測します。これらのほとんどは冗長です。最後の単語からの予測を使用します。
  • 予測された単語をデコーダー入力に連結し、デコーダーに渡します。
  • このアプローチでは、デコーダーは、予測した前の単語に基づいて次の単語を予測します。
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 \xe9 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 \xe9 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 heard about this idea .
Ground truth   : and my neighboring homes heard about this idea .
sentence = "vou ent\xe3o muito rapidamente partilhar convosco algumas hist\xf3rias de algumas coisas m\xe1gicas 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\xe3o muito rapidamente partilhar convosco algumas hist\xf3rias de algumas coisas m\xe1gicas que aconteceram.
Prediction     : so i ' ll be very quickly share with you some stories of some magic stuff that will happen .
Ground truth   : so i 'll just share with you some stories very quickly of some magical things that have happened .

あなたはに異なる層とデコーダの注目ブロックを渡すことができplotパラメータ。

注意プロット

evaluate関数はまた、関心の辞書を返しますが、モデルの内部作業を視覚化するために使用することができますマッピングします。

sentence = "este \xe9 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 \xe9 o primeiro livro que eu fiz.
Prediction     : this is the first book 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([9, 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=(10,), dtype=string, numpy=
array([b'[START]', b'this', b'is', b'the', b'first', b'book', 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

モデルはなじみのない言葉でも大丈夫です。 「トリケラトプス」も「百科事典」も入力データセットに含まれておらず、共有語彙がなくても、モデルはそれらを音訳することをほとんど学習します。

sentence = "Eu li sobre triceratops na enciclop\xe9dia."
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\xe9dia.
Prediction     : i read about tattoosees in encyclopedia .
Ground truth   : I read about triceratops in the encyclopedia.

png

概要

このチュートリアルでは、位置エンコーディング、マルチヘッドアテンション、マスキングの重要性、およびトランスフォーマーの作成方法について学習しました。

別のデータセットを使用してトランスフォーマーをトレーニングしてみてください。上記のハイパーパラメータを変更して、ベーストランスまたはトランスXLを作成することもできます。また、作成するために、ここで定義された層を使用することができますBERT美術モデルの列車の状態を。さらに、ビーム検索を実装して、より良い予測を得ることができます。