【问题标题】:TensorFlow LSTM: Why does test accuracy become low, but not training one?TensorFlow LSTM:为什么测试准确率变低,但不能训练?
【发布时间】:2018-08-19 05:00:04
【问题描述】:

我尝试使用 TensorFlow 构建 LSTM 模型。 LSTM 的训练似乎运行良好,准确率超过 90%。困扰我的一个问题是“测试准确率”非常低。所以,我认为这是由于过度拟合?但是像增加训练batch或者减少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模型,所以,这是第一次,所以我知道我做错了什么,但不能指望它

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

    

【问题讨论】:

    标签: python tensorflow deep-learning lstm


    【解决方案1】:

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

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

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

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

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

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

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

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

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

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

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

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

    【讨论】:

    • 感谢您提供的信息丰富的建议,我认为您是对的。一些训练/测试数据的组合失败了,但一对可能会成功。所以,我知道考虑哪些数据集是合适的很重要。另一方面,我想知道我是否需要选择适合预测数据的训练数据?我觉得太难了!我在答题板上发布了详细信息。
    【解决方案2】:

    根据 dennlinger 的信息丰富的回答,我似乎得出了一个答案。最重要的是,我将训练数据分为六组(x_1、x_2...x_6 和 y_1、y_2、...y_6),每组的测试数据大小大致相同。我不确定将其用作您提到的第三个验证集,但请尝试应用它。更重要的是,我检查了每个集合不包含哪些类,例如y_1不包含类No.11、16、21、22和25

    train_y
    []
    y_1
    [11, 16, 21, 22, 25]
    y_2
    [11, 14, 16, 23]
    y_3
    [11, 19, 21, 23]
    y_4
    [14, 21, 23]
    y_5
    [16, 21, 22, 23]
    y_6
    [11, 21, 22, 23]
    test_y
    [11, 21, 22, 23]
    

    第一次检查(验证)是在 x_1/y_1 集上训练并计算测试数据的准确度。虽然我在每一步都停止训练,但性能并没有提高,结果几乎相同。

    Stop at step 1000
    Inter500,Minibatch loss= 1.976426, Traning Accracy=46.01227
    Test Accuracy is 7.317072868347168
    Stop at step1500
    Inter1000,Minibatch loss= 1.098709, Traning Accracy=66.25767
    Test Accuracy is 4.2682929039001465
    Stop at step 2000
    Inter1500,Minibatch loss= 0.906059, Traning Accracy=74.23312
    Test Accuracy is 6.097560882568359
    Stop at step 2500
    Inter2000,Minibatch loss= 0.946361, Traning Accracy=76.07362
    Test Accuracy is 6.707317352294922
    

    接下来,我尝试检查了几种组合的性能,结果如下

    Train on x_6/y_6 sets and test on test data
    Inter2500,Minibatch loss= 0.752621, Traning Accracy=79.77941
    Test Accuracy is 78.65853881835938
    
    Train on x_6/y_6 sets and test on x_5/y_5 sets
    Inter2500,Minibatch loss= 0.772954, Traning Accracy=78.67647
    Test Accuracy is 3.658536434173584
    
    Train on training data and test on x_4/y_4 sets
    Inter3000,Minibatch loss= 1.980538, Traning Accracy=41.01731
    Test Accuracy is 37.42331314086914
    

    有趣的是,在 x_6/y_6 集上训练并在测试数据上进行测试的组合可以比之前的组合表现更好,测试的准确率提高到 78% 左右。这是,我假设,由于相同的类,这意味着 y_6 包含所有类的测试数据(见上文),以及相同的大小。所以,这个节目我必须考虑哪些数据集是合适的,并尝试在各种条件下验证 LSTM 模型,这非常重要。

    另一方面,CHG 减少神经元(80 到 10 或 5 个)和批次,根本没有提高性能。

    【讨论】:

    • 非常感谢您为此付出的跟进和努力!很高兴听到你的结果!为了完整起见,如果您对某个答案(甚至是您自己的答案)有些满意,请考虑通过单击投票旁边的绿色对勾来接受它,以便其他人可以立即看到结果。
    【解决方案3】:

    如果训练准确率继续上升,但测试准确率下降,那么你就是过拟合了。尝试运行更少的 epoch 或使用更低的学习率。

    【讨论】:

    • 这通常不是真的。它很可能过拟合,但也可能是您的测试/训练数据的错误采样(有关详细信息,请参阅我即将发布的答案)
    猜你喜欢
    • 2018-02-08
    • 1970-01-01
    • 2020-10-17
    • 2018-09-18
    • 1970-01-01
    • 2018-12-20
    • 2019-05-12
    • 2020-04-20
    • 2017-10-05
    相关资源
    最近更新 更多