মনোযোগ সহ নিউরাল মেশিন অনুবাদ

TensorFlow.org এ দেখুন Google Colab-এ চালান GitHub-এ উৎস দেখুননোটবুক ডাউনলোড করুন

এই নোটবুক ইংরেজি উপর ভিত্তি করে অনুবাদ স্প্যানিশ জন্য ক্রম (seq2seq) মডেল একটি ক্রম রেলগাড়ি কার্যকর করার দৃষ্টি আকর্ষণ করছি ভিত্তিক নিউরাল যান্ত্রিক অনুবাদ পন্থা । এটি একটি উন্নত উদাহরণ যা কিছু জ্ঞান অনুমান করে:

  • সিকোয়েন্স টু সিকোয়েন্স মডেল
  • কেরাস স্তরের নীচে টেনসরফ্লো মৌলিক বিষয়গুলি:
    • সরাসরি টেনসরের সাথে কাজ করা
    • লেখা কাস্টম keras.Model s এবং keras.layers

এই স্থাপত্য কিছুটা পুরানো এটি এখনও মাধ্যমে কাজ করার জন্য একটি খুব দরকারী প্রজেক্ট (উপর যাওয়ার আগে মনোযোগ প্রক্রিয়া গভীরভাবে পেতে হয় ট্রান্সফরমারস )।

"? ¿Todavia estan স্বীকারোক্তি কাসা" এই নোটবুক মডেল প্রশিক্ষণ পরে, আপনি যেমন, ইনপুট একটি স্পেনীয় বাক্য করতে সক্ষম হবে, এবং ইংরেজি অনুবাদ আসতে: "আপনি বাড়ীতে এখনও"

ফলে মডেল হিসেবে রপ্তানিযোগ্য হয় tf.saved_model তাই এটি অন্যান্য TensorFlow পরিবেশের মধ্যে ব্যবহার করা যেতে পারে।

একটি খেলনা উদাহরণের জন্য অনুবাদের মান যুক্তিসঙ্গত, তবে জেনারেট করা মনোযোগের প্লটটি সম্ভবত আরও আকর্ষণীয়। এটি দেখায় যে অনুবাদ করার সময় ইনপুট বাক্যের কোন অংশে মডেলের মনোযোগ রয়েছে:

স্প্যানিশ-ইংরেজি মনোযোগ প্লট

সেটআপ

pip install tensorflow_text
import numpy as np

import typing
from typing import Any, Tuple

import tensorflow as tf

import tensorflow_text as tf_text

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

এই টিউটোরিয়ালটি স্ক্র্যাচ থেকে কয়েকটি স্তর তৈরি করে, আপনি যদি কাস্টম এবং বিল্টইন বাস্তবায়নের মধ্যে স্যুইচ করতে চান তবে এই ভেরিয়েবলটি ব্যবহার করুন।

use_builtins = True

এই টিউটোরিয়ালটি অনেক নিম্ন স্তরের API ব্যবহার করে যেখানে আকারগুলি ভুল করা সহজ। এই ক্লাসটি পুরো টিউটোরিয়াল জুড়ে আকার পরীক্ষা করতে ব্যবহৃত হয়।

আকৃতি পরীক্ষক

তথ্যটি

আমরা কর্তৃক প্রদত্ত একটি ভাষা ডেটা সেটটি ব্যবহার করব http://www.manythings.org/anki/ এই সেটটি বিন্যাসে ভাষা অনুবাদ জোড়া রয়েছে:

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

তাদের বিভিন্ন ভাষা উপলব্ধ আছে, কিন্তু আমরা ইংরেজি-স্প্যানিশ ডেটাসেট ব্যবহার করব।

ডাউনলোড করুন এবং ডেটাসেট প্রস্তুত করুন

সুবিধার জন্য, আমরা Google ক্লাউডে এই ডেটাসেটের একটি অনুলিপি হোস্ট করেছি, তবে আপনি নিজের কপিও ডাউনলোড করতে পারেন। ডেটাসেট ডাউনলোড করার পরে, এখানে আমরা ডেটা প্রস্তুত করার জন্য পদক্ষেপ নেব:

  1. একটি শুরু এবং শেষ প্রত্যেক বাক্যের টোকেন যুক্ত করো।
  2. বিশেষ অক্ষর মুছে বাক্য পরিষ্কার করুন.
  3. একটি শব্দ সূচক এবং বিপরীত শব্দ সূচক তৈরি করুন (শব্দ → আইডি এবং আইডি → শব্দ থেকে অভিধান ম্যাপিং)।
  4. প্রতিটি বাক্যকে সর্বোচ্চ দৈর্ঘ্যে প্যাড করুন।
# Download the file
import pathlib

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

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

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

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

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

একটি tf.data ডেটাসেট তৈরি করুন

স্ট্রিং এই অ্যারে থেকে একটি তৈরি করতে পারেন tf.data.Dataset যে shuffles এবং তাদের ব্যাচে দক্ষতার স্ট্রিং:

BUFFER_SIZE = len(inp)
BATCH_SIZE = 64

dataset = tf.data.Dataset.from_tensor_slices((inp, targ)).shuffle(BUFFER_SIZE)
dataset = dataset.batch(BATCH_SIZE)
for example_input_batch, example_target_batch in dataset.take(1):
  print(example_input_batch[:5])
  print()
  print(example_target_batch[:5])
  break
tf.Tensor(
[b'No s\xc3\xa9 lo que quiero.' b'\xc2\xbfDeber\xc3\xada repetirlo?'
 b'Tard\xc3\xa9 m\xc3\xa1s de 2 horas en traducir unas p\xc3\xa1ginas en ingl\xc3\xa9s.'
 b'A Tom comenz\xc3\xb3 a temerle a Mary.' b'Mi pasatiempo es la lectura.'], shape=(5,), dtype=string)

tf.Tensor(
[b"I don't know what I want." b'Should I repeat it?'
 b'It took me more than two hours to translate a few pages of English.'
 b'Tom became afraid of Mary.' b'My hobby is reading.'], shape=(5,), dtype=string)

টেক্সট প্রিপ্রসেসিং

এই টিউটোরিয়ালের উদ্দেশ্য হ'ল একটি মডেল যে একটি রূপে এক্সপোর্ট করা যাবে নির্মাণ করা হয় tf.saved_model । যে রপ্তানি মডেল দরকারী করতে এটা গ্রহণ করা উচিত tf.string ইনপুট, এবং আসতে tf.string আউটপুট: সমস্ত টেক্সট প্রক্রিয়াকরণ মডেল ভিতরে ঘটবে।

প্রমিতকরণ

মডেলটি একটি সীমিত শব্দভান্ডার সহ বহুভাষিক পাঠ্য নিয়ে কাজ করছে। তাই ইনপুট টেক্সট মানসম্মত করা গুরুত্বপূর্ণ হবে।

প্রথম ধাপ হল ইউনিকোড নর্মালাইজেশন যাতে উচ্চারিত অক্ষরগুলিকে বিভক্ত করা যায় এবং সামঞ্জস্যপূর্ণ অক্ষরগুলিকে তাদের ASCII সমতুল্য দিয়ে প্রতিস্থাপন করা যায়।

tensorflow_text প্যাকেজের মাধ্যমে একটি ইউনিকোড স্বাভাবিক অপারেশন রয়েছে:

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

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

ইউনিকোড নর্মালাইজেশন টেক্সট স্ট্যান্ডার্ডাইজেশন ফাংশনের প্রথম ধাপ হবে:

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

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

টেক্সট ভেক্টরাইজেশন

এই প্রমিতকরণ ফাংশন একটি গুটিয়ে করা হবে tf.keras.layers.TextVectorization স্তর যা শব্দভান্ডার নিষ্কাশন এবং ইনপুট টেক্সট রূপান্তর টোকেন ক্রমের সাথে হ্যান্ডেল করা হবে।

max_vocab_size = 5000

input_text_processor = tf.keras.layers.TextVectorization(
    standardize=tf_lower_and_split_punct,
    max_tokens=max_vocab_size)

TextVectorization স্তর এবং অনেক অন্যান্য প্রাক-প্রক্রিয়াকরণ স্তর একটি আছে adapt পদ্ধতি। এই পদ্ধতি প্রশিক্ষণ ডেটার এক যুগান্তকারী সার্চ, এবং মত অনেক কাজ করে Model.fix । এই adapt পদ্ধতি স্তর ডেটার উপর ভিত্তি করে সূচনা। এখানে এটি শব্দভান্ডার নির্ধারণ করে:

input_text_processor.adapt(inp)

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

যে স্পেনীয় এর TextVectorization স্তর, এখন গড়ে তোলা এবং .adapt() ইংরেজি এক:

output_text_processor = tf.keras.layers.TextVectorization(
    standardize=tf_lower_and_split_punct,
    max_tokens=max_vocab_size)

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

এখন এই স্তরগুলি স্ট্রিংগুলির একটি ব্যাচকে টোকেন আইডিগুলির একটি ব্যাচে রূপান্তর করতে পারে:

example_tokens = input_text_processor(example_input_batch)
example_tokens[:3, :10]
<tf.Tensor: shape=(3, 10), dtype=int64, numpy=
array([[   2,    9,   17,   22,    5,   48,    4,    3,    0,    0],
       [   2,   13,  177,    1,   12,    3,    0,    0,    0,    0],
       [   2,  120,   35,    6,  290,   14, 2134,  506, 2637,   14]])>

get_vocabulary পদ্ধতি টোকেন ID- র টেক্সট ফিরে রূপান্তর করতে ব্যবহার করা যেতে পারে:

input_vocab = np.array(input_text_processor.get_vocabulary())
tokens = input_vocab[example_tokens[0].numpy()]
' '.join(tokens)
'[START] no se lo que quiero . [END]      '

ফিরে আসা টোকেন আইডিগুলি শূন্য-প্যাডেড। এটি সহজেই একটি মাস্কে পরিণত করা যেতে পারে:

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

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

png

এনকোডার/ডিকোডার মডেল

নিম্নলিখিত চিত্রটি মডেলটির একটি ওভারভিউ দেখায়। প্রতিটি সময়-ধাপে ডিকোডারের আউটপুট পরবর্তী শব্দের পূর্বাভাস দেওয়ার জন্য এনকোড করা ইনপুটের উপর একটি ওজনযুক্ত যোগফলের সাথে মিলিত হয়। ডায়াগ্রাম এবং সূত্র থেকে এসেছ Lương এর কাগজ

মনোযোগের প্রক্রিয়া

এটিতে যাওয়ার আগে মডেলটির জন্য কয়েকটি ধ্রুবক সংজ্ঞায়িত করুন:

embedding_dim = 256
units = 1024

এনকোডার

এনকোডার তৈরি করে শুরু করুন, উপরের চিত্রের নীল অংশ।

এনকোডার:

  1. (থেকে টোকেন ID- র একটি তালিকা লাগে input_text_processor )।
  2. প্রতিটি টোকেন জন্য একটি এম্বেডিং ভেক্টর আপ সৌন্দর্য (ক ব্যবহার layers.Embedding )।
  3. একটি নতুন ক্রম মধ্যে embeddings (ক ব্যবহার প্রক্রিয়া layers.GRU )।
  4. রিটার্ন:
    • প্রক্রিয়াকৃত ক্রম। এই মনোযোগ মাথা পাস করা হবে.
    • অভ্যন্তরীণ অবস্থা। এটি ডিকোডার শুরু করতে ব্যবহার করা হবে
class Encoder(tf.keras.layers.Layer):
  def __init__(self, input_vocab_size, embedding_dim, enc_units):
    super(Encoder, self).__init__()
    self.enc_units = enc_units
    self.input_vocab_size = input_vocab_size

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

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

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

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

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

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

এটি এখন পর্যন্ত একসাথে কীভাবে ফিট করে তা এখানে:

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

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

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

এনকোডারটি তার অভ্যন্তরীণ অবস্থা ফেরত দেয় যাতে তার অবস্থাটি ডিকোডার শুরু করতে ব্যবহার করা যেতে পারে।

এটি একটি RNN-এর পক্ষে তার অবস্থা ফিরিয়ে দেওয়াও সাধারণ ব্যাপার যাতে এটি একাধিক কলের উপর একটি ক্রম প্রক্রিয়া করতে পারে। আপনি ডিকোডার নির্মাণ যে আরো দেখতে পাবেন.

মনোযোগের মাথা

ডিকোডার ইনপুট সিকোয়েন্সের অংশগুলিতে বেছে বেছে ফোকাস করার জন্য মনোযোগ ব্যবহার করে। মনোযোগ প্রতিটি উদাহরণের জন্য ইনপুট হিসাবে ভেক্টরের একটি ক্রম নেয় এবং প্রতিটি উদাহরণের জন্য একটি "মনোযোগ" ভেক্টর প্রদান করে। এই মনোযোগ স্তর একটি অনুরূপ layers.GlobalAveragePoling1D কিন্তু মনোযোগ স্তর একটি ভরযুক্ত গড় সম্পাদন করে।

আসুন দেখে নেওয়া যাক এটি কীভাবে কাজ করে:

মনোযোগ সমীকরণ 1

মনোযোগ সমীকরণ 2

কোথায়:

  • \(s\) এনকোডার সূচি।
  • \(t\) ডিকোডার সূচি।
  • \(\alpha_{ts}\) মনোযোগ ওজন হয়।
  • \(h_s\) এনকোডার আউটপুট ক্রম (মনোযোগ "কী" এবং "মান" ট্রান্সফরমার পরিভাষা) এর উপস্থিত ছিলেন হচ্ছে।
  • \(h_t\) ডিকোডার রাষ্ট্র ক্রম (মনোযোগ "QUERY" ট্রান্সফরমার পরিভাষা) এর দোসর হয়।
  • \(c_t\) ফলে প্রসঙ্গ বাহক।
  • \(a_t\) চূড়ান্ত "প্রসঙ্গ" এবং "QUERY" মিশ্রন আউটপুট।

সমীকরণ:

  1. মনোযোগ ওজন, হিসাব করে \(\alpha_{ts}\), এনকোডারের আউটপুট ক্রম জুড়ে একটি softmax হিসাবে।
  2. এনকোডার আউটপুটগুলির ওজনযুক্ত যোগফল হিসাবে প্রসঙ্গ ভেক্টর গণনা করে।

শেষবার \(score\) ফাংশন। এর কাজ হল প্রতিটি কী-কোয়েরি জোড়ার জন্য একটি স্কেলার লগিট-স্কোর গণনা করা। দুটি সাধারণ পন্থা আছে:

মনোযোগ সমীকরণ 4

এই টিউটোরিয়ালটি ব্যবহার Bahdanau এর যুত মনোযোগ । TensorFlow উভয় হিসেবে বাস্তবায়নের অন্তর্ভুক্ত layers.Attention এবং layers.AdditiveAttention । হ্যান্ডলগুলি নিচে বর্গ একজোড়া ওজন ম্যাট্রিক্স layers.Dense স্তর এবং builtin বাস্তবায়ন কল।

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

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

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

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

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

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

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

    return context_vector, attention_weights

মনোযোগ স্তর পরীক্ষা করুন

একটি তৈরি করুন BahdanauAttention স্তর:

attention_layer = BahdanauAttention(units)

এই স্তরটি 3টি ইনপুট নেয়:

  • query এই পরে, ডিকোডার দ্বারা উত্পন্ন করা হবে না।
  • value এই এনকোডার আউটপুট হবে।
  • mask : প্যাডিং অগ্রাহ্য করতে, example_tokens != 0
(example_tokens != 0).shape
TensorShape([64, 14])

মনোযোগ স্তরের ভেক্টরাইজড বাস্তবায়ন আপনাকে কোয়েরি ভেক্টরের ক্রমগুলির একটি ব্যাচ এবং মান ভেক্টরগুলির ক্রমগুলির একটি ব্যাচ পাস করতে দেয়৷ ফলাফল হলো:

  1. ফলাফল ভেক্টরের ক্রমগুলির একটি ব্যাচ প্রশ্নের আকারকে নির্ধারণ করে।
  2. একটি ব্যাচ মনোযোগ আকার সঙ্গে, মানচিত্র (query_length, value_length)
# Later, the decoder will generate this attention query
example_attention_query = tf.random.normal(shape=[len(example_tokens), 2, 10])

# Attend to the encoded tokens

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

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

মনোযোগ ওজন সমষ্টি উচিত 1.0 প্রতিটি ক্রম জন্য।

এখানে এ সিকোয়েন্স জুড়ে মনোযোগ ওজন হয় t=0 :

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

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

png

ছোট-রেণ্ডম আরম্ভের কারণে মনোযোগ ওজন সব কাছাকাছি 1/(sequence_length) । আপনি একটি একক ক্রম জন্য ওজন উপর জুম থাকে, তাহলে আপনি দেখতে পারেন কিছু ছোট প্রকরণ যে মডেল প্রসারিত করতে জানতে পারেন, এবং কাজে লাগান নেই।

attention_weights.shape
TensorShape([64, 2, 14])
attention_slice = attention_weights[0, 0].numpy()
attention_slice = attention_slice[attention_slice != 0]

[<matplotlib.lines.Line2D at 0x7fb42c5b1090>]
<Figure size 432x288 with 0 Axes>

png

ডিকোডার

ডিকোডারের কাজ হল পরবর্তী আউটপুট টোকেনের জন্য পূর্বাভাস তৈরি করা।

  1. ডিকোডার সম্পূর্ণ এনকোডার আউটপুট গ্রহণ করে।
  2. এটি এখন পর্যন্ত কী তৈরি করেছে তার ট্র্যাক রাখতে এটি একটি RNN ব্যবহার করে৷
  3. এটি এনকোডারের আউটপুটের দিকে দৃষ্টি আকর্ষণ করার জন্য তার RNN আউটপুট ব্যবহার করে, প্রসঙ্গ ভেক্টর তৈরি করে।
  4. এটি "মনোযোগ ভেক্টর" তৈরি করতে সমীকরণ 3 (নীচে) ব্যবহার করে RNN আউটপুট এবং প্রসঙ্গ ভেক্টরকে একত্রিত করে।
  5. এটি "মনোযোগ ভেক্টর" এর উপর ভিত্তি করে পরবর্তী টোকেনের জন্য লগিট পূর্বাভাস তৈরি করে।

মনোযোগ সমীকরণ 3

এখানে Decoder শ্রেণী ও এর সূচনাকারী। ইনিশিয়ালাইজার সমস্ত প্রয়োজনীয় স্তর তৈরি করে।

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

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

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

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

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

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

call এই স্তরের জন্য পদ্ধতি নেয় এবং একাধিক tensors ফেরৎ। সেগুলিকে সাধারণ কন্টেইনার ক্লাসে সংগঠিত করুন:

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

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

এখানে বাস্তবায়ন হয় call পদ্ধতি:

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

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

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

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

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

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

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

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

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

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

এনকোডার তার RNN একটি একক কলের সাথে তার পূর্ণ ইনপুট ক্রম প্রক্রিয়া করে। ডিকোডার এই বাস্তবায়ন দক্ষ প্রশিক্ষণের জন্য তা করতে পারে হিসাবে ভাল। কিন্তু এই টিউটোরিয়ালটি কয়েকটি কারণে একটি লুপে ডিকোডার চালাবে:

  • নমনীয়তা: লুপ লেখা আপনাকে প্রশিক্ষণ পদ্ধতির উপর সরাসরি নিয়ন্ত্রণ দেয়।
  • স্বচ্ছতা: এটা মাস্কিং ঠাট না এবং ব্যবহার করা সম্ভব layers.RNN , অথবা tfa.seq2seq একটি একক কলে পরিণত এই সব প্যাক করার জন্য API গুলি। কিন্তু একটি লুপ হিসাবে এটি লিখতে পরিষ্কার হতে পারে.

এখন এই ডিকোডার ব্যবহার করে দেখুন।

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

ডিকোডার 4টি ইনপুট নেয়।

  • new_tokens - শেষ টোকেন উত্পন্ন। সঙ্গে ডিকোডার আরম্ভ "[START]" টোকেন।
  • enc_output - দ্বারা জেনারেট করা Encoder
  • mask - একটি বুলিয়ান টেন্সর ইঙ্গিত যেখানে tokens != 0
  • state - পূর্ববর্তী state ডিকোডার থেকে আউটপুট (ডিকোডার এর RNN অভ্যন্তরীণ স্থিতি)। পাশ None তা শূন্য আরম্ভ। মূল কাগজটি এটিকে এনকোডারের চূড়ান্ত RNN অবস্থা থেকে শুরু করে।
# Convert the target sequence, and collect the "[START]" tokens
example_output_tokens = output_text_processor(example_target_batch)

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

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

লগিট অনুযায়ী একটি টোকেন নমুনা:

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

আউটপুটের প্রথম শব্দ হিসাবে টোকেনটিকে ডিকোড করুন:

vocab = np.array(output_text_processor.get_vocabulary())
first_word = vocab[sampled_token.numpy()]
first_word[:5]
array([['already'],
       ['plants'],
       ['pretended'],
       ['convince'],
       ['square']], dtype='<U16')

এখন লজিটের দ্বিতীয় সেট তৈরি করতে ডিকোডার ব্যবহার করুন।

  • একই পাস enc_output এবং mask , এই পরিবর্তিত হয়নি।
  • পাস হিসাবে টোকেনটি নমুনা new_tokens
  • পাশ decoder_state ডিকোডার শেষ সময় ফিরে, তাই RNN যেখানে এটি বাকি শেষ সময় বন্ধ একটি মেমরির চলতে থাকে।
dec_result, dec_state = decoder(
    DecoderInput(sampled_token,
                 example_enc_output,
                 mask=(example_tokens != 0)),
    state=dec_state)
sampled_token = tf.random.categorical(dec_result.logits[:, 0, :], num_samples=1)
first_word = vocab[sampled_token.numpy()]
first_word[:5]
array([['nap'],
       ['mean'],
       ['worker'],
       ['passage'],
       ['baked']], dtype='<U16')

প্রশিক্ষণ

এখন আপনার কাছে মডেলের সমস্ত উপাদান রয়েছে, এটি মডেলটির প্রশিক্ষণ শুরু করার সময়। আপনার প্রয়োজন হবে:

  • একটি ক্ষতি ফাংশন এবং অপ্টিমাইজার অপ্টিমাইজেশান সঞ্চালন.
  • প্রতিটি ইনপুট/টার্গেট ব্যাচের জন্য মডেল আপডেট করার পদ্ধতি নির্ধারণ করে একটি প্রশিক্ষণ ধাপ ফাংশন।
  • প্রশিক্ষণ চালানো এবং চেকপয়েন্ট সংরক্ষণ করার জন্য একটি প্রশিক্ষণ লুপ।

ক্ষতি ফাংশন সংজ্ঞায়িত করুন

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

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

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

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

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

প্রশিক্ষণ পদক্ষেপ বাস্তবায়ন

একটি মডেল বর্গ দিয়ে শুরু করুন, প্রশিক্ষণ প্রক্রিয়া হিসেবে বাস্তবায়িত হবে train_step এই মডেল উপর পদ্ধতি। দেখুন কাস্টমাইজ মাপসই বিস্তারিত জানার জন্য।

এখানে train_step পদ্ধতি কাছাকাছি একটি লেফাফা হয় _train_step বাস্তবায়ন যা পরে আসতে হবে। এই মোড়কের উপর এবং বন্ধ করতে একটি সুইচ রয়েছে tf.function , সংকলন সহজ ডিবাগ করা।

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

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

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

সার্বিক জন্য বাস্তবায়ন Model.train_step পদ্ধতি নিম্নরূপ:

  1. একটি ব্যাচ জখন input_text, target_text থেকে tf.data.Dataset
  2. সেই কাঁচা পাঠ্য ইনপুটগুলিকে টোকেন-এম্বেডিং এবং মাস্কগুলিতে রূপান্তর করুন৷
  3. উপর এনকোডার চালান input_tokens পেতে encoder_output এবং encoder_state
  4. ডিকোডার অবস্থা এবং ক্ষতি শুরু করুন।
  5. উপর লুপ target_tokens :
    1. ডিকোডারটি একবারে এক ধাপ চালান।
    2. প্রতিটি পদক্ষেপের জন্য ক্ষতি গণনা করুন।
    3. গড় ক্ষতি জমা.
  6. ক্ষতির গ্রেডিয়েন্ট গণনা এবং মডেল এর আপডেট প্রয়োগ করতে অপটিমাইজার ব্যবহার trainable_variables

_preprocess পদ্ধতি, নীচের যোগ কার্যকরী # 1 এবং # 2 ধাপ:

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

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

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

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

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

_train_step পদ্ধতি, নীচের যোগ, আসলে ডিকোডার চলমান ছাড়া অবশিষ্ট পদক্ষেপ হ্যান্ডলগুলি:

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

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

  max_target_length = tf.shape(target_tokens)[1]

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

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

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

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

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

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

_loop_step পদ্ধতি, নীচের যোগ ডিকোডার executes এবং ক্রমবর্ধমান কমে যাওয়া এবং নতুন ডিকোডার রাজ্য (হিসাব dec_state )।

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

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

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

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

  return step_loss, dec_state
TrainTranslator._loop_step = _loop_step

প্রশিক্ষণের ধাপটি পরীক্ষা করুন

একটি বিল্ড TrainTranslator , এবং ব্যবহার প্রশিক্ষণ জন্য এখান থেকে কনফিগার Model.compile পদ্ধতি:

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

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

পরীক্ষা করুন train_step । এই ধরনের একটি পাঠ্য মডেলের জন্য ক্ষতি কাছাকাছি শুরু করা উচিত:

np.log(output_text_processor.vocabulary_size())
8.517193191416236
%%time
for n in range(10):
  print(translator.train_step([example_input_batch, example_target_batch]))
print()
{'batch_loss': <tf.Tensor: shape=(), dtype=float32, numpy=7.5849695>}
{'batch_loss': <tf.Tensor: shape=(), dtype=float32, numpy=7.55271>}
{'batch_loss': <tf.Tensor: shape=(), dtype=float32, numpy=7.4929113>}
{'batch_loss': <tf.Tensor: shape=(), dtype=float32, numpy=7.3296022>}
{'batch_loss': <tf.Tensor: shape=(), dtype=float32, numpy=6.80437>}
{'batch_loss': <tf.Tensor: shape=(), dtype=float32, numpy=5.000246>}
{'batch_loss': <tf.Tensor: shape=(), dtype=float32, numpy=5.8740363>}
{'batch_loss': <tf.Tensor: shape=(), dtype=float32, numpy=4.794589>}
{'batch_loss': <tf.Tensor: shape=(), dtype=float32, numpy=4.3175836>}
{'batch_loss': <tf.Tensor: shape=(), dtype=float32, numpy=4.108163>}

CPU times: user 5.49 s, sys: 0 ns, total: 5.49 s
Wall time: 5.45 s

যদিও এটা একটি ছাড়া ডিবাগ করা আরো সহজ tf.function এটা একটি কার্যকারিতা সাহায্য দিতে পারে। তাই এখন যে _train_step পদ্ধতি কাজ করছে, চেষ্টা tf.function -wrapped _tf_train_step যখন প্রশিক্ষণ কর্মক্ষমতা বাড়ানোর জন্য:

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

প্রথম কল ধীর হবে, কারণ এটি ফাংশন ট্রেস করে।

translator.train_step([example_input_batch, example_target_batch])
2021-12-04 12:09:48.074769: E tensorflow/core/grappler/optimizers/meta_optimizer.cc:812] function_optimizer failed: INVALID_ARGUMENT: Input 6 of node gradient_tape/while/while_grad/body/_531/gradient_tape/while/gradients/while/decoder_1/gru_3/PartitionedCall_grad/PartitionedCall was passed variant from gradient_tape/while/while_grad/body/_531/gradient_tape/while/gradients/while/decoder_1/gru_3/PartitionedCall_grad/TensorListPopBack_2:1 incompatible with expected float.
2021-12-04 12:09:48.180156: E tensorflow/core/grappler/optimizers/meta_optimizer.cc:812] layout failed: OUT_OF_RANGE: src_output = 25, but num_outputs is only 25
2021-12-04 12:09:48.285846: E tensorflow/core/grappler/optimizers/meta_optimizer.cc:812] tfg_optimizer{} failed: INVALID_ARGUMENT: Input 6 of node gradient_tape/while/while_grad/body/_531/gradient_tape/while/gradients/while/decoder_1/gru_3/PartitionedCall_grad/PartitionedCall was passed variant from gradient_tape/while/while_grad/body/_531/gradient_tape/while/gradients/while/decoder_1/gru_3/PartitionedCall_grad/TensorListPopBack_2:1 incompatible with expected float.
    when importing GraphDef to MLIR module in GrapplerHook
2021-12-04 12:09:48.307794: E tensorflow/core/grappler/optimizers/meta_optimizer.cc:812] function_optimizer failed: INVALID_ARGUMENT: Input 6 of node gradient_tape/while/while_grad/body/_531/gradient_tape/while/gradients/while/decoder_1/gru_3/PartitionedCall_grad/PartitionedCall was passed variant from gradient_tape/while/while_grad/body/_531/gradient_tape/while/gradients/while/decoder_1/gru_3/PartitionedCall_grad/TensorListPopBack_2:1 incompatible with expected float.
2021-12-04 12:09:48.425447: W tensorflow/core/common_runtime/process_function_library_runtime.cc:866] Ignoring multi-device function optimization failure: INVALID_ARGUMENT: Input 1 of node while/body/_1/while/TensorListPushBack_56 was passed float from while/body/_1/while/decoder_1/gru_3/PartitionedCall:6 incompatible with expected variant.
{'batch_loss': <tf.Tensor: shape=(), dtype=float32, numpy=4.045638>}

কিন্তু পরে এটি সাধারণত 2-3x দ্রুত উৎসুক চেয়ে এর train_step পদ্ধতি:

%%time
for n in range(10):
  print(translator.train_step([example_input_batch, example_target_batch]))
print()
{'batch_loss': <tf.Tensor: shape=(), dtype=float32, numpy=4.1098256>}
{'batch_loss': <tf.Tensor: shape=(), dtype=float32, numpy=4.169871>}
{'batch_loss': <tf.Tensor: shape=(), dtype=float32, numpy=4.139249>}
{'batch_loss': <tf.Tensor: shape=(), dtype=float32, numpy=4.0410743>}
{'batch_loss': <tf.Tensor: shape=(), dtype=float32, numpy=3.9664454>}
{'batch_loss': <tf.Tensor: shape=(), dtype=float32, numpy=3.895707>}
{'batch_loss': <tf.Tensor: shape=(), dtype=float32, numpy=3.8154407>}
{'batch_loss': <tf.Tensor: shape=(), dtype=float32, numpy=3.7583396>}
{'batch_loss': <tf.Tensor: shape=(), dtype=float32, numpy=3.6986444>}
{'batch_loss': <tf.Tensor: shape=(), dtype=float32, numpy=3.640298>}

CPU times: user 4.4 s, sys: 960 ms, total: 5.36 s
Wall time: 1.67 s

একটি নতুন মডেলের একটি ভাল পরীক্ষা হল এটি একটি একক ব্যাচ ইনপুটকে ওভারফিট করতে পারে তা দেখা। এটি চেষ্টা করুন, ক্ষতি দ্রুত শূন্যে যেতে হবে:

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

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

png

এখন আপনি আত্মবিশ্বাসী যে প্রশিক্ষণের ধাপটি কাজ করছে, স্ক্র্যাচ থেকে প্রশিক্ষণের জন্য মডেলটির একটি নতুন অনুলিপি তৈরি করুন:

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

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

মডেলকে প্রশিক্ষণ দিন

সেখানে থাকাকালীন, আপনার নিজস্ব প্রশিক্ষণ লুপ লেখা বাস্তবায়নের সঙ্গে কিছুই ভুল Model.train_step পদ্ধতি, পূর্বের বিভাগে হিসাবে, আপনি চালাতে সক্ষম Model.fit এবং এড়ানোর যে সব বয়লার-প্লেট কোড rewriting।

এই টিউটোরিয়ালটি শুধুমাত্র সময়কাল একটি দম্পতি জন্য ট্রেন, তাই একটি ব্যবহার callbacks.Callback ষড়যন্ত্র জন্য, ব্যাচ ক্ষতির ইতিহাস সংগ্রহ করুন:

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

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

batch_loss = BatchLogs('batch_loss')
train_translator.fit(dataset, epochs=3,
                     callbacks=[batch_loss])
Epoch 1/3
2021-12-04 12:10:11.617839: E tensorflow/core/grappler/optimizers/meta_optimizer.cc:812] function_optimizer failed: INVALID_ARGUMENT: Input 6 of node StatefulPartitionedCall/gradient_tape/while/while_grad/body/_589/gradient_tape/while/gradients/while/decoder_2/gru_5/PartitionedCall_grad/PartitionedCall was passed variant from StatefulPartitionedCall/gradient_tape/while/while_grad/body/_589/gradient_tape/while/gradients/while/decoder_2/gru_5/PartitionedCall_grad/TensorListPopBack_2:1 incompatible with expected float.
2021-12-04 12:10:11.737105: E tensorflow/core/grappler/optimizers/meta_optimizer.cc:812] layout failed: OUT_OF_RANGE: src_output = 25, but num_outputs is only 25
2021-12-04 12:10:11.855054: E tensorflow/core/grappler/optimizers/meta_optimizer.cc:812] tfg_optimizer{} failed: INVALID_ARGUMENT: Input 6 of node StatefulPartitionedCall/gradient_tape/while/while_grad/body/_589/gradient_tape/while/gradients/while/decoder_2/gru_5/PartitionedCall_grad/PartitionedCall was passed variant from StatefulPartitionedCall/gradient_tape/while/while_grad/body/_589/gradient_tape/while/gradients/while/decoder_2/gru_5/PartitionedCall_grad/TensorListPopBack_2:1 incompatible with expected float.
    when importing GraphDef to MLIR module in GrapplerHook
2021-12-04 12:10:11.878896: E tensorflow/core/grappler/optimizers/meta_optimizer.cc:812] function_optimizer failed: INVALID_ARGUMENT: Input 6 of node StatefulPartitionedCall/gradient_tape/while/while_grad/body/_589/gradient_tape/while/gradients/while/decoder_2/gru_5/PartitionedCall_grad/PartitionedCall was passed variant from StatefulPartitionedCall/gradient_tape/while/while_grad/body/_589/gradient_tape/while/gradients/while/decoder_2/gru_5/PartitionedCall_grad/TensorListPopBack_2:1 incompatible with expected float.
2021-12-04 12:10:12.004755: W tensorflow/core/common_runtime/process_function_library_runtime.cc:866] Ignoring multi-device function optimization failure: INVALID_ARGUMENT: Input 1 of node StatefulPartitionedCall/while/body/_59/while/TensorListPushBack_56 was passed float from StatefulPartitionedCall/while/body/_59/while/decoder_2/gru_5/PartitionedCall:6 incompatible with expected variant.
1859/1859 [==============================] - 349s 185ms/step - batch_loss: 2.0443
Epoch 2/3
1859/1859 [==============================] - 350s 188ms/step - batch_loss: 1.0382
Epoch 3/3
1859/1859 [==============================] - 343s 184ms/step - batch_loss: 0.8085
<keras.callbacks.History at 0x7fb42c3eda10>
plt.plot(batch_loss.logs)
plt.ylim([0, 3])
plt.xlabel('Batch #')
plt.ylabel('CE/token')
Text(0, 0.5, 'CE/token')

png

প্লটে দৃশ্যমান লাফগুলি যুগের সীমানায় রয়েছে।

অনুবাদ করা

এখন যে মডেল প্রশিক্ষিত করা হয়, সম্পূর্ণ চালানো একটি ফাংশন বাস্তবায়ন text => text অনুবাদ।

এই মডেল চাহিদা invert জন্য text => token IDs ম্যাপিং দ্বারা উপলব্ধ output_text_processor । এটি বিশেষ টোকেনের জন্য আইডি জানতে হবে। এই সব নতুন ক্লাসের জন্য কনস্ট্রাক্টরে প্রয়োগ করা হয়। প্রকৃত অনুবাদ পদ্ধতির বাস্তবায়ন অনুসরণ করা হবে।

সামগ্রিকভাবে এটি প্রশিক্ষণ লুপের অনুরূপ, প্রতিটি ধাপে ডিকোডারে ইনপুটটি ডিকোডারের শেষ ভবিষ্যদ্বাণী থেকে একটি নমুনা।

class Translator(tf.Module):

  def __init__(self, encoder, decoder, input_text_processor,
               output_text_processor):
    self.encoder = encoder
    self.decoder = decoder
    self.input_text_processor = input_text_processor
    self.output_text_processor = output_text_processor

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

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

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

    self.start_token = index_from_string(tf.constant('[START]'))
    self.end_token = index_from_string(tf.constant('[END]'))
translator = Translator(
    encoder=train_translator.encoder,
    decoder=train_translator.decoder,
    input_text_processor=input_text_processor,
    output_text_processor=output_text_processor,
)
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:21: DeprecationWarning: `np.bool` is a deprecated alias for the builtin `bool`. To silence this warning, use `bool` by itself. Doing this will not modify any behavior and is safe. If you specifically wanted the numpy scalar type, use `np.bool_` here.
Deprecated in NumPy 1.20; for more details and guidance: https://numpy.org/devdocs/release/1.20.0-notes.html#deprecations

টোকেন আইডিগুলিকে পাঠ্যে রূপান্তর করুন

বাস্তবায়ন প্রথম পদ্ধতি tokens_to_text মানুষের পাঠযোগ্য টেক্সট টোকেন ID থেকে শুরু যা রূপান্তরিত করে।

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

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

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

কিছু র্যান্ডম টোকেন আইডি ইনপুট করুন এবং দেখুন এটি কী তৈরি করে:

example_output_tokens = tf.random.uniform(
    shape=[5, 2], minval=0, dtype=tf.int64,
    maxval=output_text_processor.vocabulary_size())
translator.tokens_to_text(example_output_tokens).numpy()
array([b'vain mysteries', b'funny ham', b'drivers responding',
       b'mysterious ignoring', b'fashion votes'], dtype=object)

ডিকোডারের পূর্বাভাস থেকে নমুনা

এই ফাংশনটি সেই ডিস্ট্রিবিউশন থেকে ডিকোডারের লগিট আউটপুট এবং নমুনা টোকেন আইডি নেয়:

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

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

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

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

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

  return new_tokens
Translator.sample = sample

কিছু র্যান্ডম ইনপুটগুলিতে এই ফাংশনটি পরীক্ষা করুন:

example_logits = tf.random.normal([5, 1, output_text_processor.vocabulary_size()])
example_output_tokens = translator.sample(example_logits, temperature=1.0)
example_output_tokens
<tf.Tensor: shape=(5, 1), dtype=int64, numpy=
array([[4506],
       [3577],
       [2961],
       [4586],
       [ 944]])>

অনুবাদ লুপ প্রয়োগ করুন

এখানে টেক্সট টু টেক্সট ট্রান্সলেশন লুপের সম্পূর্ণ বাস্তবায়ন রয়েছে।

এই বাস্তবায়ন পাইথন তালিকার মধ্যে ফলাফল সংগ্রহ ব্যবহার করার আগে tf.concat তাদের tensors মধ্যে যোগদানের জন্য।

এই বাস্তবায়ন স্ট্যাটিক্যালি কাছে গ্রাফ unrolls max_length পুনরাবৃত্তিও। পাইথনে উদগ্রীব মৃত্যুদন্ডের সাথে এটি ঠিক আছে।

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

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

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

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

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

    attention.append(dec_result.attention_weights)

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

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

    # Collect the generated tokens
    result_tokens.append(new_tokens)

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

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

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

এটি একটি সাধারণ ইনপুটে চালান:

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

result = translator.translate(
    input_text = input_text)

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

CPU times: user 165 ms, sys: 4.37 ms, total: 169 ms
Wall time: 164 ms

আপনি এই মডেল রপ্তানি করতে চান তাহলে আপনাকে একটি এই পদ্ধতি মোড়ানো করতে হবে tf.function । আপনি যদি এটি করার চেষ্টা করেন তবে এই মৌলিক বাস্তবায়নে কয়েকটি সমস্যা রয়েছে:

  1. ফলস্বরূপ গ্রাফগুলি খুব বড় এবং তৈরি করতে, সংরক্ষণ করতে বা লোড করতে কয়েক সেকেন্ড সময় নেয়৷
  2. আপনাকে অবশ্যই একটি স্ট্যাটিক্যালি unrolled লুপ থেকে বিরতি করতে পারেন যাতে এটা সবসময় চালানো হবে max_length পুনরাবৃত্তিও, এমনকি যদি সব আউটপুট করা হয়। কিন্তু তারপরেও এটি উদগ্রীব মৃত্যুদন্ডের চেয়ে সামান্য দ্রুততর।
@tf.function(input_signature=[tf.TensorSpec(dtype=tf.string, shape=[None])])
def tf_translate(self, input_text):
  return self.translate(input_text)

Translator.tf_translate = tf_translate

চালান tf.function একবার এটি কম্পাইল করার:

%%time
result = translator.tf_translate(
    input_text = input_text)
CPU times: user 18.8 s, sys: 0 ns, total: 18.8 s
Wall time: 18.7 s
%%time
result = translator.tf_translate(
    input_text = input_text)

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

CPU times: user 175 ms, sys: 0 ns, total: 175 ms
Wall time: 88 ms

[ঐচ্ছিক] একটি প্রতীকী লুপ ব্যবহার করুন

Translator.translate = translate_symbolic

প্রাথমিক বাস্তবায়ন আউটপুট সংগ্রহ করতে পাইথন তালিকা ব্যবহার করে। এই ব্যবহারের tf.range লুপ পুনরুক্তিকারীর হিসাবে, যার ফলে tf.autograph লুপ রূপান্তর করবে। এই বাস্তবায়ন সবচেয়ে বড় পরিবর্তন ব্যবহার tf.TensorArray পরিবর্তে পাইথন list জমা tensors করতে। tf.TensorArray গ্রাফ মোডে tensors সংখ্যা পরিবর্তনশীল সংগ্রহ করতে প্রয়োজন হয়।

উদগ্রীব সম্পাদনের সাথে এই বাস্তবায়নটি মূলের সাথে সমানভাবে সম্পাদন করে:

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

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

CPU times: user 175 ms, sys: 0 ns, total: 175 ms
Wall time: 170 ms

কিন্তু আপনি যখন একটি এটি মোড়ানো tf.function আপনি দুই পার্থক্য বিজ্ঞপ্তি পাবেন।

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

Translator.tf_translate = tf_translate

প্রথম: গ্রাফ সৃষ্টি অনেক দ্রুততর (~ 10x), যেহেতু এটি তৈরি করে না max_iterations মডেল কপি।

%%time
result = translator.tf_translate(
    input_text = input_text)
CPU times: user 1.79 s, sys: 0 ns, total: 1.79 s
Wall time: 1.77 s

দ্বিতীয়: সংকলিত ফাংশনটি ছোট ইনপুটগুলিতে অনেক দ্রুত হয় (এই উদাহরণে 5x), কারণ এটি লুপ থেকে বেরিয়ে যেতে পারে।

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

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

CPU times: user 40.1 ms, sys: 0 ns, total: 40.1 ms
Wall time: 17.1 ms

প্রক্রিয়াটি কল্পনা করুন

মনোযোগ ওজন দ্বারা ফিরে translate পদ্ধতি দেখান যেখানে মডেল 'দেখে' যখন এটি প্রতিটি আউটপুট টোকেন উত্পন্ন।

সুতরাং ইনপুটের উপর মনোযোগের যোগফল সবগুলিকে ফিরিয়ে দেওয়া উচিত:

a = result['attention'][0]

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

এখানে প্রথম উদাহরণের প্রথম আউটপুট ধাপের জন্য মনোযোগ বিতরণ করা হয়েছে। অপ্রশিক্ষিত মডেলের তুলনায় মনোযোগ এখন অনেক বেশি ফোকাস করা হয়েছে তা লক্ষ্য করুন:

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

png

যেহেতু ইনপুট এবং আউটপুট শব্দের মধ্যে কিছু মোটামুটি প্রান্তিককরণ রয়েছে, তাই আপনি আশা করেন যে মনোযোগ তির্যকের কাছাকাছি ফোকাস করা হবে:

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

png

একটি ভাল মনোযোগ প্লট করতে এখানে কিছু কোড আছে:

লেবেলযুক্ত মনোযোগ প্লট

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

png

আরও কয়েকটি বাক্য অনুবাদ করুন এবং সেগুলি প্লট করুন:

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

result = translator.tf_translate(three_input_text)

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

print()
this is my life .
are you still at home ?
all about killed .

CPU times: user 78 ms, sys: 23 ms, total: 101 ms
Wall time: 23.1 ms
result['text']
<tf.Tensor: shape=(3,), dtype=string, numpy=
array([b'this is my life .', b'are you still at home ?',
       b'all about killed .'], dtype=object)>
i = 0
plot_attention(result['attention'][i], three_input_text[i], result['text'][i])
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:14: UserWarning: FixedFormatter should only be used together with FixedLocator
  
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:15: UserWarning: FixedFormatter should only be used together with FixedLocator
  from ipykernel import kernelapp as app

png

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

png

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

png

ছোট বাক্যগুলি প্রায়শই ভাল কাজ করে, কিন্তু ইনপুটটি খুব দীর্ঘ হলে মডেলটি আক্ষরিকভাবে ফোকাস হারায় এবং যুক্তিসঙ্গত ভবিষ্যদ্বাণী প্রদান করা বন্ধ করে দেয়। এই জন্য দুটি প্রধান কারণ আছে:

  1. মডেলের ভবিষ্যদ্বাণী নির্বিশেষে, প্রতিটি ধাপে সঠিক টোকেন খাওয়ানোর জন্য মডেলটিকে শিক্ষক-জোর করে প্রশিক্ষণ দেওয়া হয়েছিল। মডেলটিকে আরও শক্তিশালী করা যেতে পারে যদি কখনও কখনও এটির নিজস্ব ভবিষ্যদ্বাণী দেওয়া হয়।
  2. মডেলটির শুধুমাত্র RNN অবস্থার মাধ্যমে পূর্ববর্তী আউটপুটে অ্যাক্সেস রয়েছে। যদি RNN অবস্থা দূষিত হয়ে যায়, তাহলে মডেলটির পুনরুদ্ধার করার কোন উপায় নেই। ট্রান্সফরমারস এনকোডার এবং ডিকোডার স্বয়ংসম্পূর্ণতা মনোযোগ ব্যবহার করে এই সমস্যার সমাধানের।
long_input_text = tf.constant([inp[-1]])

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

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

png

রপ্তানি

একবার আপনি আছে একটি মডেল আপনি সন্তুষ্ট থাকা একটি যেমন রপ্তানি করতে চাইতে পারেন tf.saved_model এই পাইথন প্রোগ্রাম যা এটি তৈরি করা ব্যবহার বাহিরে জন্য।

যেহেতু মডেলের উপশ্রেণী হয় tf.Module (মাধ্যমে keras.Model ), এবং রপ্তানির জন্য সব কার্যকারিতা একটি কম্পাইল করা হয় tf.function মডেলের পরিচ্ছন্নভাবে রপ্তানি উচিত tf.saved_model.save :

এখন ফাংশন আঁকা হয়েছে যে এটি ব্যবহার রপ্তানি করা যেতে পারে saved_model.save :

tf.saved_model.save(translator, 'translator',
                    signatures={'serving_default': translator.tf_translate})
2021-12-04 12:27:54.310890: W tensorflow/python/util/util.cc:368] Sets are not currently considered sequences, but this may change in the future, so consider avoiding using them.
WARNING:absl:Found untraced functions such as encoder_2_layer_call_fn, encoder_2_layer_call_and_return_conditional_losses, decoder_2_layer_call_fn, decoder_2_layer_call_and_return_conditional_losses, embedding_4_layer_call_fn while saving (showing 5 of 60). These functions will not be directly callable after loading.
INFO:tensorflow:Assets written to: translator/assets
INFO:tensorflow:Assets written to: translator/assets
reloaded = tf.saved_model.load('translator')
result = reloaded.tf_translate(three_input_text)
%%time
result = reloaded.tf_translate(three_input_text)

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

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

CPU times: user 42.8 ms, sys: 7.69 ms, total: 50.5 ms
Wall time: 20 ms

পরবর্তী পদক্ষেপ

  • একটি ভিন্ন ডেটা সেটটি ডাউনলোড ফরাসি জার্মান, অথবা ইংরেজিতে অনুবাদের নিয়ে পরীক্ষা করতে, উদাহরণস্বরূপ, ইংরেজি।
  • একটি বৃহত্তর ডেটাসেটে প্রশিক্ষণ নিয়ে পরীক্ষা করুন, বা আরও যুগ ব্যবহার করুন।
  • ব্যবহার করে দেখুন ট্রান্সফরমার টিউটোরিয়াল যা অনুরূপ অনুবাদ কাজের প্রয়োগ কিন্তু RNNs পরিবর্তে একটি ট্রান্সফরমার স্তর ব্যবহার করে। এই সংস্করণ একটি ব্যবহার text.BertTokenizer wordpiece tokenization বাস্তবায়ন।
  • কটাক্ষপাত আছে tensorflow_addons.seq2seq ক্রম মডেলের ক্রম এই সাজানোর বাস্তবায়ন জন্য। tfa.seq2seq প্যাকেজ মত উচ্চ স্তরের কার্যকারিতা অন্তর্ভুক্ত seq2seq.BeamSearchDecoder