Keras 中的 CuDNNLSTM 和 LSTM 有啥区别?

Posted

技术标签:

【中文标题】Keras 中的 CuDNNLSTM 和 LSTM 有啥区别?【英文标题】:What is the difference between CuDNNLSTM and LSTM in Keras?Keras 中的 CuDNNLSTM 和 LSTM 有什么区别? 【发布时间】:2018-10-03 20:43:59 【问题描述】:

在高级深度学习库Keras中,有多种循环层;这些包括LSTM(长期短期记忆)和CuDNNLSTM。根据Keras documentation,CuDNNLSTM 是:

由 CuDNN 支持的快速 LSTM 实现。 只能在 GPU 上运行,带有 TensorFlow 后端。

我相信 Keras 会尽可能自动使用 GPU。根据TensorFlow build instructions,要拥有一个正常工作的 TensorFlow GPU 后端,您将需要 CuDNN:

您的系统上必须安装以下 NVIDIA 软件:

NVIDIA 的 Cuda 工具包 (>= 7.0)。我们推荐版本 9.0。有关详细信息,请参阅 NVIDIA 的文档。确保将相关的 Cuda 路径名附加到 LD_LIBRARY_PATH 环境变量中,如 NVIDIA 文档中所述。 与 NVIDIA 的 Cuda Toolkit 关联的 NVIDIA 驱动程序。 cuDNN (>= v3)。我们推荐版本 6.0。有关详细信息,请参阅 NVIDIA 的文档,尤其是关于将适当的路径名附加到 LD_LIBRARY_PATH 环境变量的说明。

因此,CuDNNLSTM 与使用 TensorFlow GPU 后端的普通 LSTM 有何不同?当找到可用的 TensorFlow GPU 后端时,CuDNNLSTM 是否会被自动选择并替换正常的 LSTM

【问题讨论】:

我猜他们是一样的?它可能只在没有 GPU 的情况下运行时有所不同。 LSTM 的选择 如果要将模型部署到生产中,CuDNNLSTM 很重要。例如,到目前为止,Google Cloud Platform 允许您在其“AI Platform”中仅使用 CPU 机器。因此,如果您使用 CuDNNLSTM 训练模型,您将无法部署它。 【参考方案1】:

你为什么不自己试试看呢? 在我的例子中,使用LSTM 训练一个模型需要 10 分 30 秒。 只需将电话从 LSTM() 切换到 CuDNNLSTM() 不到一分钟。

我还注意到切换到CuDNNLSTM() 也大大加快了model.evaluate()model.predict()

【讨论】:

为什么我才发现这个,太神奇了!过去在大型数据集上评估模型需要 3 小时,现在只需 20 分钟左右。 CuDNNLSTM 更快(它使用 GPU 支持)但它的选项比 LSTM 少(例如 dropout) 更多信息请参见此主题:reddit.com/r/learnmachinelearning/comments/9jv0gx/… 只是重新执行所说的话。运行具有 10 个 LSTM 层、3 个密集层和每层 200 个神经元的模型,使用硬 sigmoid 激活函数强制使用通用 GPU - 每个 epoch 超过 40 分钟。将其更改回普通的 sigmoid 允许 cuDNN - 每个 epoch 54 秒。有很大的不同。 我刚刚在 Python 3.9.9 和 Tensorflow 2.7.0 上尝试过。我用 tf.compat.v1.keras.layers.CuDNNLSTM(128, return_sequences=True) 替换了 tf.keras.layers.LSTM(128, return_sequences=True),我得到了超过 3 倍的速度提升,从每步 110ms 到38 毫秒。在 RTX 3080Ti 上运行,低端显卡可能会看到更大的性能提升。因此,官方文档中关于 tensorflow 2.x 已经使用 CuDNN 内核的说法是不正确的,至少它对我不起作用。【参考方案2】:

GPU 适合大规模并行计算,大多数线性代数运算可以并行化以提高性能,矩阵乘法和梯度下降等向量运算可以应用于在 GPU 支持下并行执行的大型矩阵。 CUDA - Compute Unified Device Architecture 提供了一个接口,允许向量运算利用 GPU 并行性。 CuDNN 使用 CUDA 在 GPU 上实现用于大型矩阵运算的内核。

这里,CuDNNLSTM 是为 CUDA 并行处理而设计的,如果没有 GPU,则无法运行。但是 LSTM 是为普通 CPU 设计的。更快的执行时间是因为并行性。

【讨论】:

【参考方案3】:

TL;DR;区别在于模型训练时间提高了 15 倍!

Setup Steps

Dependencies

性能基准测试:标准测试机器的比较。在 612235 个样本上训练 1 次迭代。

keras.layers.LSTM Intel i5-4690 CPU only: 612235/612235 [==============================] - 3755s 6ms/step - loss: 2.7339 - acc: 0.5067 - val_loss: 2.1149 - val_acc: 0.6175

GTX:950 & Intel i5-4690: 612235/612235 [==============================] - 1417s 2ms/step - loss: 2.7007 - acc: 0.5137 - val_loss: 2.0983 - val_acc: 0.6199

GPU 增益为 2.5 倍。

GTX:970 & Intel i5-4690: 612235/612235 [==============================] - 1322s 2ms/step - loss: 1.9214 - acc: 0.6442 - val_loss: 1.8808 - val_acc: 0.6461

强大的 GPU 带来的收益可忽略不计。

RTX 2070 & Intel i7-9700K: 612235/612235 [==============================] - 1012s 2ms/step - loss: 2.7268 - acc: 0.5111 - val_loss: 2.1162 - val_acc: 0.6234

即使有很棒的硬件升级,收益也很小!!!

keras.layers.CuDNNLSTM RTX 2070 & Intel i7-9700K: 612235/612235 [==============================] - 69s 112us/step - loss: 1.9139 - acc: 0.6437 - val_loss: 1.8668 - val_acc: 0.6469

54 倍的 CPU 增益! 比传统(非 Cuda)LSTM 实现提高 15 倍!

【讨论】:

似乎只需要显示最后两个案例,因为它们是一个公平的测试 - 相同的组件,只有 CuDNNLSTM 与 LSTM 不同。前几个例子只会让你的帖子混乱。跨度> 【参考方案4】:

TensorFlow 2.0 中,内置的 LSTMGRU 层已更新为利用 CuDNN 内核默认情况下,当 GPU 可用时。进行此更改后,之前的 keras.layers.CuDNNLSTM/CuDNNGRU 层已被弃用,您可以构建模型而无需担心运行它的硬件。

由于 CuDNN 内核 是在某些假设下构建的,这意味着如果您更改内置的默认值,该层将无法使用 CuDNN 内核 LSTMGRU 层。

查看 tensorflow RNN 文档:https://www.tensorflow.org/guide/keras/rnn

【讨论】:

这不是真的。我刚刚在 Python 3.9.9 和 Tensorflow 2.7.0 上尝试过。我用 tf.compat.v1.keras.layers.CuDNNLSTM(128, return_sequences=True) 替换了 tf.keras.layers.LSTM(128, return_sequences=True),我得到了超过 3 倍的速度提升,从每步 110ms 到38 毫秒。在 RTX 3080Ti 上运行,低端显卡可能会看到更大的性能提升。因此,你所说的关于 tensorflow 2.x 已经使用 CuDNN 内核的说法是不正确的,至少它对我不起作用。 使用 RTX 2060 Super 与 Keras 2.4/TF 2.3 确认 - 使用 CuDNNLSTM(通过 tf.compat.v1.keras.layers)与 LSTM 没有观察到加速。就我而言,无论哪种方式都是 24 毫秒/步。

以上是关于Keras 中的 CuDNNLSTM 和 LSTM 有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章

CuDNNLSTM:调用 ThenRnnForward 失败

tensorflow.keras.layers:ImportError:无法导入名称“CuDNNLSTM”

Keras - ImportError:无法导入名称'CuDNNLSTM'

CuDNNLSTM:UnknownError:找不到 dnn 实现

Keras中的LSTM

TensorFlow:如何使用具有可变输入长度的 CudnnLSTM(如 dynamic_rnn)?