|高性能PyTorch是如何炼成的?过来人吐血整理的10条避坑指南


选自towardsdatascience
作者:Eugene Khvedchenya
机器之心编译
参与:小舟、蛋酱、魔王
高性能 PyTorch 的训练管道是什么样的?是产生最高准确率的模型?是最快的运行速度?是易于理解和扩展?还是容易并行化?答案是 , 包括以上提到的所有 。
|高性能PyTorch是如何炼成的?过来人吐血整理的10条避坑指南
本文插图

如何用最少的精力 , 完成最高效的 PyTorch 训练?一位有着 PyTorch 两年使用经历的 Medium 博主最近分享了他在这方面的 10 个真诚建议 。
?
在 Efficient PyTorch 这一部分中 , 作者提供了一些识别和消除 I/O 和 CPU 瓶颈的技巧 。 第二部分阐述了一些高效张量运算的技巧 , 第三部分是在高效模型上的 debug 技巧 。
在阅读这篇文章之前 , 你需要对 PyTorch 有一定程度的了解 。
好吧 , 从最明显的一个开始:
建议 0:了解你代码中的瓶颈在哪里
命令行工具比如 nvidia-smi、htop、iotop、nvtop、py-spy、strace 等 , 应该成为你最好的伙伴 。 你的训练管道是否受 CPU 约束?IO 约束?GPU 约束?这些工具将帮你找到答案 。
这些工具你可能从未听过 , 即使听过也可能没用过 。 没关系 。 如果你不立即使用它们也可以 。 只需记住 , 其他人可能正在用它们来训练模型 , 速度可能会比你快 5%、10%、15%-…… 最终可能会导致面向市场或者工作机会时候的不同结果 。
数据预处理
几乎每个训练管道都以 Dataset 类开始 。 它负责提供数据样本 。 任何必要的数据转换和扩充都可能在此进行 。 简而言之 , Dataset 能报告其规模大小以及在给定索引时 , 给出数据样本 。
如果你要处理类图像的数据(2D、3D 扫描) , 那么磁盘 I/O 可能会成为瓶颈 。 为了获取原始像素数据 , 你的代码需要从磁盘中读取数据并解码图像到内存 。 每个任务都是迅速的 , 但是当你需要尽快处理成百上千或者成千上万个任务时 , 可能就成了一个挑战 。 像 NVidia 这样的库会提供一个 GPU 加速的 JPEG 解码 。 如果你在数据处理管道中遇到了 IO 瓶颈 , 这种方法绝对值得一试 。
还有另外一个选择 , SSD 磁盘的访问时间约为 0.08–0.16 毫秒 。 RAM 的访问时间是纳秒级别的 。 我们可以直接将数据存入内存 。
建议 1:如果可能的话 , 将数据的全部或部分移至 RAM 。
如果你的内存中有足够多的 RAM 来加载和保存你的训练数据 , 这是从管道中排除最慢的数据检索步骤最简单的方法 。
这个建议可能对云实例特别有用 , 比如亚马逊的 p3.8xlarge 。 该实例有 EBS 磁盘 , 它的性能在默认设置下非常受限 。 但是 , 该实例配备了惊人的 248Gb 的 RAM 。 这足够将整个 ImageNet 数据集存入内存了!你可以通过以下方法达到这一目标:
class RAMDataset(Dataset): def __init__(image_fnames, targets): self.targets = targets self.images = [] for fname in tqdm(image_fnames, desc=''Loading files in RAM''): with open(fname, ''rb'') as f: self.images.append(f.read())
def __len__(self): return len(self.targets)
def __getitem__(self, index): target = self.targets[index] image, retval = cv2.imdecode(self.images[index], cv2.IMREAD_COLOR) return image, target
我个人也面对过这个瓶颈问题 。 我有一台配有 4x1080Ti GPUs 的家用 PC 。 有一次 , 我采用了有 4 个 NVidia Tesla V100 的 p3.8xlarge 实例 , 然后将我的训练代码移到那里 。 鉴于 V100 比我的 oldie 1080Ti 更新更快的事实 , 我期待看到训练快 15–30% 。 出乎意料的是 , 每个时期的训练时间都增加了 。 这让我明白要注意基础设施和环境差异 , 而不仅仅是 CPU 和 GPU 的速度 。


推荐阅读