知行编程网知行编程网  2022-08-08 14:00 知行编程网 隐藏边栏 |   抢沙发  9 
文章评分 0 次,平均分 0.0
导读

PyTorch使用上的13个特性,确实非常的有用。

PyTorch在学术界和工业界的应用研究中都获得了很多关注。它是一个具有很大灵活性的深度学习框架,使用了大量的实用工具和函数来加快工作速度。PyTorch的学习曲线并不是那么陡峭,但在其中实现高效和干净的代码可能会很棘手。在使用它超过2年之后,以下是我最喜欢的PyTorch功能,我希望我一开始学习它就知道。

1. DatasetFolder

当学习PyTorch时,人们首先要做的事情之一是实现自己的某种<span style="font-size: 15px;">Dataset</span> 。这是一个低级错误,没有必要浪费时间写这样的东西。通常,数据集要么是数据列表(或者是numpy数组),要么磁盘上的文件。所以,把数据在磁盘上组织好,要比写一个自定义的<span style="font-size: 15px;">Dataset</span>来加载某种奇怪的格式更好。

分类器最常见的数据格式之一,是有一个带有子文件夹的目录,子文件夹表示类,子文件夹中的文件表示样本,如下所示。

有一个内置的方式来加载这类数据集,不管你的数据是图像,文本文件或其他什么,只要使用'<span style="font-size: 15px;">DatasetFolder</span>就可以了。令人惊讶的是,这个类是<span style="font-size: 15px;">torchvision</span>包的一部分,而不是核心PyTorch。这个类非常全面,你可以从文件夹中过滤文件,使用自定义代码加载它们,并动态转换原始文件。例子:

如果你在处理图像,还有一个<span style="font-size: 15px;">torchvision.datasets.ImageFolder</span>类,它基于<span style="font-size: 15px;">DatasetLoader</span>,它被预先配置为加载图像。

2. 尽量少用 <span style="font-size: 20px;">.to(device)</span> ,用 <span style="font-size: 20px;">zeros_like</span> / <span style="font-size: 20px;">ones_like</span> 之类的代替

我读过很多来自GitHub仓库的PyTorch代码。最让我恼火的是,几乎在每个repo中都有许多<span style="font-size: 15px;">*.to(device)</span>行,它们将数据从CPU或GPU转移到其他地方。这样的语句通常会出现在大量的repos或初学者教程中。我强烈建议尽可能少地实现这类操作,并依赖内置的PyTorch功能自动实现这类操作。到处使用<span style="font-size: 15px;">.to(device)</span>通常会导致性能下降,还会出现异常:

显然,有些情况下你无法回避它,但大多数情况(如果不是全部)都在这里。其中一种情况是初始化一个全0或全1的张量,这在深度神经网络计算损失的的时候是经常发生的,模型的输出已经在cuda上了,你需要另外的tensor也是在cuda上,这时,你可以使用<span style="font-size: 15px;">*_like</span>操作符:

在内部,PyTorch所做的是调用以下操作:

所以所有的设置都是正确的,这样就减少了代码中出现错误的概率。类似的操作包括:

3. Register Buffer ( <span style="font-size: 20px;">nn.Module.register_buffer</span>)

这将是我劝人们不要到处使用 <span style="font-size: 15px;">.to(device)</span> 的下一步。有时,你的模型或损失函数需要有预先设置的参数,并在调用<span style="font-size: 15px;">forward</span>时使用,例如,它可以是一个“权重”参数,它可以缩放损失或一些固定张量,它不会改变,但每次都使用。对于这种情况,请使用<span style="font-size: 15px;">nn.Module.register_buffer</span> 方法,它告诉PyTorch将传递给它的值存储在模块中,并将这些值随模块一起移动。如果你初始化你的模块,然后将它移动到GPU,这些值也会自动移动。此外,如果你保存模块的状态,buffers也会被保存!

一旦注册,这些值就可以在forward函数中访问,就像其他模块的属性一样。

4. Built-in <span style="font-size: 20px;">Identity()</span>

有时候,当你使用迁移学习时,你需要用1:1的映射替换一些层,可以用<span style="font-size: 15px;">nn.Module</span>来实现这个目的,只返回输入值。PyTorch内置了这个类。

例子,你想要在分类层之前从一个预训练过的<span style="font-size: 15px;">ResNet50</span>获取图像表示。以下是如何做到这一点:

5. Pairwise distances: <span style="font-size: 20px;">torch.cdist</span>

下次当你遇到计算两个张量之间的欧几里得距离(或者一般来说:p范数)的问题时,请记住<span style="font-size: 15px;">torch.cdist</span>。它确实做到了这一点,并且在使用欧几里得距离时还自动使用矩阵乘法,从而提高了性能。

没有矩阵乘法或有矩阵乘法的性能,在我的机器上使用mm时,速度快了2倍以上。

867µs±142µs per loop (mean±std. dev. of 7 run, 1000 loop each)

417µs±52.9µs per loop (mean±std. dev. of 7 run, 1000 loop each)

6. Cosine similarity: <span style="font-size: 20px;">F.cosine_similarity</span>

与上一点相同,计算欧几里得距离并不总是你需要的东西。当处理向量时,通常余弦相似度是选择的度量。PyTorch也有一个内置的余弦相似度实现。


PyTorch中批量计算余弦距离

7. 归一化向量: <span style="font-size: 20px;">F.normalize</span>

最后一点仍然与向量和距离有松散的联系,那就是归一化:通常是通过改变向量的大小来提高计算的稳定性。最常用的归一化是L2,可以在PyTorch中按如下方式应用:

在PyTorch中执行归一化的旧方法是:

在PyTorch中批量进行L2归一化

8. 线性层 + 分块技巧 (<span style="font-size: 20px;">torch.chunk</span>)

这是我最近发现的一个有创意的技巧。假设你想把你的输入映射到N个不同的线性投影中。你可以通过创建N<span style="font-size: 15px;">nn.Linear</span>来做到这一点。或者你也可以创建一个单一的线性层,做一个向前传递,然后将输出分成N块。这种方法通常会带来更高的性能,所以这是一个值得记住的技巧。

289 µs ± 30.8 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

202 µs ± 8.09 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

9. Masked select (<span style="font-size: 20px;">torch.masked_select</span>)

有时你只需要对输入张量的一部分进行计算。给你一个例子:你想计算的损失只在满足某些条件的张量上。为了做到这一点,你可以使用<span style="font-size: 15px;">torch.masked_select</span>,注意,当需要梯度时也可以使用这个操作。

直接在tensor上应用mask

类似的行为可以通过使用mask作为输入张量的 “indexer”来实现。

有时,一个理想的解决方案是用0填充mask中所有的<span style="font-size: 15px;">False</span>值,可以这样做:

10. 使用 <span style="font-size: 20px;">torch.where</span>来对tensors加条件

当你想把两个张量结合在一个条件下这个函数很有用,如果条件是真,那么从第一个张量中取元素,如果条件是假,从第二个张量中取元素。

11. 在给定的位置给张量填入值(<span style="font-size: 20px;">Tensor.scatter</span>)

这个函数的用例如下,你想用给定位置下另一个张量的值填充一个张量。一维张量更容易理解,所以我将先展示它,然后继续更高级的例子。

上面的例子很简单,但是现在看看如果将index改为<span style="font-size: 15px;">index = torch.tensor([0, 1, 4])</span>会发生什么:

为什么最后一个值是-3,这是反直觉的,对吧?这是PyTorch <span style="font-size: 15px;">scatter</span>函数的中心思想。<span style="font-size: 15px;">index</span>变量表示<span style="font-size: 15px;">data</span>张量的第i个值应该放在<span style="font-size: 15px;">values</span>张量的哪个位置。我希望下面的简单python版的这个操作能让你更明白:


2D数据的PyTorch scatter例子

始终记住,<span style="font-size: 15px;">index</span>的形状与<span style="font-size: 15px;">values</span>的形状相关,而<span style="font-size: 15px;">index</span>中的值对应于<span style="font-size: 15px;">data</span>中的位置。

12. 在网络中进行图像插值 (<span style="font-size: 20px;">F.interpolate</span>)

当我学习PyTorch时,我惊讶地发现,实际上可以在前向传递中调整图像(或任何中间张量),并保持梯度流。这种方法在使用CNN和GANs时特别有用。

13个你一定要知道的PyTorch特性

13个你一定要知道的PyTorch特性

看看梯度流是如何保存的:

13. 将图像做成网格 (<span style="font-size: 20px;">torchvision.utils.make_grid</span>)

当使用PyTorch和torchvision时,不需要使用matplotlib或一些外部库来复制粘贴代码来显示图像网格。只要使用<span style="font-size: 15px;">torchvision.utils.make_grid</span>就行了。

13个你一定要知道的PyTorch特性

本文为原创文章,版权归所有,欢迎分享本文,转载请保留出处!

知行编程网
知行编程网 关注:1    粉丝:1
这个人很懒,什么都没写

发表评论

表情 格式 链接 私密 签到
扫一扫二维码分享