TensorFlow dynamic_rnn 回归输入

TensorFlow dynamic_rnn input for regression

我在尝试将现有的张量流序列转换为序列分类器到回归量时遇到困难。

目前我一直在处理 tf.nn.dynamic_rnn() 的输入。根据文档和其他答案,输入应该是 (batch_size, sequence_length, input_size) 的形状。但是我的输入数据只有两个维度:(sequence_length, batch_size).

原始解决方案使用 tf.nn.embedding_lookup() 作为将输入馈送到 dynamic_rnn() 之前的中间步骤。如果我理解正确,我相信我不需要这一步,因为我正在处理回归问题,而不是分类问题。

我需要 embedding_lookup 这一步吗?如果是这样,为什么?如果没有,我怎样才能将我的 encoder_inputs 直接放入 dynamic_rnn()

下面是一般想法的最小化工作示例:

import numpy as np
import tensorflow as tf

tf.reset_default_graph()
sess = tf.InteractiveSession()

PAD = 0
EOS = 1
VOCAB_SIZE = 10 # Don't think I should need this for regression?
input_embedding_size = 20

encoder_hidden_units = 20
decoder_hidden_units = encoder_hidden_units

LENGTH_MIN = 3
LENGTH_MAX = 8
VOCAB_LOWER = 2
VOCAB_UPPER = VOCAB_SIZE
BATCH_SIZE = 10

def get_random_sequences():
    sequences = []
    for j in range(BATCH_SIZE):
        random_numbers = np.random.randint(3, 10, size=8)
        sequences.append(random_numbers)
    sequences = np.asarray(sequences).T
    return(sequences)

def next_feed():
    batch = get_random_sequences()

    encoder_inputs_ = batch
    eos = np.ones(BATCH_SIZE)
    decoder_targets_ = np.hstack((batch.T, np.atleast_2d(eos).T)).T
    decoder_inputs_ = np.hstack((np.atleast_2d(eos).T, batch.T)).T

    #print(encoder_inputs_)
    #print(decoder_inputs_)

    return {
        encoder_inputs: encoder_inputs_,
        decoder_inputs: decoder_inputs_,
        decoder_targets: decoder_targets_,
    }

### "MAIN"

# Placeholders
encoder_inputs = tf.placeholder(shape=(LENGTH_MAX, BATCH_SIZE), dtype=tf.int32, name='encoder_inputs')
decoder_targets = tf.placeholder(shape=(LENGTH_MAX + 1, BATCH_SIZE), dtype=tf.int32, name='decoder_targets')
decoder_inputs = tf.placeholder(shape=(LENGTH_MAX + 1, BATCH_SIZE), dtype=tf.int32, name='decoder_inputs')

# Don't think I should need this for regression problems
embeddings = tf.Variable(tf.random_uniform([VOCAB_SIZE, input_embedding_size], -1.0, 1.0), dtype=tf.float32)
encoder_inputs_embedded = tf.nn.embedding_lookup(embeddings, encoder_inputs)
decoder_inputs_embedded = tf.nn.embedding_lookup(embeddings, decoder_inputs)

# Encoder RNN
encoder_cell = tf.contrib.rnn.LSTMCell(encoder_hidden_units)
encoder_outputs, encoder_final_state = tf.nn.dynamic_rnn(
    encoder_cell, encoder_inputs_embedded, # Throws 'ValueError: Shape (8, 10) must have rank at least 3' if encoder_inputs is used
    dtype=tf.float32, time_major=True,
)

# Decoder RNN
decoder_cell = tf.contrib.rnn.LSTMCell(decoder_hidden_units)
decoder_outputs, decoder_final_state = tf.nn.dynamic_rnn(
    decoder_cell, decoder_inputs_embedded, 
    initial_state=encoder_final_state,
    dtype=tf.float32, time_major=True, scope="plain_decoder",
)
decoder_logits = tf.contrib.layers.linear(decoder_outputs, VOCAB_SIZE)
decoder_prediction = tf.argmax(decoder_logits, 2)

# Loss function
loss = tf.reduce_mean(tf.squared_difference(decoder_logits, tf.one_hot(decoder_targets, depth=VOCAB_SIZE, dtype=tf.float32)))
train_op = tf.train.AdamOptimizer().minimize(loss)


sess.run(tf.global_variables_initializer())

max_batches = 5000
batches_in_epoch = 500

print('Starting train')
try:
    for batch in range(max_batches):
        feed = next_feed()
        _, l = sess.run([train_op, loss], feed)

        if batch == 0 or batch % batches_in_epoch == 0:
            print('batch {}'.format(batch))
            print('  minibatch loss: {}'.format(sess.run(loss, feed)))
            predict_ = sess.run(decoder_prediction, feed)
            for i, (inp, pred) in enumerate(zip(feed[encoder_inputs].T, predict_.T)):
                print('  sample {}:'.format(i + 1))
                print('    input     > {}'.format(inp))
                print('    predicted > {}'.format(pred))
                if i >= 2:
                    break
            print()
except KeyboardInterrupt:
    print('training interrupted')

我在 Whosebug 上阅读过类似的问题,但发现自己仍然对如何解决这个问题感到困惑。

编辑: 我想我应该澄清一下,上面的代码运行良好,但是真正需要的输出应该模拟噪声信号(例如文本到语音),这就是为什么我认为我需要连续的输出值而不是单词或字母。

如果你想做连续的,为什么你不能把你的输入占位符重塑成 [BATCH, TIME_STEPS, 1] 的形状,然后通过 tf.expand_dims(input, 2) 将那个额外的维度添加到你的输入中。这样,您的输入将匹配 dynamic_rnn 期望的尺寸(实际上在您的情况下,因为您正在做 time_major=True 您的输入应该是形状 [TIME_STEPS, BATCH, 1])

我很想知道您随后如何处理输出维度从像元大小到 1 的切换。现在您有这一行:

decoder_logits = tf.contrib.layers.linear(decoder_outputs, VOCAB_SIZE)

但是既然你已经不做分类了,那么VOCAB_SIZE就是1?几天前我在这里问了一个类似的问题,但没有得到任何答复。我是这样做的(使用 1),但不确定它是否合适(在实践中似乎有点工作,但并不完美)。