TensorFlow RNN 文本生成示例教程

Posted

技术标签:

【中文标题】TensorFlow RNN 文本生成示例教程【英文标题】:Tensorflow RNN text generation example tutorial 【发布时间】:2020-03-06 00:30:33 【问题描述】:

查看本教程here,他们使用“Romeo:”的起始序列。

int(generate_text(model, start_string=u"ROMEO: "))

但是,看看实际的生成步骤,是否可以说它只使用最后一个字符“”?所以无论我们使用“ROMEO:”还是只使用“”,都是一样的?很难测试,因为它从输出分布中采样...

与此相关的是,由于原始训练序列要长得多,因此尚不清楚如何从如此短的字符串中进行预测。我知道,如果我们在 100 个字符的历史上进行训练,我们会预测第 101 个字符,然后使用 2-101 来预测 102 个字符......但是它是如何从 7 个字符开始的呢?

编辑

作为一个具体的例子,我将我的模型重新设计为以下形式:

    model = tf.keras.Sequential()
model.add(tf.keras.layers.SimpleRNN(units=512, input_shape = (seq_len, 1), activation="tanh"))
    model.add(tf.keras.layers.Dense(len(vocab))) 
    model.compile(loss=loss, optimizer='adam')
    model.summary()

请注意,我使用 simpleRNN 而不是 GRU 并放弃了嵌入步骤。这两项更改都是为了简化模型,但这并不重要。

我的训练和输出数据如下:

>>> input_array_reshaped
array([[46., 47., 53., ..., 39., 58.,  1.],
       [ 8.,  0., 20., ..., 33., 31., 10.],
       [63.,  1., 44., ..., 58., 46., 43.],
       ...,
       [47., 41., 47., ...,  0., 21., 57.],
       [59., 58.,  1., ...,  1., 61., 43.],
       [52., 57., 43., ...,  1., 63., 53.]])
>>> input_array_reshaped.shape
(5000, 100)

>>> output_array_reshaped.shape
(5000, 1, 1)

>>> output_array_reshaped
array([[[40.]],

       [[ 0.]],

       [[56.]],

       ...,

       [[ 1.]],

       [[56.]],

       [[59.]]])

但是,如果我尝试预测少于 100 个字符的字符串,我会得到:

ValueError: Error when checking input: expected simple_rnn_1_input to have shape (100, 1) but got array with shape (50, 1)

如果需要,下面是我的预测功能。如果我将 required_training_length 更改为 100 以外的任何值,它就会崩溃。它需要“特别”长度为 100 的 time_steps。

谁能告诉我如何调整模型以使其更灵活,如示例中所示?我错过了什么微妙之处?

def generateText(starting_corpus, num_char_to_generate = 1000, required_training_length = 100):
    random_starting_int = random.sample(range(len(text)),1)[0]
    ending_position = random_starting_int+required_training_length

    starting_string = text[random_starting_int:ending_position]
    print("Starting string is: " + starting_string)
    numeric_starting_string = [char2idx[x] for x in starting_string]
    reshaped_numeric_string = np.reshape(numeric_starting_string, (1, len(numeric_starting_string), 1)).astype('float32')


    output_numeric_vector = []
    for i in range(num_char_to_generate): 
        if i%50 == 0:
            print("Processing character index: "+str(i))
        predicted_values = model.predict(reshaped_numeric_string)
        selected_predicted_value = tf.random.categorical(predicted_values, num_samples = 1)[0][0].numpy().astype('float32') #sample from the predicted values
        #temp = reshaped_numeric_string.copy()
        output_numeric_vector.append(selected_predicted_value)
        reshaped_numeric_string = np.append(reshaped_numeric_string[:,1:,:], np.reshape(selected_predicted_value, (1,1,1)), axis = 1)

    predicted_chars = [idx2char[x] for x in output_numeric_vector]
    final_text = ''.join(predicted_chars)
    return(final_text)

【问题讨论】:

【参考方案1】:

但是,看看实际的生成步骤,是否公平地说 它只使用最后一个字符“”?所以无论我们 使用“ROMEO:”还是只使用“”?很难测试,因为它是从 输出分布...

不,它考虑了所有字符。您可以轻松 通过使用固定的随机种子来验证:

from numpy.random import seed
from tensorflow.random import set_seed
seed(1)
set_seed(1)
print('======')
print(generate_text(m, 'ROMEO: '))
seed(1)
set_seed(1)
print('======')
print(generate_text(m, ' '))

与此相关,尚不清楚它会如何从如此短的时间预测 字符串作为原始训练序列要长得多。一世 了解如果我们在 100 个字符的历史上进行训练,我们会预测 第 101 次然后使用 2-101 预测 102 ......但它是如何开始的 只有 7 个字符?

它在内部循环运行序列。它需要第一个 字符并预测第二个。然后第二个预测 第三个等等。这样做时,它会更新其隐藏状态,以便 它的预测变得越来越好。最终它停滞不前 因为它不能记住任意长的序列。

【讨论】:

以上是关于TensorFlow RNN 文本生成示例教程的主要内容,如果未能解决你的问题,请参考以下文章

Tensorflow - 使用经过训练的 RNN 生成文本

『TensotFlow』LSTM古诗生成任务总结

怎么把这个RNN文本分类代码改成文本生成?

探索ChatGPT技术在文本生成机器翻译领域的简单应用

RNN 模型错误:“ValueError:此模型尚未构建。”

深度学习(08)_RNN-LSTM循环神经网络-03-Tensorflow进阶实现