TensorFlow 2.0 Beta : 上級 Tutorials : テキストとシークエンス :- 画像キャプショニング with Attention (翻訳/解説)
翻訳 : (株)クラスキャット セールスインフォメーション
作成日時 : 07/06/2019
* 本ページは、TensorFlow の本家サイトの TF 2.0 Beta – Advanced Tutorials – Text and sequences の以下のページを翻訳した上で適宜、補足説明したものです:
* サンプルコードの動作確認はしておりますが、必要な場合には適宜、追加改変しています。
* ご自由にリンクを張って頂いてかまいませんが、sales-info@classcat.com までご一報いただけると嬉しいです。
テキストとシークエンス :- 画像キャプショニング with Attention
下のような画像が与えられたとき、私達の目標は “a surfer riding on a wave” のようなキャプションを生成することです。
これを達成するために、attention ベースのモデルを使用します、これは (モデルが) キャプションを生成するとき画像のどのパートにモデルが注目しているかを見ることを可能にします。
モデル・アーキテクチャは Show, Attend and Tell: Neural Image Caption Generation with Visual Attention に類似しています。
このノートブックは end-to-end なサンプルです。ノートブックを実行する時、それは MS-COCO データセットをダウンロードし、Inception V3 を使用して画像のサブセットを前処理してキャッシュし、エンコーダ-デコーダ・モデルを訓練して、そして訓練されたモデルを使用して新しい画像上でキャプションを生成します。
このサンプルでは、比較的小さい総量のデータ上でモデルを訓練します — およそ 20,000 画像のための最初の 30,000 キャプションです (データセットの画像毎に複数のキャプションがあるからです)。
from __future__ import absolute_import, division, print_function, unicode_literals
!pip install -q tensorflow-gpu==2.0.0-beta1 import tensorflow as tf # You'll generate plots of attention in order to see which parts of an image # our model focuses on during captioning import matplotlib.pyplot as plt # Scikit-learn includes many helpful utilities from sklearn.model_selection import train_test_split from sklearn.utils import shuffle import re import numpy as np import os import time import json from glob import glob from PIL import Image import pickle
MS-COCO データセットをダウンロードして準備する
モデルを訓練するために MS-COCO データセット を使用します。このデータセットは 82,000 以上の画像を含み、その各々は少なくとも 5 つの異なるキャプションのアノテーションを持ちます。下のコードはデータセットを自動的にダウンロードして抽出します。
警告: これから先に巨大なダウンロード があります。訓練セットを使用します、これは 13 GB ファイルです。
annotation_zip = tf.keras.utils.get_file('captions.zip', cache_subdir=os.path.abspath('.'), origin = 'http://images.cocodataset.org/annotations/annotations_trainval2014.zip', extract = True) annotation_file = os.path.dirname(annotation_zip)+'/annotations/captions_train2014.json' name_of_zip = 'train2014.zip' if not os.path.exists(os.path.abspath('.') + '/' + name_of_zip): image_zip = tf.keras.utils.get_file(name_of_zip, cache_subdir=os.path.abspath('.'), origin = 'http://images.cocodataset.org/zips/train2014.zip', extract = True) PATH = os.path.dirname(image_zip)+'/train2014/' else: PATH = os.path.abspath('.')+'/train2014/'
Downloading data from http://images.cocodataset.org/annotations/annotations_trainval2014.zip 252878848/252872794 [==============================] - 6s 0us/step Downloading data from http://images.cocodataset.org/zips/train2014.zip 13510574080/13510573713 [==============================] - 298s 0us/step
オプション: 訓練セットのサイズを制限する
このチュートリアルのための訓練を高速化するため、モデルを訓練するために 30,000 キャプションのサブセットとそれらに対応する画像を使用します。より多くのデータを使用することの選択は改善されたキャプショニング品質という結果になるでしょう。
# Read the json file with open(annotation_file, 'r') as f: annotations = json.load(f) # Store captions and image names in vectors all_captions = [] all_img_name_vector = [] for annot in annotations['annotations']: caption = '' + annot['caption'] + ' ' image_id = annot['image_id'] full_coco_image_path = PATH + 'COCO_train2014_' + '%012d.jpg' % (image_id) all_img_name_vector.append(full_coco_image_path) all_captions.append(caption) # Shuffle captions and image_names together # Set a random state train_captions, img_name_vector = shuffle(all_captions, all_img_name_vector, random_state=1) # Select the first 30000 captions from the shuffled set num_examples = 30000 train_captions = train_captions[:num_examples] img_name_vector = img_name_vector[:num_examples]
len(train_captions), len(all_captions)
(30000, 414113)
InceptionV3 を使用して画像を前処理する
次に、各画像を分類するために (Imagenet で事前訓練された) InceptionV3 を使用します。最後の畳込み層から特徴を抽出します。
最初に、画像を次により inceptionV3 が想定するフォーマットに変換する必要があります : * 画像を 299px x 299px にリサイズします。* preprocess_input メソッドを使用して画像を正規化するために 画像を前処理します、その結果それは -1 から 1 の範囲のピクセルを含みます、これは InceptionV3 を訓練するために使用された画像のフォーマットに適合させるためです。
def load_image(image_path): img = tf.io.read_file(image_path) img = tf.image.decode_jpeg(img, channels=3) img = tf.image.resize(img, (299, 299)) img = tf.keras.applications.inception_v3.preprocess_input(img) return img, image_path
InceptionV3 を初期化して事前訓練された Imagenet 重みをロードする
さて tf.keras モデルを作成します、そこでは出力層は InceptionV3 アーキテクチャの最後の畳み込み層です。この層の出力の shape は 8x8x2048 です。最後の畳み込み層を使用します、何故ならばこのサンプルでは attention を使用しているからです。訓練の間にこの初期化は遂行しません、何故ならばそれはボトルネックになり得るからです。
- 各画像はネットワークを通して forward されて最後に得られるベクトルは辞書にストアされます (image_name –> feature_vector)。
- 総ての画像がネットワークを通された後、辞書を pickle 化してそれをディスクにセーブします。
image_model = tf.keras.applications.InceptionV3(include_top=False, weights='imagenet') new_input = image_model.input hidden_layer = image_model.layers[-1].output image_features_extract_model = tf.keras.Model(new_input, hidden_layer)
Downloading data from https://github.com/fchollet/deep-learning-models/releases/download/v0.5/inception_v3_weights_tf_dim_ordering_tf_kernels_notop.h5 87916544/87910968 [==============================] - 2s 0us/step
InceptionV3 から抽出した特徴をキャッシュする
各画像を InceptionV3 で前処理して出力をディスクにキャッシュします。出力を RAM にキャッシングすることはより高速ですがメモリ集約的で、画像毎に 8 * 8 * 2048 floats を必要とします。書く時点で、これは Colab のメモリ制限を超過するでしょう (現在 12 GB メモリ)。
パフォーマンスはより洗練されたキャッシング・ストラテジー (例えば、ディスク I/O へのランダムアクセスを減じるために画像群をシャーディングする) で改善されるかもしれませんが、それはより多くのコードを必要とするでしょう。
キャッシングは GPU を持つ Colab で実行するのにおよそ 10 分間かかります。進捗バーを見ることを望む場合、次ができます :
- tqdm をインストールする:
!pip install -q tqdm - Import tqdm:
from tqdm import tqdm - 次の行を変更する:
for img, path in image_dataset:
to:
for img, path in tqdm(image_dataset):.
# Get unique images encode_train = sorted(set(img_name_vector)) # Feel free to change batch_size according to your system configuration image_dataset = tf.data.Dataset.from_tensor_slices(encode_train) image_dataset = image_dataset.map( load_image, num_parallel_calls=tf.data.experimental.AUTOTUNE).batch(16) for img, path in image_dataset: batch_features = image_features_extract_model(img) batch_features = tf.reshape(batch_features, (batch_features.shape[0], -1, batch_features.shape[3])) for bf, p in zip(batch_features, path): path_of_feature = p.numpy().decode("utf-8") np.save(path_of_feature, bf.numpy())
キャプションを前処理してトークン化する
- 最初にキャプションをトークン化します (例えば、スペースで分割することにより)。これはデータの総ての一意な単語の語彙を与えます (例えば、”surfing”, “football” 等)。
- 次に、(メモリを節約するために) 語彙サイズを top 5,000 単語に制限します。総ての他の単語をトークン “UNK” (unknown) で置き替えます。
- それから単語-to-インデックスとインデックス-to-単語マッピングを作成します。
- 最後に、最長のものと同じ長さになるように総てのシークエンスをパッドします。
# Find the maximum length of any caption in our dataset def calc_max_length(tensor): return max(len(t) for t in tensor)
# Choose the top 5000 words from the vocabulary top_k = 5000 tokenizer = tf.keras.preprocessing.text.Tokenizer(num_words=top_k, oov_token="", filters='!"#$%&()*+.,-/:;=?@[\]^_`{|}~ ') tokenizer.fit_on_texts(train_captions) train_seqs = tokenizer.texts_to_sequences(train_captions)
tokenizer.word_index['<pad>'] = 0 tokenizer.index_word[0] = '<pad>'
# Create the tokenized vectors train_seqs = tokenizer.texts_to_sequences(train_captions)
# Pad each vector to the max_length of the captions # If you do not provide a max_length value, pad_sequences calculates it automatically cap_vector = tf.keras.preprocessing.sequence.pad_sequences(train_seqs, padding='post')
# Calculates the max_length, which is used to store the attention weights max_length = calc_max_length(train_seqs)
データを訓練とテストに分割する
# Create training and validation sets using an 80-20 split img_name_train, img_name_val, cap_train, cap_val = train_test_split(img_name_vector, cap_vector, test_size=0.2, random_state=0)
len(img_name_train), len(cap_train), len(img_name_val), len(cap_val)
(24000, 24000, 6000, 6000)
訓練のために tf.data dataset を作成します
画像とキャプションの準備ができました!次に、モデルを訓練するために使用する tf.data データセットを作成しましょう。
# Feel free to change these parameters according to your system's configuration BATCH_SIZE = 64 BUFFER_SIZE = 1000 embedding_dim = 256 units = 512 vocab_size = len(tokenizer.word_index) + 1 num_steps = len(img_name_train) // BATCH_SIZE # Shape of the vector extracted from InceptionV3 is (64, 2048) # These two variables represent that vector shape features_shape = 2048 attention_features_shape = 64
# Load the numpy files def map_func(img_name, cap): img_tensor = np.load(img_name.decode('utf-8')+'.npy') return img_tensor, cap
dataset = tf.data.Dataset.from_tensor_slices((img_name_train, cap_train)) # Use map to load the numpy files in parallel dataset = dataset.map(lambda item1, item2: tf.numpy_function( map_func, [item1, item2], [tf.float32, tf.int32]), num_parallel_calls=tf.data.experimental.AUTOTUNE) # Shuffle and batch dataset = dataset.shuffle(BUFFER_SIZE).batch(BATCH_SIZE) dataset = dataset.prefetch(buffer_size=tf.data.experimental.AUTOTUNE)
モデル
面白い事実: 下のデコーダは ニューラル機械翻訳 with Attention のためのサンプルのものと同一です。
モデル・アーキテクチャは Show, Attend and Tell ペーパーによりインスパイアされています。
- このサンプルでは、InceptionV3 のより低い畳み込み層から特徴を抽出します、これは shape (8, 8, 2048) のベクトルを与えます。
- それを (64, 2048) の shape に押しつぶします。
- それからこのベクトルは CNN エンコーダを通して渡されます (これは単一の完全結合層から成ります)。
- RNN (ここでは GRU) が次の単語を予測するために画像に渡り注視します。
class BahdanauAttention(tf.keras.Model): def __init__(self, units): super(BahdanauAttention, self).__init__() self.W1 = tf.keras.layers.Dense(units) self.W2 = tf.keras.layers.Dense(units) self.V = tf.keras.layers.Dense(1) def call(self, features, hidden): # features(CNN_encoder output) shape == (batch_size, 64, embedding_dim) # hidden shape == (batch_size, hidden_size) # hidden_with_time_axis shape == (batch_size, 1, hidden_size) hidden_with_time_axis = tf.expand_dims(hidden, 1) # score shape == (batch_size, 64, hidden_size) score = tf.nn.tanh(self.W1(features) + self.W2(hidden_with_time_axis)) # attention_weights shape == (batch_size, 64, 1) # you get 1 at the last axis because you are applying score to self.V attention_weights = tf.nn.softmax(self.V(score), axis=1) # context_vector shape after sum == (batch_size, hidden_size) context_vector = attention_weights * features context_vector = tf.reduce_sum(context_vector, axis=1) return context_vector, attention_weights
class CNN_Encoder(tf.keras.Model): # Since you have already extracted the features and dumped it using pickle # This encoder passes those features through a Fully connected layer def __init__(self, embedding_dim): super(CNN_Encoder, self).__init__() # shape after fc == (batch_size, 64, embedding_dim) self.fc = tf.keras.layers.Dense(embedding_dim) def call(self, x): x = self.fc(x) x = tf.nn.relu(x) return x
class RNN_Decoder(tf.keras.Model): def __init__(self, embedding_dim, units, vocab_size): super(RNN_Decoder, self).__init__() self.units = units self.embedding = tf.keras.layers.Embedding(vocab_size, embedding_dim) self.gru = tf.keras.layers.GRU(self.units, return_sequences=True, return_state=True, recurrent_initializer='glorot_uniform') self.fc1 = tf.keras.layers.Dense(self.units) self.fc2 = tf.keras.layers.Dense(vocab_size) self.attention = BahdanauAttention(self.units) def call(self, x, features, hidden): # defining attention as a separate model context_vector, attention_weights = self.attention(features, hidden) # x shape after passing through embedding == (batch_size, 1, embedding_dim) x = self.embedding(x) # x shape after concatenation == (batch_size, 1, embedding_dim + hidden_size) x = tf.concat([tf.expand_dims(context_vector, 1), x], axis=-1) # passing the concatenated vector to the GRU output, state = self.gru(x) # shape == (batch_size, max_length, hidden_size) x = self.fc1(output) # x shape == (batch_size * max_length, hidden_size) x = tf.reshape(x, (-1, x.shape[2])) # output shape == (batch_size * max_length, vocab) x = self.fc2(x) return x, state, attention_weights def reset_state(self, batch_size): return tf.zeros((batch_size, self.units))
encoder = CNN_Encoder(embedding_dim) decoder = RNN_Decoder(embedding_dim, units, vocab_size)
optimizer = tf.keras.optimizers.Adam() 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_mean(loss_)
チェックポイント
checkpoint_path = "./checkpoints/train" ckpt = tf.train.Checkpoint(encoder=encoder, decoder=decoder, optimizer = optimizer) ckpt_manager = tf.train.CheckpointManager(ckpt, checkpoint_path, max_to_keep=5)
start_epoch = 0 if ckpt_manager.latest_checkpoint: start_epoch = int(ckpt_manager.latest_checkpoint.split('-')[-1])
訓練
- それぞれの .npy ファイルにストアされている特徴を抽出してからそれらの特徴をエンコーダを通して渡します。
- エンコーダ出力、(0 に初期化された) 隠れ状態そしてデコーダ入力 (それは start トークンです) がデコーダに渡されます。
- デコーダは予測とデコーダ隠れ状態を返します。
- そしてデコーダ隠れ状態はモデルに渡し戻されて予測は損失を計算するために使用されます。
- デコーダへの次の入力を決めるために teacher forcing を使用します。
- teacher forcing はそこではターゲット単語がデコーダへの次の入力として渡されるようなテクニックです。
- 最後のステップは勾配を計算してそれを optimizer に適用してそして backpropagate します。
# adding this in a separate cell because if you run the training cell # many times, the loss_plot array will be reset loss_plot = []
@tf.function def train_step(img_tensor, target): loss = 0 # initializing the hidden state for each batch # because the captions are not related from image to image hidden = decoder.reset_state(batch_size=target.shape[0]) dec_input = tf.expand_dims([tokenizer.word_index['']] * BATCH_SIZE, 1) with tf.GradientTape() as tape: features = encoder(img_tensor) for i in range(1, target.shape[1]): # passing the features through the decoder predictions, hidden, _ = decoder(dec_input, features, hidden) loss += loss_function(target[:, i], predictions) # using teacher forcing dec_input = tf.expand_dims(target[:, i], 1) total_loss = (loss / int(target.shape[1])) trainable_variables = encoder.trainable_variables + decoder.trainable_variables gradients = tape.gradient(loss, trainable_variables) optimizer.apply_gradients(zip(gradients, trainable_variables)) return loss, total_loss
EPOCHS = 20 for epoch in range(start_epoch, EPOCHS): start = time.time() total_loss = 0 for (batch, (img_tensor, target)) in enumerate(dataset): batch_loss, t_loss = train_step(img_tensor, target) total_loss += t_loss if batch % 100 == 0: print ('Epoch {} Batch {} Loss {:.4f}'.format( epoch + 1, batch, batch_loss.numpy() / int(target.shape[1]))) # storing the epoch end loss value to plot later loss_plot.append(total_loss / num_steps) if epoch % 5 == 0: ckpt_manager.save() print ('Epoch {} Loss {:.6f}'.format(epoch + 1, total_loss/num_steps)) print ('Time taken for 1 epoch {} sec\n'.format(time.time() - start))
Epoch 1 Batch 0 Loss 2.0500 Epoch 1 Batch 100 Loss 1.1069 Epoch 1 Batch 200 Loss 0.9892 Epoch 1 Batch 300 Loss 0.9893 Epoch 1 Loss 1.075467 Time taken for 1 epoch 208.44214582443237 sec Epoch 2 Batch 0 Loss 0.8720 Epoch 2 Batch 100 Loss 0.7934 Epoch 2 Batch 200 Loss 0.7722 Epoch 2 Batch 300 Loss 0.8354 Epoch 2 Loss 0.813784 Time taken for 1 epoch 69.56642508506775 sec Epoch 3 Batch 0 Loss 0.7634 Epoch 3 Batch 100 Loss 0.7146 Epoch 3 Batch 200 Loss 0.6952 Epoch 3 Batch 300 Loss 0.7735 Epoch 3 Loss 0.736129 Time taken for 1 epoch 68.59322023391724 sec Epoch 4 Batch 0 Loss 0.7161 Epoch 4 Batch 100 Loss 0.6617 Epoch 4 Batch 200 Loss 0.6478 Epoch 4 Batch 300 Loss 0.7399 Epoch 4 Loss 0.689814 Time taken for 1 epoch 68.88294863700867 sec Epoch 5 Batch 0 Loss 0.6749 Epoch 5 Batch 100 Loss 0.6207 Epoch 5 Batch 200 Loss 0.6135 Epoch 5 Batch 300 Loss 0.7017 Epoch 5 Loss 0.653753 Time taken for 1 epoch 70.6437156200409 sec Epoch 6 Batch 0 Loss 0.6470 Epoch 6 Batch 100 Loss 0.5872 Epoch 6 Batch 200 Loss 0.5889 Epoch 6 Batch 300 Loss 0.6672 Epoch 6 Loss 0.623586 Time taken for 1 epoch 69.7294511795044 sec Epoch 7 Batch 0 Loss 0.6234 Epoch 7 Batch 100 Loss 0.5594 Epoch 7 Batch 200 Loss 0.5643 Epoch 7 Batch 300 Loss 0.6386 Epoch 7 Loss 0.598236 Time taken for 1 epoch 67.98005199432373 sec Epoch 8 Batch 0 Loss 0.6024 Epoch 8 Batch 100 Loss 0.5331 Epoch 8 Batch 200 Loss 0.5449 Epoch 8 Batch 300 Loss 0.6187 Epoch 8 Loss 0.574878 Time taken for 1 epoch 69.89835166931152 sec Epoch 9 Batch 0 Loss 0.5754 Epoch 9 Batch 100 Loss 0.5234 Epoch 9 Batch 200 Loss 0.5256 Epoch 9 Batch 300 Loss 0.6037 Epoch 9 Loss 0.553293 Time taken for 1 epoch 68.3003740310669 sec Epoch 10 Batch 0 Loss 0.5569 Epoch 10 Batch 100 Loss 0.4994 Epoch 10 Batch 200 Loss 0.4934 Epoch 10 Batch 300 Loss 0.5600 Epoch 10 Loss 0.533848 Time taken for 1 epoch 69.4975745677948 sec Epoch 11 Batch 0 Loss 0.5454 Epoch 11 Batch 100 Loss 0.4740 Epoch 11 Batch 200 Loss 0.4806 Epoch 11 Batch 300 Loss 0.5392 Epoch 11 Loss 0.516213 Time taken for 1 epoch 70.42340064048767 sec Epoch 12 Batch 0 Loss 0.5324 Epoch 12 Batch 100 Loss 0.4572 Epoch 12 Batch 200 Loss 0.4702 Epoch 12 Batch 300 Loss 0.5303 Epoch 12 Loss 0.499344 Time taken for 1 epoch 69.0728235244751 sec Epoch 13 Batch 0 Loss 0.5100 Epoch 13 Batch 100 Loss 0.4414 Epoch 13 Batch 200 Loss 0.4668 Epoch 13 Batch 300 Loss 0.5122 Epoch 13 Loss 0.482220 Time taken for 1 epoch 68.99846816062927 sec Epoch 14 Batch 0 Loss 0.4834 Epoch 14 Batch 100 Loss 0.4519 Epoch 14 Batch 200 Loss 0.4227 Epoch 14 Batch 300 Loss 0.4884 Epoch 14 Loss 0.465576 Time taken for 1 epoch 67.78600645065308 sec Epoch 15 Batch 0 Loss 0.4607 Epoch 15 Batch 100 Loss 0.4202 Epoch 15 Batch 200 Loss 0.4004 Epoch 15 Batch 300 Loss 0.5098 Epoch 15 Loss 0.449775 Time taken for 1 epoch 70.15660309791565 sec Epoch 16 Batch 0 Loss 0.4475 Epoch 16 Batch 100 Loss 0.4179 Epoch 16 Batch 200 Loss 0.3996 Epoch 16 Batch 300 Loss 0.4680 Epoch 16 Loss 0.436949 Time taken for 1 epoch 68.8959448337555 sec Epoch 17 Batch 0 Loss 0.4261 Epoch 17 Batch 100 Loss 0.3849 Epoch 17 Batch 200 Loss 0.3903 Epoch 17 Batch 300 Loss 0.4470 Epoch 17 Loss 0.424533 Time taken for 1 epoch 69.10690641403198 sec Epoch 18 Batch 0 Loss 0.4112 Epoch 18 Batch 100 Loss 0.3673 Epoch 18 Batch 200 Loss 0.3934 Epoch 18 Batch 300 Loss 0.4380 Epoch 18 Loss 0.412055 Time taken for 1 epoch 69.39148497581482 sec Epoch 19 Batch 0 Loss 0.3895 Epoch 19 Batch 100 Loss 0.3556 Epoch 19 Batch 200 Loss 0.3743 Epoch 19 Batch 300 Loss 0.4130 Epoch 19 Loss 0.399825 Time taken for 1 epoch 68.86549687385559 sec Epoch 20 Batch 0 Loss 0.3956 Epoch 20 Batch 100 Loss 0.3547 Epoch 20 Batch 200 Loss 0.3462 Epoch 20 Batch 300 Loss 0.4282 Epoch 20 Loss 0.391777 Time taken for 1 epoch 70.18613910675049 sec
plt.plot(loss_plot) plt.xlabel('Epochs') plt.ylabel('Loss') plt.title('Loss Plot') plt.show()
キャプション!
- evaluate 関数は訓練ループに類似しています、ここでは teacher forcing を使用しないことを除いて。各時間ステップにおけるデコーダへの入力は隠れ状態とエンコーダ出力に加えてその前の予測です。
- モデルが end トークンを予測するとき予測は停止します。
- そして総ての時間ステップのために attention 重みをストアします。
def evaluate(image): attention_plot = np.zeros((max_length, attention_features_shape)) hidden = decoder.reset_state(batch_size=1) temp_input = tf.expand_dims(load_image(image)[0], 0) img_tensor_val = image_features_extract_model(temp_input) img_tensor_val = tf.reshape(img_tensor_val, (img_tensor_val.shape[0], -1, img_tensor_val.shape[3])) features = encoder(img_tensor_val) dec_input = tf.expand_dims([tokenizer.word_index['']], 0) result = [] for i in range(max_length): predictions, hidden, attention_weights = decoder(dec_input, features, hidden) attention_plot[i] = tf.reshape(attention_weights, (-1, )).numpy() predicted_id = tf.argmax(predictions[0]).numpy() result.append(tokenizer.index_word[predicted_id]) if tokenizer.index_word[predicted_id] == ' ': return result, attention_plot dec_input = tf.expand_dims([predicted_id], 0) attention_plot = attention_plot[:len(result), :] return result, attention_plot
def plot_attention(image, result, attention_plot): temp_image = np.array(Image.open(image)) fig = plt.figure(figsize=(10, 10)) len_result = len(result) for l in range(len_result): temp_att = np.resize(attention_plot[l], (8, 8)) ax = fig.add_subplot(len_result//2, len_result//2, l+1) ax.set_title(result[l]) img = ax.imshow(temp_image) ax.imshow(temp_att, cmap='gray', alpha=0.6, extent=img.get_extent()) plt.tight_layout() plt.show()
# captions on the validation set rid = np.random.randint(0, len(img_name_val)) image = img_name_val[rid] real_caption = ' '.join([tokenizer.index_word[i] for i in cap_val[rid] if i not in [0]]) result, attention_plot = evaluate(image) print ('Real Caption:', real_caption) print ('Prediction Caption:', ' '.join(result)) plot_attention(image, result, attention_plot) # opening the image Image.open(img_name_val[rid])
Real Caption: <start> a city street has lighted signs and buildings <end> Prediction Caption: a group of people are taken in the background <end>
貴方自身の画像でそれを試してください
楽しみのために、貴方自身の画像を丁度訓練したモデルでキャプションするために使用できるメソッドを下で提供しました。留意してください、それはデータの比較的小さい量の上で訓練されました、そして貴方の画像は訓練データとは異なるかもしれません (そのため奇妙な結果に備えてください!)
image_url = 'https://tensorflow.org/images/surf.jpg' image_extension = image_url[-4:] image_path = tf.keras.utils.get_file('image'+image_extension, origin=image_url) result, attention_plot = evaluate(image_path) print ('Prediction Caption:', ' '.join(result)) plot_attention(image_path, result, attention_plot) # opening the image Image.open(image_path)
Prediction Caption: a man in a man in a suit and a picture of a man in a suit and a picture of a man in a suit and a picture of a man in a suit and a picture of a man in a suit and a picture of a /home/kbuilder/.local/lib/python3.5/site-packages/matplotlib/tight_layout.py:199: UserWarning: Tight layout not applied. tight_layout cannot make axes width small enough to accommodate all axes decorations warnings.warn('Tight layout not applied. '
以上