如何在GPU上进行训练时处理非确定性?

Spa*_*key 11 python machine-learning tensorflow

在调整超参数以使我的模型更好地执行时,我注意到每次运行代码时我得到的分数(以及因此创建的模型)都不同,尽管为随机操作修复了所有种子.如果我在CPU上运行,则不会发生此问题.

我用Google搜索并发现使用GPU进行训练时这是一个常见问题.这是一个非常好/详细的示例,其中包含用于验证该问题是否存在的短代码片段.

他们将非确定性指向"tf.reduce_sum"函数.但是,对我来说情况并非如此.可能是因为我使用的是不同的硬件(1080 TI)或不同版本的CUDA库或Tensorflow.看起来CUDA库的许多不同部分都是非确定性的,并且似乎不容易弄清楚哪个部分以及如何摆脱它.此外,这必须是设计的,因此非确定性的交换可能会有足够的效率提升.

所以,我的问题是:

由于GPU在培训NN方面很受欢迎,因此该领域的人们必须有办法处理非确定性问题,因为我无法看到你如何能够可靠地调整超参数.使用GPU时处理非确定性的标准方法是什么?

P-G*_*-Gn 12

TL; DR

  • 先验确定性操作的非确定性来自concurent(多线程)实现.
  • 尽管如此,tensorflow目前还不能保证其所有运营的确定性.在互联网上快速搜索后,似乎情况与其他主要工具包类似.
  • 在培训期间,除非您正在调试问题,否则可以在运行之间产生波动.不确定性是培训的本质,在比较结果时,测量它并将其考虑在内是明智的 - 即使工具包最终在培训中达到完美的决定论.

那,但更长

当您将神经网络操作视为数学运算时,您会发现一切都是确定性的.卷积,激活,交叉熵 - 这里的一切都是数学方程式,应该是确定性的.即使是伪随机操作,例如改组,辍学,噪音等,也完全由种子决定.

另一方面,当您从计算实现中看到这些操作时,您会将它们视为大规模并行化计算,除非您非常小心,否则它们可能是随机性的来源.

问题的核心在于,当您在多个并行线程上运行操作时,通常不知道哪个线程将首先结束.当线程对自己的数据进行操作时并不重要,因此,例如,将激活函数应用于张量应该是确定性的.但是当这些线程需要同步时,例如计算总和时,结果可能取决于求和的顺序,进而取决于首先结束的线程的顺序.

从那里,你可以广泛地说两个选择:

  • 保持与更简单的实现相关的非确定性.

  • 在设计并行算法时要格外小心,以减少或消除计算中的非确定性.增加的约束通常会导致算法速度变慢

哪条路线需要CuDNN?好吧,主要是确定性的.在最近的版本中,确定性操作是常态而非例外.但它曾经提供许多非确定性操作,更重要的是,它曾经不提供某些操作,如减少,人们需要在CUDA中实现自己,并对可靠性有不同程度的考虑.

像theano这样的一些图书馆在这些话题上提前做得更早,因为早期暴露出deterministic用户可以打开或关闭的标志 - 但正如你从其描述中看到的那样,它远远没有提供任何保证.

如果more,有时我们会选择一些更确定但更慢的实现.特别是在GPU上,我们将避免使用AtomicAdd.有时我们仍然会使用非确定性实现,例如,当我们没有确定性的GPU实现时.另请参阅dnn.conv.algo*标志以涵盖更多案例.

在张量流中,对确定性的需求的实现已经相当晚了,但它的发展速度正在减缓 - 这也得益于CuDNN在这方面的进展.很长一段时间,减少是不确定的,但现在它们似乎是确定性的.CuDNN在版本6.0中引入确定性约简的事实当然可能有所帮助.

目前看来,对于确定性的张量流动的主要障碍是卷积的向后传递.它确实是CuDNN提出的标记为非确定性算法的少数操作之一CUDNN_CONVOLUTION_BWD_FILTER_ALGO_0.该算法仍然在张量流中的后向滤波器的可能选择列表中.并且由于过滤器的选择似乎是基于性能的,因此如果它更有效,它确实可以被选中.(我对tensorflow的C++代码不是那么熟悉,所以请耐心等待.)

这很重要吗?

如果您正在调试问题,确定性并不重要:它是强制性的.您需要重现导致问题的步骤.这是目前像tensorflow这样的工具包的真正问题.为了缓解这个问题,您唯一的选择是调试实时,在正确的位置添加检查和断点 - 不是很好.

部署是事物的另一个方面,通常希望具有确定性行为,部分用于人类接受.虽然没有人会合理地期望医疗诊断算法永远不会失败,但计算机可能会根据运行情况给同一患者不同的诊断,这是很尴尬的.(虽然医生自己也不能免疫这种变异).

这些原因是修正神经网络中非确定性的正当动机.

对于所有其他方面,我会说,如果不接受,我们需要接受神经网络训练的非确定性.出于所有目的,培训是随机的.我们使用随机梯度下降,随机数据,使用随机初始化和丢失 - 更重要的是,训练数据本身是一个随机的数据样本.从这个角度来看,计算机只能用种子生成伪随机数这一事实就是一件神器.当你训练时,你的损失是一个值,由于这种随机性,也带有置信区间.比较这些值以优化超参数而忽略那些置信区间并没有多大意义 - 因此,在我看来,花费太多精力修复非确定性以及许多其他情况是徒劳的.


Tim*_*lin 8

从 开始TF 2.9 (TF >= 2.9),如果您希望 TF 模型确定性地运行,则需要在程序开头添加以下行。

import tensorflow as tf

tf.keras.utils.set_random_seed(1)
tf.config.experimental.enable_op_determinism()
Run Code Online (Sandbox Code Playgroud)

重要提示:第​​一行设置以下各项的随机种子:Python、NumPy 和 TensorFlow。第二行使每个 TensorFlow 操作具有确定性。