我试图弄清楚如何减少我的 LSTM 中的错误。这是一个奇怪的用例,因为我们没有进行分类,而是输入短列表(最多 32 个元素长)并输出一系列实数,范围从 -1 到 1 - 表示角度。本质上,我们想从氨基酸输入中重建短蛋白质环。
过去,我们的数据集中有冗余数据,因此报告的准确性是不正确的。由于删除了冗余数据,我们的验证准确性变得更差,这表明我们的网络已经学会了记住最常见的例子。
我们的数据集有 10,000 个项目,在训练、验证和测试之间划分为 70/20/10。我们使用双向 LSTM,如下所示:
x = tf.cast(tf_train_dataset, dtype=tf.float32)
output_size = FLAGS.max_cdr_length * 4
dmask = tf.placeholder(tf.float32, [None, output_size], name="dmask")
keep_prob = tf.placeholder(tf.float32, name="keepprob")
sizes = [FLAGS.lstm_size,int(math.floor(FLAGS.lstm_size/2)),int(math.floor(FLAGS.lstm_size/ 4))]
single_rnn_cell_fw = tf.contrib.rnn.MultiRNNCell( [lstm_cell(sizes[i], keep_prob, "cell_fw" + str(i)) for i in range(len(sizes))])
single_rnn_cell_bw = tf.contrib.rnn.MultiRNNCell( [lstm_cell(sizes[i], keep_prob, "cell_bw" + str(i)) for i in range(len(sizes))])
length = create_length(x)
initial_state = single_rnn_cell_fw.zero_state(FLAGS.batch_size, dtype=tf.float32)
initial_state = single_rnn_cell_bw.zero_state(FLAGS.batch_size, dtype=tf.float32)
outputs, states = tf.nn.bidirectional_dynamic_rnn(cell_fw=single_rnn_cell_fw, cell_bw=single_rnn_cell_bw, inputs=x, dtype=tf.float32, sequence_length = length)
output_fw, output_bw = outputs
states_fw, states_bw = states
output_fw = last_relevant(FLAGS, output_fw, length, "last_fw")
output_bw = last_relevant(FLAGS, output_bw, length, "last_bw")
output = tf.concat((output_fw, output_bw), axis=1, name='bidirectional_concat_outputs')
test = tf.placeholder(tf.float32, [None, output_size], name="train_test")
W_o = weight_variable([sizes[-1]*2, output_size], "weight_output")
b_o = bias_variable([output_size],"bias_output")
y_conv = tf.tanh( ( tf.matmul(output, W_o)) * dmask, name="output")
本质上,我们使用 3 层 LSTM,每层有 256、128 和 64 个单元。我们采取向前和向后传递的最后一步并将它们连接在一起。这些馈入最终的全连接层,以我们需要的方式呈现数据。我们使用掩码将这些步骤设置为不需要归零。
我们的成本函数再次使用掩码,并取平方差的平均值。我们根据测试数据构建掩码。要忽略的值设置为 -3.0。
def cost(goutput, gtest, gweights, FLAGS):
mask = tf.sign(tf.add(gtest,3.0))
basic_error = tf.square(gtest-goutput) * mask
basic_error = tf.reduce_sum(basic_error)
basic_error /= tf.reduce_sum(mask)
return basic_error
为了训练网络,我使用了各种优化器。使用 AdamOptimizer 获得了最低分数。其他的,如 Adagrad、Adadelta、RMSProp 往往会在 0.3/0.4 误差附近保持平坦,这并不是特别大。
我们的学习率为 0.004,批量大小为 200。我们使用 0.5 概率的 dropout 层。
我尝试过添加更多层、改变学习率、批量大小,甚至是数据的表示。我尝试过批量正则化、L1 和 L2 权重正则化(尽管可能不正确),我什至考虑改用 convnet 方法。
似乎没有任何区别。似乎起作用的是更改优化器。随着改进,Adam 似乎更嘈杂,但它确实比其他优化器更接近。
我们需要降低到更接近 0.05 或 0.01 的值。有时训练误差会达到 0.09,但验证不会随之而来。到目前为止,我已经运行了这个网络大约 500 个 epoch(大约 8 小时),它倾向于解决大约 0.2 个验证错误。
我不太确定下一步该尝试什么。衰减的学习率可能会有所帮助,但我怀疑我需要做一些更基本的事情。它可能像代码中的错误一样简单 - 我需要仔细检查掩码,