我在 Tensorflow 中使用带有 BasicLSTMCells 的循环神经网络。基本来说,我有一个词 ID 的输入序列,我将每个 ID 转换为词嵌入,然后一次通过 RNN 传递词嵌入,并在读取整个序列后对单个词进行预测。我的嵌入矩阵的维度为 V x H,其中 V 是我的词汇表大小,H 是我的 RNN 中的隐藏单元数。为了预测下一个词,我将隐藏向量乘以大小为 H x V 的权重矩阵,然后计算 softmax。使用我描述的设置,一切似乎都按预期工作。我能够在一些示例上进行训练并做出合理的预测。然而,我注意到如果我尝试使用嵌入矩阵的转置,这将是一个大小为 H x V 的矩阵,而不是单独的 softmax 层矩阵,Tensorflow 会引发一个值错误,声称它未指定的某些东西的维度没有相同的秩。我已经验证了我的嵌入矩阵(嗯,它的转置)的维度与我创建的单独的 softmax 矩阵的维度相同。仅更改一行代码,从使用我的嵌入矩阵改为使用单独的 softmax 权重矩阵就会导致错误。我创建了一个相对较小的程序来演示我想做的事情,并展示是什么导致了错误。当我尝试使用只有单个隐藏层网络时,我无法在较小的网络上使错误发生。
import sysimport timeimport tensorflow as tffrom tensorflow.models.rnn import rnnfrom tensorflow.models.rnn import rnn_cellfrom tensorflow.models.rnn.rnn_cell import BasicLSTMCellimport numpy as npINPUT_LENGTH = 17BATCH_SIZE = 20VOCAB_SIZE = 11NUM_EPOCHS = 1000HIDDEN_UNITS = 100class Model(object): def __init__(self, is_training): initializer = tf.random_uniform_initializer(-1.0, 1.0) self._target = tf.placeholder(tf.float32, [BATCH_SIZE, VOCAB_SIZE]) self._input_data=tf.placeholder(tf.int32,[BATCH_SIZE, INPUT_LENGTH]) self.embedding = tf.get_variable("embedding", [VOCAB_SIZE, HIDDEN_UNITS], initializer=initializer) self.inputs = tf.split(1, INPUT_LENGTH, tf.nn.embedding_lookup(self.embedding, self._input_data)) self.inputs2 = [tf.squeeze(input_, [1]) for input_ in self.inputs] cell = rnn_cell.BasicLSTMCell(num_units=HIDDEN_UNITS) initial_state = cell.zero_state(BATCH_SIZE, tf.float32) outputs, states = rnn.rnn(cell, self.inputs2, initial_state=initial_state) self._outputs = outputs[-1] self.soft_w = tf.get_variable("softmax_w", [HIDDEN_UNITS, VOCAB_SIZE], initializer=initializer) prod = tf.matmul(self._outputs, self.soft_w)#取消注释以下行会导致错误# prod = tf.matmul(self._outputs, self.embedding, False, True) soft_b = tf.get_variable("softmax_b", [VOCAB_SIZE], initializer=initializer) self._logits = tf.nn.bias_add(prod,soft_b) self._loss = tf.nn.softmax_cross_entropy_with_logits(self._logits, self._target) if not is_training: return learning_rate = .010001 optimizer = tf.train.GradientDescentOptimizer(learning_rate) self._train_op = optimizer.minimize(self._loss) def train(self, sess, inputs, targets): t = np.zeros((BATCH_SIZE, VOCAB_SIZE)) for i, target in enumerate(targets): t[i,target] = 1.0 inputs = np.array(inputs) inputs = inputs.reshape(BATCH_SIZE,INPUT_LENGTH) fd = {self._target:t, self._input_data:inputs} o = sess.run([self._train_op, self._loss, self._outputs, self.embedding, self.soft_w], feed_dict = fd) print o[2].shape print o[3].shape print o[4].shape sys.exit() return np.mean(o[1])#这只是生成虚拟数据def read_data_rows(count): ret = [] for i in range(count): inputs = [4] * INPUT_LENGTH output = 1 ret.append((inputs, output)) return retdef main(): start = time.time() tf.set_random_seed(1) print "creating model",time.time()-start m = Model(is_training=True) with tf.Session() as sess: print "initializing variables", time.time()-start tf.initialize_all_variables().run() for epoch in range(NUM_EPOCHS): train_rows = read_data_rows(100) for row_num in range(0, len(train_rows), BATCH_SIZE): qs = [] ans = [] batch = train_rows[row_num:row_num+BATCH_SIZE] for b in batch: qs.append(b[0]) ans.append(b[1]) m.train(sess, qs, ans)if __name__ == "__main__": main()
我看到的错误是 ValueError:当取消注释我上面提到的行时,Shapes TensorShape([Dimension(100)]) 和 TensorShape([Dimension(17), Dimension(100)]) 必须具有相同的秩。导致我看到的错误的原因是什么?为什么嵌入矩阵不像矩阵 self.soft_w 那样被处理?
回答:
TensorFlow 的 0.6.0(及更早版本)发布中,在 tf.nn.embedding_lookup()
和 tf.gather()
的梯度实现中存在一个错误,当索引参数(在您的代码中为 self._input_data
)具有多个维度时。
升级到最新的源代码发布应该可以修复此错误。否则,这个提交包含了对 array_grad.py
的相关更改,这将使您的程序能够工作。