将PyTorch投入生产的5个常见错误

作者:Taras Matsyk
编译:ronghuaiyang
导读
本文列举了5个将PyTorch应用到生产时容易遇到的5个错误操作 。
将PyTorch投入生产的5个常见错误文章插图
ML是有趣的 , ML是受欢迎的 , ML无处不在 。 大多数公司要么使用TensorFlow , 要么使用PyTorch , 还有些老家伙喜欢Caffe 。
尽管大多数教程和在线教程使用TensofFlow , 但我的大部分经验都是使用PyTorch 。 在这里 , 我想分享在生产中使用PyTorch最常见的5个错误 。 考虑过使用CPU吗?使用多线程?使用更多的GPU内存?这些坑我们都踩过 。
错误 #1 — 在推理模式下保存动态图如果你以前使用过TensorFlow , 那么你可能知道TensorFlow和PyTorch之间的关键区别 —— 静态图和动态图 。 调试TensorFlow非常困难 , 因为每次模型更改时都要重新构建graph 。 这需要时间、努力和你的希望 。 当然 , TensorFlow现在更好了 。
总的来说 , 为了使调试更容易 , ML框架使用动态图 , 这些图与PyTorch中所谓的Variables有关 。 你使用的每个变量都链接到前一个变量 , 以构建反向传播的关系 。
下面是它在实际中的样子:
将PyTorch投入生产的5个常见错误文章插图
在大多数情况下 , 你希望在模型训练完成后优化所有的计算 。 如果你看一下torch的接口 , 有很多可选项 , 特别是在优化方面 。 eval模式、detach和no_grad的方法造成了很多混乱 。 让我来解释一下它们是如何工作的 。 在模型被训练和部署之后 , 以下是你所关心的事情:速度、速度和CUDA内存溢出异常 。
为了加速PyTorch模型 , 你需要将它切换到eval模式 。 它通知所有层在推理模式下使用batchnorm和dropout层(简单地说就是不使用dropout) 。 现在 , 有一个detach方法可以将变量从它的计算图中分离出来 。 当你从头开始构建模型时 , 它很有用 , 但当你想重用SOTA的模型时 , 它就不太有用了 。 一个更全局性的解决方案将是在前向传播的时候在上下文中使用torch.no_grad 。 这样可以不用在在结果中存储图中变量的梯度 , 从而减少内存消耗 。 它节省内存 , 简化计算 , 因此 , 你得到更多的速度和更少的内存使用 。
错误 #2 — 没有使能cudnn优化算法你可以在nn.Module中设置很多布尔标志 , 有一个是你必须知道的 。 使用cudnn.benchmark = True来对cudnn进行优化 。 通过设置cudnn.enabled = True , 可以确保cudnn确实在寻找最优算法 。 NVIDIA在优化方面为你提供了很多神奇的功能 , 你可以从中受益 。
请注意你的数据必须在GPU上 , 模型输入大小不应该改变 。 数据的形状的变化越多 , 可以做的优化就越少 。 例如 , 要对数据进行归一化 , 可以对图像进行预处理 。 总之 , 可以有变化 , 但不要太多 。
错误 #3 — 重用 JIT-compilationPyTorch提供了一种简单的方法来优化和重用来自不同语言的模型(见Python-To-Cpp) 。 如果你足够勇敢 , 你可能会更有创造力 , 并将你的模型嵌入到其他语言中 。
JIT-compilation允许在输入形状不变的情况下优化计算图 。 它的意思是 , 如果你的数据形状变化不大(参见错误#2) , JIT是一种选择 。 老实说 , 和上面提到的no_grad和cudnn相比 , 它并没有太大的区别 , 但可能有 。 这只是第一个版本 , 有巨大的潜力 。
请注意 , 如果你的模型中有conditions , 这在RNNs中很常见 , 它就没法用了 。
错误 #4 — 尝试扩展使用CPUGPU很贵 , 云虚拟机也一样很贵 。 即使使用AWS , 一个实例也将花费你大约100美元/天(最低价格是0.7美元/小时) 。 也许有人会想“如果我用5个CPU来代替1个GPU可以吗?” 。 所有试过的人都知道这是一个死胡同 。 是的 , 你可以为CPU优化一个模型 , 但是最终它还是会比GPU慢 。 相信我 , 我强烈建议忘记这个想法 。
错误 #5 — 处理向量而不是矩阵

  • cudnn - check
  • no_grad - check
  • GPU with correct version of CUDA - check
  • JIT-compilation - check
一切都准备好了 , 还能做什么?
现在是时候使用一点数学了 。 如果你还记得大部分NN是如何用所谓的张量训练的 。 张量在数学上是一个n维数组或多线性几何向量 。 你能做的就是把输入(如果你有足够的时间的话)分组成张量或者矩阵 , 然后把它输入到你的模型中 。 例如 , 使用图像数组作为发送到PyTorch的矩阵 。 性能增益等于同时传递的对象数量 。
这是一个显而易见的解决方案 , 但是很少有人真正使用它 , 因为大多数时候对象都是一个一个地处理的 , 而且在流程上设置这样的流可能有点困难 。 别担心 , 你会成功的!