首页 > 解决方案 > TensorFlow LSTM:为什么测试准确率变低,但不能训练?

问题描述

我曾尝试使用 TensorFlow 构建 LSTM 模型。LSTM 的训练似乎运行良好,准确率超过 90%。困扰我的一个问题是“测试准确率”非常低。所以,我认为这是由于过度拟合?但是诸如增加训练批次或减少 element_size(从 10 到 5)之类的尝试都是浪费我的努力,应用“dropout”也没有解决它。我想要一些关于如何改进我的代码以获得高测试准确性的指导。以下是我的数据/参数的摘要

Input variable is economic time series data standardized
Output variable is categorical features (labels) converted by one-hot encoding

Sequence_length : 20
Element_size: 5
Hidden_layer : 80
Categories (labels): 30 
Training batch : 924
Test batch : 164
Learn rate is 0.0005 (Is it low?)

这是我构建的代码

#Split x_buch and y_batch
train_x,test_x=np.split(x_batch,[int(batch_size*0.85)])
train_y,test_y=np.split(y_batch,[int(batch_size*0.85)])
print('train_x shape: {0} and test_x shape: {1}'.format(train_x.shape,test_x.shape))
print('train_y shape: {0} and test_y shape: {1}'.format(train_y.shape,test_y.shape))

#Create placehold for inpt, labels
inputs=tf.placeholder(tf.float32,shape=[None,step_time,element_size],name='inputs')
y=tf.placeholder(tf.float32,shape=[None,label_num],name='y')

#Tensorflow  built-in functinon
with tf.variable_scope('lstm'):
    lstm_cell=tf.contrib.rnn.LSTMCell(hidden_layer,forget_bias=1.0)
    cell_drop=tf.contrib.rnn.DropoutWrapper(lstm_cell, output_keep_prob=0.7)
    outputs,states=tf.nn.dynamic_rnn(cell_drop,inputs,dtype=tf.float32) 
    print('outputs shape: {0}'.format(outputs.shape))

W1={'linear_layer':tf.Variable(tf.truncated_normal([hidden_layer,label_num],mean=0,stddev=.01))}
b1={'linear_layer':tf.Variable(tf.truncated_normal([label_num],mean=0,stddev=.01))}

#Extract the last relevant output and use in a linear layer
final_output=tf.matmul(outputs[:,-1,:],W1['linear_layer'])+b1['linear_layer']

with tf.name_scope('cross_entropy'):
    softmax=tf.nn.softmax_cross_entropy_with_logits(logits=final_output,labels=y)
    cross_entropy=tf.reduce_mean(softmax)

with tf.name_scope('train'):
    train_step=tf.train.AdamOptimizer(learn_rate,0.9).minimize(cross_entropy)

with tf.name_scope('accracy'):
    correct_prediction=tf.equal(tf.argmax(y,1),tf.argmax(final_output,1))
    accuracy=(tf.reduce_mean(tf.cast(correct_prediction,tf.float32)))*100

#Training
with tf.Session()as sess:
    sess.run(tf.global_variables_initializer())    
    for step in range(5000):
        sess.run(train_step,feed_dict={inputs:train_x,y:train_y})
        if step % 500 == 0:
            acc=sess.run(accuracy,feed_dict={inputs:train_x,y:train_y})
            loss=sess.run(cross_entropy,feed_dict={inputs:train_x,y:train_y})
            print('Inter'+str(step)+',Minibatch loss= '+'{:.6f}'.format(loss)+', Traning Accracy='+'{:.5f}'.format(acc))

# Test
    test_acc=sess.run(accuracy,feed_dict={inputs:test_x,y:test_y})
    print("Test Accuracy is {0}".format(test_acc))

结果是

Input Shape: (21760, 5)
Output Shape: (21760, 30)
x_batch shape: (1088, 20, 5)
y_batch shape: (1088, 30)
train_x shape: (924, 20, 5) and test_x shape: (164, 20, 5)
train_y shape: (924, 30) and test_y shape: (164, 30)
outputs shape: (?, 20, 80)
Inter0,Minibatch loss= 3.398923, Traning Accracy=5.30303
Inter500,Minibatch loss= 2.027734, Traning Accracy=38.09524
Inter1000,Minibatch loss= 1.340760, Traning Accracy=61.79654
Inter1500,Minibatch loss= 1.010518, Traning Accracy=72.83550
Inter2000,Minibatch loss= 0.743997, Traning Accracy=79.76190
Inter2500,Minibatch loss= 0.687736, Traning Accracy=79.76190
Inter3000,Minibatch loss= 0.475408, Traning Accracy=85.17316
Inter3500,Minibatch loss= 0.430477, Traning Accracy=87.22944
Inter4000,Minibatch loss= 0.359262, Traning Accracy=89.17749
Inter4500,Minibatch loss= 0.274463, Traning Accracy=90.69264
Test Accuracy is 4.878048419952393

我从未使用过 TensorFlow 和 LSTM 模型,所以,这是第一次,因此我知道我做错了什么,但不能指望它

那么,有人可以提供帮助吗?

    

标签: pythontensorflowdeep-learninglstm

解决方案


在我详细介绍之前:
我假设您batch_size在谈论element_size? 如果我的假设有误,请在这里纠正我。

正如另一个答案所提到的,一个潜在的原因可能是过度拟合,即您正在尝试“对训练数据过于努力”。解决此问题的一种通用方法是使用保留的验证样本跟踪看不见的训练数据的性能。即,您有第三个验证集(通常与测试数据大小相同),而不是拆分两种方式(训练/测试),并在训练期间不时检查您的模型在此验证数据上的执行情况。

一个常见的观察是以下曲线: 在此处输入图像描述 如您所见,该模型在训练数据上不断改进,但它确实如此,因为它牺牲了泛化到看不见的数据的能力

通常,您会尝试在验证集上的误差最小的点停止训练——即使这不能保证您的训练数据的最佳结果。我们希望它在(完全未知的)之前的测试集上表现最好。

作为一个快速的旁注,如果您在 TensorFlow 中执行此操作(我不是 100% 熟悉):通常,您必须将模型从训练“切换”到评估以获得验证集的实际结果(而不是不小心也对它们进行了训练),但是您可以在网上找到很多实际的实现。

此外,如果神经元过多,过度拟合可能会成为问题!在您的情况下,您只有 800 个示例,但已经有 80 个神经元,这在 IMO 中的比例太高了。您可以尝试使用更少的神经元,看看这是否会提高您的测试集的准确性,即使这也可能会降低训练数据的准确性。
最后,您希望对您的问题有一个紧凑的描述,而不是一个“学习”识别每个训练实例的网络。

此外,如果您确实使用小批量,您可以尝试进一步减少数量。我真的很喜欢Yann LeCun 的这条推文,所以我也会在这里发布这条推文 ;-)开个
玩笑,小批量的训练也可以带来更好的泛化效果,这听起来很荒谬。大批量通常只有在您拥有大量训练集或在 GPU 上进行训练时才真正有用(从那时起,从 GPU 到内存的复制非常昂贵,而小批量减少了此类操作的数量),或者如果你需要很长时间才能达到收敛。

由于您使用的是 LSTM 架构(由于其顺序性,它在 CPU 和 GPU 上具有相似的性能,因为没有太多需要并行化),大批量可能不会提高您的(计算)性能,但有较小的批次可能会提高准确性性能。

最后,这就是为什么我最初对另一个答案发表评论的原因,我们可能完全不理解这里的解释,毕竟这可能是一个完全不同的原因。

许多人往往忘记的是对您的测试/训练拆分进行一些初步的探索性分析。如果您的测试集中只有一个类的代表,但训练数据中几乎没有,那么结果可能不会很好。同样,如果您只训练 30 个班级中的 29 个,那么网络将很难识别第 30 个班级的任何样本。

为避免这种情况,请确保您有一个稍微均匀的拆分(即在测试和训练集中为每个类抽取一定数量的类),并检查这些类是否有点均匀分布

这样做可能会在以后为您节省很多痛苦,并且通常也有助于提高全新训练数据的性能。永远记住——深度学习并不能神奇地解决你在预测分析中遇到的所有问题,它只是为你提供了一个非常强大的工具来解决特定的子问题。


推荐阅读