Dropout 的应用

对于深层深度 RNN,在训练集上很容易过拟合。Dropout 是防止过拟合的常用技术。

可以简单的在 RNN 层之前或之后添加一层 Dropout 层,但如果需要在 RNN 层之间应用 Dropout 技术就需要DropoutWrapper

下面的代码中,每一层的 RNN 的输入前都应用了 Dropout,Dropout 的概率为 50%。

  1. keep_prob = 0.5
  2. cell = tf.contrib.rnn.BasicRNNCell(num_units=n_neurons)
  3. cell_drop = tf.contrib.rnn.DropoutWrapper(cell, input_keep_prob=keep_prob)
  4. multi_layer_cell = tf.contrib.rnn.MultiRNNCell([cell_drop]*n_layers)
  5. rnn_outputs, states = tf.nn.dynamic_rnn(multi_layer_cell, X, dtype=tf.float32)

同时也可以通过设置output_keep_prob来在输出应用 Dropout 技术。

然而在以上代码中存在的主要问题是,Dropout 不管是在训练还是测试时都起作用了,而我们想要的仅仅是在训练时应用 Dropout。

很不幸的是DropoutWrapper不支持is_training这样一个设置选项。因此必须自己写 Dropout 包装类,或者创建两个计算图,一个用来训练,一个用来测试。后则可通过如下面代码这样实现。

  1. import sys
  2. is_training = (sys.argv[-1] == "train")
  3. X = tf.placeholder(tf.float32, [None, n_steps, n_inputs])
  4. y = tf.placeholder(tf.float32, [None, n_steps, n_outputs])
  5. cell = tf.contrib.rnn.BasicRNNCell(num_units=n_neurons)
  6. if is_training:
  7. cell = tf.contrib.rnn.DropoutWrapper(cell, input_keep_prob=keep_prob)
  8. multi_layer_cell = tf.contrib.rnn.MultiRNNCell([cell]*n_layers)
  9. rnn_outpus, status = tf.nn.dynamic_rnn(multi_layer_cell, X, dtype=tf.float32)
  10. [...] # bulid the rest of the graph
  11. init = tf.global_variables_initializer()
  12. saver = tf.train.Saver()
  13. with tf.Session() as sess:
  14. if is_training:
  15. init.run()
  16. for iteration in range(n_iterations):
  17. [...] # train the model
  18. save_path = saver.save(sess, "/tmp/my_model.ckpt")
  19. else:
  20. saver.restore(sess, "/tmp/my_model.ckpt")
  21. [...] # use the model

通过以上的方法就能够训练各种 RNN 网络了。然而对于长序列的 RNN 训练还言之过早,事情会变得有一些困难。

那么我们来探讨一下究竟这是为什么和怎么应对呢?