Правильное структурирование текстовых данных для генерации текста с помощью модели Tensorflow - PullRequest
1 голос
/ 11 февраля 2020

Я пытаюсь обучить мою модель генерировать предложения длиной не более 210 символов. Из того, что я прочитал, я видел только тренировку по «непрерывному» тексту. Как книга. Однако я пытаюсь тренировать свою модель на отдельных предложениях.

Я довольно плохо знаком с тензорным потоком и ML, поэтому сейчас я могу тренировать свою модель, но она генерирует мусор, на первый взгляд случайный текст. У меня есть 10 000 предложений, поэтому я думаю, что у меня достаточно данных.

Обзор моих данных

Структура [['SENTENCE'], ['SENTENCE2'] ... ]

Подготовка данных

tokenizer = keras.preprocessing.text.Tokenizer(num_words=209, lower=False, char_level=True, filters='#$%&()*+-<=>@[\\]^_`{|}~\t\n')
tokenizer.fit_on_texts(df['title'].values)
df['encoded_with_keras'] = tokenizer.texts_to_sequences(df['title'].values)

dataset = df['encoded_with_keras'].values
dataset = tf.keras.preprocessing.sequence.pad_sequences(dataset, padding='post')

dataset = dataset.flatten()

dataset = tf.data.Dataset.from_tensor_slices(dataset)

sequences = dataset.batch(seq_len+1, drop_remainder=True)

def create_seq_targets(seq):
    input_txt = seq[:-1]
    target_txt = seq[1:]
    return input_txt, target_txt

dataset = sequences.map(create_seq_targets)

dataset = dataset.shuffle(buffer_size).batch(batch_size, drop_remainder=True)

Модель

def create_model(vocab_size, embed_dim, rnn_neurons, batch_size):
    model = Sequential()
    model.add(Embedding(vocab_size, embed_dim, batch_input_shape=[batch_size, None],input_length=209, mask_zero=True))
    model.add(LSTM(rnn_neurons, return_sequences=True, stateful=True,))
    model.add(Dropout(0.2))
    model.add(Dense(258, activation='relu'))
    model.add(Dropout(0.2))
    model.add(Dense(128, activation='relu'))
    model.add(Dropout(0.2))
    model.add(Dense(vocab_size, activation='softmax'))
    model.compile(optimizer='adam', loss="sparse_categorical_crossentropy")
    return model

Когда я даю модели последовательность для начала Я возвращаюсь к абсолютной чепухе, и в конце концов модель предсказывает 0, которого нет в отображении char_index.

Редактировать

Генерация текста


epochs = 2

# Directory where the checkpoints will be saved
checkpoint_dir = './training_checkpoints'
# Name of the checkpoint files
checkpoint_prefix = os.path.join(checkpoint_dir, "ckpt_{epoch}")

checkpoint_callback=tf.keras.callbacks.ModelCheckpoint(
    filepath=checkpoint_prefix,
    save_weights_only=True)


model = create_model(vocab_size = vocab_size,
  embed_dim=embed_dim,
  rnn_neurons=rnn_neurons,
  batch_size=1)

model.load_weights(tf.train.latest_checkpoint(checkpoint_dir))

model.build(tf.TensorShape([1, None]))

def generate_text(model, start_string):
  num_generate = 200

  input_eval = [char_2_index[s] for s in start_string]
  input_eval = tf.expand_dims(input_eval, 0)

  text_generated = []

  temperature = 1

  # model.reset_states()
  for i in range(num_generate):
      print(text_generated)
      predictions = model(input_eval)

      predictions = tf.squeeze(predictions, 0)

      predictions = predictions / temperature

      predicted_id = tf.random.categorical(predictions, num_samples=1)[-1,0].numpy()
      print(predicted_id)

      input_eval = tf.expand_dims([predicted_id], 0)

      text_generated.append(index_2_char[predicted_id])

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

1 Ответ

0 голосов
/ 14 февраля 2020

Есть несколько вещей, которые нужно изменить с первого взгляда.

  • Токенизатор должен иметь num_words = vocab_size
  • Сначала (не анализировал это глубоко), я Вы не можете себе представить, почему вы сглаживаете свой набор данных и получаете срезы, если, вероятно, он правильно структурирован
  • Вы не можете использовать stateful=True, если не хотите, чтобы «партия 2 была продолжением партии 1», вы есть отдельные предложения, поэтому stateful=False. (Если вы не тренируетесь правильно с циклами ручной тренировки и состояниями сброса для каждой партии, что является ненужной проблемой на этапе обучения)

Что необходимо проверить визуально:

Входные данные должны иметь следующий формат:

[
    [1,2,3,6,10,4,10, ...up to sentence length - 1...],
    [5,6,3,6,7,3,11,... up to sentence length - 1...],
    .... up to number of sentences ...
]

Выходные данные должны быть:

[
    [2,3,6,10,4,10,15 ...], #equal to input data, shifted by 1
    [6,3,6,7,3,11,13, ...],
    ...
]

Распечатать несколько строк из них, чтобы проверить, они правильно обработаны, как и предполагалось.

Обучение будет легко:

model.fit(input_data, output_data, epochs=....)

Да, ваша модель будет предсказывать нули, так как в ваших данных есть нули, это не странно: вы сделал pad_sequences.
Вы можете интерпретировать ноль как «конец предложения» в этом случае, так как вы сделали 'post' pading. Когда ваша модель дает вам ноль, она решила, что сгенерированное ею предложение должно закончиться в этой точке - если она была хорошо обучена, она, вероятно, продолжит выводить нули для этого предложения с этого момента.


Генерация новых предложений

Эта часть более сложна, и вам нужно переписать модель, теперь имеющую значение stative=True, и перенести веса из обученной модели в эту новую модель.

Прежде чем что-либо позвонить model.reset_states().

Вам нужно будет вручную кормить партию формой (number_of_sentences=batch_size, 1). Это будет «первый символ» каждого предложения, которое он сгенерирует. Результатом будет «второй символ» каждого предложения.

Получите этот вывод и подпишите им модель. Он будет генерировать «третий символ» каждого предложения. И так далее.

Когда все выходные значения равны нулю, все предложения полностью сгенерированы, и вы можете остановить l oop.

еще раз позвонить model.reset_states(), прежде чем пытаться сгенерировать новый пакет предложений.


Примеры такого прогнозирования можно найти здесь: { ссылка }

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...