2023年11月1日水曜日

RNNのチュートリアルをやってみた

RNNのチュートリアルをやってみた

概要

このチュートリアルをやってみました
所感などメモしておきます

環境

  • macOS 14.0 (m2mac mini pro)
  • Python 3.11.6
  • tensorflow 2.14.0

インストール

  • piepnv install tensorflow
  • pipenv install tensorflow-macos
  • pipenv install tensorflow-metal

訓練に時間がかかるので GPU を有効にします
使わないと10倍くらい訓練に時間がかかります

サンプルコード

import os
import time

import numpy as np
import tensorflow as tf

path_to_file = tf.keras.utils.get_file(
    "shakespeare.txt",
    "https://storage.googleapis.com/download.tensorflow.org/data/shakespeare.txt",
)
text = open(path_to_file, "rb").read().decode(encoding="utf-8")

# 1. 学習データの取得、作成
vocab = sorted(set(text))
char2idx = {u: i for i, u in enumerate(vocab)}
idx2char = np.array(vocab)
text_as_int = np.array([char2idx[c] for c in text])

seq_length = 100
examples_per_epoch = len(text) // (seq_length + 1)
char_dataset = tf.data.Dataset.from_tensor_slices(text_as_int)
sequences = char_dataset.batch(seq_length + 1, drop_remainder=True)


def split_input_target(chunk):
    input_text = chunk[:-1]
    target_text = chunk[1:]
    return input_text, target_text


dataset = sequences.map(split_input_target)


# 2, モデルの生成
BATCH_SIZE = 64
BUFFER_SIZE = 10000
dataset = dataset.shuffle(BUFFER_SIZE).batch(BATCH_SIZE, drop_remainder=True)

vocab_size = len(vocab)
embedding_dim = 256
rnn_units = 1024


def build_model(vocab_size, embedding_dim, rnn_units, batch_size):
    model = tf.keras.Sequential(
        [
            tf.keras.layers.Embedding(
                vocab_size, embedding_dim, batch_input_shape=[batch_size, None]
            ),
            tf.keras.layers.GRU(
                rnn_units,
                return_sequences=True,
                stateful=True,
                recurrent_initializer="glorot_uniform",
            ),
            tf.keras.layers.Dense(vocab_size),
        ]
    )
    return model


model = build_model(
    vocab_size=len(vocab),
    embedding_dim=embedding_dim,
    rnn_units=rnn_units,
    batch_size=BATCH_SIZE,
)


# 3. モデルの訓練
def loss(labels, logits):
    return tf.keras.losses.sparse_categorical_crossentropy(
        labels, logits, from_logits=True
    )


for input_example_batch, target_example_batch in dataset.take(1):
    example_batch_predictions = model(input_example_batch)
    sampled_indices = tf.random.categorical(example_batch_predictions[0], num_samples=1)
    sampled_indices = tf.squeeze(sampled_indices, axis=-1).numpy()
    example_batch_loss = loss(target_example_batch, example_batch_predictions)


model.compile(optimizer="adam", loss=loss)

checkpoint_dir = "./training_checkpoints"
checkpoint_prefix = os.path.join(checkpoint_dir, "ckpt_{epoch}")
checkpoint_callback = tf.keras.callbacks.ModelCheckpoint(
    filepath=checkpoint_prefix, save_weights_only=True
)

EPOCHS = 10
history = model.fit(
    dataset, epochs=EPOCHS, callbacks=[checkpoint_callback]
)  # これで訓練するのでこれが時間がかかる
tf.train.latest_checkpoint(checkpoint_dir)

model = build_model(vocab_size, embedding_dim, rnn_units, batch_size=1)
model.load_weights(tf.train.latest_checkpoint(checkpoint_dir)).expect_partial()
model.build(tf.TensorShape([1, None]))

model.summary()


# 4. モデルの評価
def generate_text(model, start_string):
    num_generate = 1000
    input_eval = [char2idx[s] for s in start_string]
    input_eval = tf.expand_dims(input_eval, 0)
    text_generated = []
    temperature = 1.0
    model.reset_states()
    for i in range(num_generate):
        predictions = model(input_eval)
        predictions = tf.squeeze(predictions, 0)
        predictions = predictions / temperature
        predicted_id = tf.random.categorical(predictions, num_samples=1)[-1, 0].numpy()
        input_eval = tf.expand_dims([predicted_id], 0)
        text_generated.append(idx2char[predicted_id])
    return start_string + "".join(text_generated)


print(generate_text(model, start_string="ROMEO: "))

ちょっと解説

流れとしては

  • 学習データの取得、作成
  • 学習モデルを作成
  • 学習モデルの訓練
  • モデルの評価

という感じです

今回のサンプルだと毎回訓練するので評価までに時間がかかります
GPU を使っていれば 1 分ほどで完了します

最後に

他気になった点としては

  • 毎回訓練させないで作成したモデルを使う回す方法
  • GPU が 10 コアあるが 1 コアしか使っていなかった (並列で学習させると一意性が担保できないから?)
  • そもそも keras の使い方や学習のさせ方がわかっていなさすぎる

とりあえず動かすことはできたのでいろいろと試してみたいと思います

参考サイト

0 件のコメント:

コメントを投稿