Разница в поведении при сборке TF Keras RNN двумя разными методами - PullRequest
0 голосов
/ 25 марта 2020

Я строю генератор текста RNN, в основном из документов Tensorflow здесь .

Мой вопрос, я определил модель двумя способами:

Метод ( 1):

model = tf.keras.Sequential([
        tf.keras.layers.Embedding(vocab_size, embed_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)
    ])

Метод (2):

model = tf.keras.Sequential()
model.add(tf.keras.layers.Embedding(vocab_size, embed_dim,
                                    batch_input_shape=[BATCH_SIZE, None]))
model.add(tf.keras.layers.GRU(rnn_units, return_sequences=True,
                              stateful=True,
                              recurrent_initializer='glorot_uniform'))
model.add(tf.keras.layers.Dense(vocab_size))

На мой взгляд, оба они делают одно и то же. Однако при генерации текста с:

def generate_text(model, start_string, length=1000):
    # converting start string to numbers (vectorisation)
    input_eval = [char2idx[s] for s in start_string]
    input_eval = tf.expand_dims(input_eval, 0)

    # initialise empty string to store results
    text = []

    model.reset_states()
    for i in range(length):
        predictions = model(input_eval)
        # remove batch dimension
        predictions = tf.squeeze(predictions, 0)

        # use categorical distribution to predict character returned by model
        predicted_id = tf.random.categorical(predictions, num_samples=1)[-1,0].numpy()

        # we pass the predicted character as the next input to the model
        # along with previous hidden state
        input_eval = tf.expand_dims([predicted_id], 0)

        # append predicted text
        text.append(idx2char[predicted_id])

    return (start_string + ''.join(text))

который я передаю:

print(generate_text(model, start_string=u'From '))

Метод (1) работает отлично, но метод (2) выдает следующую ошибку:

WARNING:tensorflow:Model was constructed with shape Tensor("embedding_1_input:0", shape=(64, None), dtype=float32) for input (64, None), but it was re-called on a Tensor with incompatible shape (1, 5).
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-33-eb814780c9fe> in <module>()
----> 1 print(generate_text(model, start_string=u'From ', length=PRINT))

14 frames
/usr/local/lib/python3.6/dist-packages/tensorflow_core/python/framework/ops.py in set_shape(self, shape)
   1086       raise ValueError(
   1087           "Tensor's shape %s is not compatible with supplied shape %s" %
-> 1088           (self.shape, shape))
   1089 
   1090   # Methods not supported / implemented for Eager Tensors.

ValueError: Tensor's shape (5, 64, 1024) is not compatible with supplied shape [5, 1, 1024]

Если бы кто-нибудь мог помочь мне понять, в чем разница между этими двумя методами, которые были бы удивительны, спасибо!

Редактировать: Включая сохранение модели и загрузку кода. Я использую это, чтобы сохранить модель (с размером пакета 64), а затем загрузить с размером пакета 1 для генерации текста. Сохранение весов:

checkpoint_callback = tf.keras.callbacks.ModelCheckpoint(
    filepath='./training_checkpoints/ckpt_{epoch}',
    save_weights_only=True
)

Загрузка весов в новую модель (размер партии = 1):

model = build_model(len(vocab_char), EMBED_DIM, UNITS, 1)
model.load_weights(tf.train.latest_checkpoint('./training_checkpoints'))
model.build(tf.TensorShape([1, None]))
model.summary()
...