提交 bf006681 编写于 作者: W wizardforcel

2021-10-14 22:31:23

上级 383a4c27
# 笔记
\ No newline at end of file
# 自动求导机制
1. [从后向中排除子图](#excluding-subgraphs-from-backward)
* [requires_grad](#requires_grad)
* [volatile](#volatile)
2. [自动求导如何编码历史信息](#how-autograd-encodes-the-history)
3. [Variable 上的 In-place 操作](#in-place-operations-on-variables)
4. [In-place 正确性检查](#in-place-correctness-checks)
* * *
本说明将概述 Autograd 如何工作并记录操作。没有必要全部了解,但建议您熟悉它,他可以将帮助你编写程序更高效,更清洁;同时还可以帮助您进行调试。
### 向后排除子视图:
每个变量都有一个标记:`requires_grad`允许从梯度计算中细分排除子图,并可以提高效率。
#### requires_grad
如果一个输入变量定义`requires_grad`,那么他的输出也可以使用`requires_grad`;相反,只有当所有的输入变量都不定义`requires_grad`梯度,才不会输出梯度。如果其中所有的变量都不需要计算梯度,在子图中从不执行向后计算。
```
>>> x = Variable(torch.randn(5, 5))
>>> y = Variable(torch.randn(5, 5))
>>> z = Variable(torch.randn(5, 5), requires_grad=True)
>>> a = x + y
>>> a.requires_grad
False
>>> b = a + z
>>> b.requires_grad
True
```
当您想要冻结部分模型时,这个标志特别有用;除非您事先知道不会使用到某些参数的梯度。
例如,如果您想调整预训练的`CNN`,只要切换冻结模型中的`requires_grad`标志即可,直到计算到最后一层才会保存中间缓冲区,仿射变换和网络输出都需要使用梯度的权值。
```
model = torchvision.models.resnet18(pretrained=True)
for param in model.parameters():
param.requires_grad = False
# Replace the last fully-connected layer
# Parameters of newly constructed modules have requires_grad=True by default
model.fc = nn.Linear(512, 100)
# Optimize only the classifier
optimizer = optim.SGD(model.fc.parameters(), lr=1e-2, momentum=0.9)
```
### autograd 如何编码历史信息:
每个变量都有一个`.creator`属性,它指向把它作为输出的函数。这是一个由`Function`对象作为节点组成的有向无环图(DAG)的入口点,它们之间的引用就是图的边。每次执行一个操作时,一个表示它的新`Function`就被实例化,它的`forward()`方法被调用,并且它输出的`Variable`的创建者被设置为这个`Function`。然后,通过跟踪从任何变量到叶节点的路径,可以重建创建数据的操作序列,并自动计算梯度。
需要注意的一点是,整个图在每次迭代时都是从头开始重新创建的,这就允许使用任意的 Python 控制流语句,这样可以在每次迭代时改变图的整体形状和大小。在启动训练之前不必对所有可能的路径进行编码—— what you run is what you differentiate.
### Variable 上的 In-place 操作:
支持自动归档中的就地操作是一件很困难的事情,我们在大多数情况下都不鼓励使用它们。Autograd 的积极缓冲区释放和重用使其非常高效,并且在现场操作实际上会降低内存使用量的情况下,极少数场合很少。除非您在内存压力很大的情况下运行,否则您可能永远不需要使用它们。
限制现场操作适用性的两个主要原因:
1. 覆盖计算梯度所需的值。这就是为什么变量不支持`log_`。其梯度公式需要原始输入,而通过计算逆运算可以重新创建它,它在数值上是不稳定的,并且需要额外的工作,这往往会失败使用这些功能的目的。
2. 每个`in-place`操作实际上需要实现重写计算图。不合适的版本只需分配新对象,并保留对旧图的引用,而`in-place`操作则需要将所有输入的`creator`更改为`Function`表示此操作。这就比较棘手,特别是如果有许多变量引用相同的存储(例如通过索引或转置创建的),并且如果被修改输入的存储被其他`Variable`引用,则`in-place`函数实际上会抛出错误。
### In-place 正确性检测:
每个变量都保留一个版本计数器`version counter`,当在任何操作中被使用时,它都会递增。当函数保存任何用于后向的`tensor`时,还会保存其包含变量的版本计数器`version counter`。一旦访问,`self.saved_tensors`它被会被检查,如果它大于保存的值,则会引起错误。
### 译者署名
| 用户名 | 头像 | 职能 | 签名 |
| --- | --- | --- | --- |
| [Song](https://ptorch.com) | ![](img/2018033000352689884.jpeg) | 翻译 | 人生总要追求点什么 |
\ No newline at end of file
此差异已折叠。
此差异已折叠。
# Tensor Attributes
* [torch.dtype](#torch-dtype)
* [torch.device](#torch-device)
* [torch.layout](#torch-layout)
每个`torch.Tensor`都有`torch.dtype`, `torch.device`,和`torch.layout`
### torch.dtype
`torch.dtype`是表示`torch.Tensor`的数据类型的对象。`PyTorch`有八种不同的数据类型:
| | Data type | dtype | Tensor types |
| --- | --- | --- | --- |
| 32-bit floating point | torch.float32 or torch.float | torch.*.FloatTensor |
| 64-bit floating point | torch.float64 or torch.double | torch.*.DoubleTensor |
| 16-bit floating point | torch.float16 or torch.half | torch.*.HalfTensor |
| 8-bit integer (unsigned) | torch.uint8 | torch.*.ByteTensor |
| 8-bit integer (signed) | torch.int8 | torch.*.CharTensor |
| 16-bit integer (signed) | torch.int16 or torch.short | torch.*.ShortTensor |
| 32-bit integer (signed) | torch.int32 or torch.int | torch.*.IntTensor |
| 64-bit integer (signed) | torch.int64 or torch.long | torch.*.LongTensor |
使用方法:
```
>>> x = torch.Tensor([[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]])
>>> print x.type()
torch.FloatTensor
```
### torch.device
`torch.device`代表将`torch.Tensor`分配到的设备的对象。
`torch.device`包含一个设备类型(`'cpu'``'cuda'`设备类型)和可选的设备的序号。如果设备序号不存在,则为当前设备; 例如,`torch.Tensor`用设备构建`'cuda'`的结果等同于`'cuda:X'`,其中`X``torch.cuda.current_device()`的结果。
`torch.Tensor`的设备可以通过`Tensor.device`访问属性。
构造`torch.device`可以通过字符串/字符串和设备编号。
通过一个字符串:
```
>>> torch.device('cuda:0')
device(type='cuda', index=0)
>>> torch.device('cpu')
device(type='cpu')
>>> torch.device('cuda') # current cuda device
device(type='cuda')
```
通过字符串和设备序号:
```
>>> torch.device('cuda', 0)
device(type='cuda', index=0)
>>> torch.device('cpu', 0)
device(type='cpu', index=0)
```
> **注意** `torch.device`函数中的参数通常可以用一个字符串替代。这允许使用代码快速构建原型。
>
> ```
> >> # Example of a function that takes in a torch.device
> >> cuda1 = torch.device('cuda:1')
> >> torch.randn((2,3), device=cuda1)
> ```
>
> ```
> >> # You can substitute the torch.device with a string
> >> torch.randn((2,3), 'cuda:1')
> ```
* * *
> **注意** 出于传统原因,可以通过单个设备序号构建设备,将其视为`cuda`设备。这匹配`Tensor.get_device()`,它为`cuda`张量返回一个序数,并且不支持`cpu`张量。
>
> ```
> >> torch.device(1)
> device(type='cuda', index=1)
> ```
* * *
> **注意** 指定设备的方法可以使用(properly formatted)字符串或(legacy)整数型设备序数,即以下示例均等效:
>
> ```
> >> torch.randn((2,3), device=torch.device('cuda:1'))
> >> torch.randn((2,3), device='cuda:1')
> >> torch.randn((2,3), device=1) # legacy
> ```
### torch.layout
`torch.layout`表示`torch.Tensor`内存布局的对象。目前,我们支持`torch.strided(dense Tensors)`并为`torch.sparse_coo(sparse COO Tensors)`提供实验支持。
`torch.strided`代表密集张量,是最常用的内存布局。每个`strided`张量都会关联 一个`torch.Storage`,它保存着它的数据。这些张力提供了多维度, 存储的`strided`视图。`Strides`是一个整数型列表:`k-th stride`表示在张量的第 k 维从一个元素跳转到下一个元素所需的内存。这个概念使得可以有效地执行多张量。
例:
```
>>> x = torch.Tensor([[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]])
>>> x.stride()
(5, 1)
>>> x.t().stride()
(1, 5)
```
关于`torch.sparse_coo`张量的更多信息,请参阅[torch.sparse](https://ptorch.com/docs/8/torch-sparse)
### 译者署名
| 用户名 | 头像 | 职能 | 签名 |
| --- | --- | --- | --- |
| [Song](https://ptorch.com) | ![](img/2018033000352689884.jpeg) | 翻译 | 人生总要追求点什么 |
\ No newline at end of file
# torch.sparse
> 警告 该 API 目前是实验性的,可能在不久的将来会发生变化。
torch 支持 COO(rdinate)格式的稀疏张量,可以有效地存储和处理大多数元素为零的张量。
稀疏张量被表示为一对致密张量:值的张量和 2D 张量的索引。可以通过提供这两个张量来构造稀疏张量,以及稀疏张量的大小(不能从这些张量推断出!)假设我们要在位置(0,2)处定义具有条目 3 的稀疏张量, ,位置(1,0)的条目 4,位置(1,2)的条目 5。我们会写:
```
>>> i = torch.LongTensor([[0, 1, 1],
[2, 0, 2]])
>>> v = torch.FloatTensor([3, 4, 5])
>>> torch.sparse.FloatTensor(i, v, torch.Size([2,3])).to_dense()
0 0 3
4 0 5
[torch.FloatTensor of size 2x3]
```
请注意,LongTensor 的输入不是索引元组的列表。如果要以这种方式编写索引,则在将它们传递给稀疏构造函数之前,应该进行转置:
```
>>> i = torch.LongTensor([[0, 2], [1, 0], [1, 2]])
>>> v = torch.FloatTensor([3, 4, 5 ])
>>> torch.sparse.FloatTensor(i.t(), v, torch.Size([2,3])).to_dense()
0 0 3
4 0 5
[torch.FloatTensor of size 2x3]
```
您还可以构建混合稀疏张量,其中只有第一个 n 维是稀疏的,其余的维度是密集的。
```
>>> i = torch.LongTensor([[2, 4]])
>>> v = torch.FloatTensor([[1, 3], [5, 7]])
>>> torch.sparse.FloatTensor(i, v).to_dense()
0 0
0 0
1 3
0 0
5 7
[torch.FloatTensor of size 5x2]
```
可以通过指定一个空的稀疏张量来构建一个空的稀疏张量:
```
print torch.sparse.FloatTensor(2, 3)
# FloatTensor of size 2x3 with indices:
# [torch.LongTensor with no dimension]
# and values:
# [torch.FloatTensor with no dimension]
```
> 注意:
>
> 我们的稀疏张量格式允许未被缩小的稀疏张量,其中索引中可能有重复的坐标; 在这种情况下,解释是该索引处的值是所有重复值条目的总和。非协调张量允许我们更有效地实施某些运营商。
>
> 在大多数情况下,您不必关心稀疏张量是否合并,因为大多数操作将在合并或未被缩小的稀疏张量的情况下工作相同。但是,您可能需要关心两种情况。
>
> 首先,如果您反复执行可以产生重复条目(例如 torch.sparse.FloatTensor.add())的操作,则应偶尔将您的稀疏张量合并,以防止它们变得太大。
>
> 其次,一些运营商将取决于它们是否被合并或不产生不同的值(例如, torch.sparse.FloatTensor._values()和 torch.sparse.FloatTensor._indices(),以及 torch.Tensor._sparse_mask())。这些运算符前面加上一个下划线,表示它们显示内部实现细节,应谨慎使用,因为与聚结的稀疏张量一起工作的代码可能无法与未被缩放的稀疏张量一起使用; 一般来说,在与这些运营商合作之前明确地合并是最安全的。
>
> 例如,假设我们想通过直接操作来实现一个操作符 torch.sparse.FloatTensor._values()。随着乘法分布的增加,标量的乘法可以以明显的方式实现; 然而,平方根不能直接实现,因为(如果你被赋予了未被缩放的张量,那将是什么)。sqrt(a + b) != sqrt(a) + sqrt(b)
### class torch.sparse.FloatTensor
* add()
* add_()
* clone()
* dim()
* div()
* div_()
* get_device()
* hspmm()
* mm()
* mul()
* mul_()
* resizeAs_()
* size()
* spadd()
* spmm()
* sspaddmm()
* sspmm()
* sub()
* sub_()
* t_()
* toDense()
* transpose()
* transpose_()
* zero_()
* coalesce()
* is_coalesced()
* _indices()
* _values()
* _nnz()
### 译者署名
| 用户名 | 头像 | 职能 | 签名 |
| --- | --- | --- | --- |
| [Song](https://ptorch.com) | ![](img/2018033000352689884.jpeg) | 翻译 | 人生总要追求点什么 |
\ No newline at end of file
此差异已折叠。
# torch.Storage
* * *
`torch.Storage`是单个数据类型的连续的`一维数组`,每个`torch.Tensor`都具有相同数据类型的相应存储。
```
class torch.FloatStorage
```
* `byte()`:将 Storage 转为 byte 类型
* `char()`:将 Storage 转为 char 类型
* `clone()`:返回 Storage 的副本
* `copy_()`
* `cpu()`:如果尚未在 CPU 上,则返回 Storage 的 CPU 副本
* `cuda(device=None, async=False)`:在 CUDA 内存中返回此对象的副本。如果该对象已经在 CUDA 内存中,并且在正确的设备上,则不会执行任何操作,并返回原始对象。 参数说明:
1. device (int) - 目标 GPU 的 id。默认值是当前设备。
2. async (bool) -如果值为 True,且源在锁定内存中,则副本相对于宿主是异步的。否则此参数不起效果。
* `data_ptr()`: 返回一个时间戳
* `double()`:将 Storage 转为 double 类型
* `element_size()`:返回参数的 size
* `fill_()`
* `float()`:将 Storage 转为 float 类型
* `from_buffer()`
* `half()`:将 Storage 转为 half 类型
* `int()`:将 Storage 转为 int 类型
* `is_cuda = False`
* `is_pinned()`
* `is_shared()`
* `is_sparse = False`
* `long()`:将 Storage 转为 long 类型
* `new()`
* `pin_memory()`:将存储复制到固定内存(如果尚未固定)。
* `resize_()`
* `share_memory_()`:这对于已经在共享内存和 CUDA 存储器中的存储器是无效的,不需要为了跨进程共享而移动。无法调整共享内存中的存储空间。返回:self
* `short()`:将 Storage 转为 short 类型
* `size()`:返回 Storage 转的大小
* `tolist()`:返回一个包含 Storage 中元素的列表
* `type(new_type=None, async=False)`:将此对象转为指定类型。如果已经是正确类型,不会执行复制操作,直接返回原对象。
参数说明:
1. `new_type` (type 或 string) -需要转成的类型
2. `async (bool)` -如果值为 True,并且源处于固定内存中,目标位于 GPU 上,反之亦然,则相对于主机异步执行该副本。否则,参数没有效果。
具体使用教程请参考:[使用 torch.Storage 共享多个张量的相同存储以及将 torch.Tensor 转化为 torch.Storage](https://ptorch.com/news/52.html)
### 译者署名
| 用户名 | 头像 | 职能 | 签名 |
| --- | --- | --- | --- |
| [Song](https://ptorch.com) | ![](img/2018033000352689884.jpeg) | 翻译 | 人生总要追求点什么 |
\ No newline at end of file
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
# torch.distributions
### 译者署名
| 用户名 | 头像 | 职能 | 签名 |
| --- | --- | --- | --- |
| [Song](https://ptorch.com) | ![](img/2018033000352689884.jpeg) | 翻译 | 人生总要追求点什么 |
\ No newline at end of file
# Multiprocessing 包 - torch.multiprocessing
* [战略管理](https://ptorch.com/docs/1/torch-multiprocessing#strategy-management)
* [共享 CUDA 张量](https://ptorch.com/docs/1/torch-multiprocessing#sharing-cuda-tensors)
* [共享策略](https://ptorch.com/docs/1/torch-multiprocessing#sharing-strategies)
1. [文件描述符 - file_descriptor](https://ptorch.com/docs/1/torch-multiprocessing#file-descriptor-file-descriptor)
2. [文件系统 - file_system](https://ptorch.com/docs/1/torch-multiprocessing#file-system-file-system)
* * *
`torch.multiprocessing`是本机`multiprocessing`模块的封装。封装了`multiprocessing`模块。它注册自定义的`reducer`,它使用共享内存为不同进程中的相同数据提供视图共享。一旦张量/存储被移动到`shared_memory`(参见[share*memory*()](http://pytorch.org/docs/master/tensors.html#torch.Tensor.share_memory_)),就可以将其发送到其他进程而不进行其它任何操作。
这个 API 与原始模块 100%兼容,将`import multiprocessing`改为`import torch.multiprocessing`就可以将所有张量通过**队列发送****通过其他机制共享转移**到共享内存中
由于 API 的相似性,我们没有记录这个软件包的大部分内容,我们建议您参考`Python multiprocessing`原始模块的文档。
> **警告:** 如果主进程突然退出(例如因为传入的信号),Python `multiprocessing`有时无法清理其子进程。这是一个已知的警告,所以如果您在中断解释器后看到任何资源泄漏,这可能意味着这刚刚发生在您身上。
## 战略管理
```
torch.multiprocessing.get_all_sharing_strategies()
```
返回一组当前系统支持的共享策略。
```
torch.multiprocessing.get_sharing_strategy()
```
返回共享 CPU 张量的当前策略
```
torch.multiprocessing.set_sharing_strategy(new_strategy)
```
设置共享 CPU 张量的策略
参数: new_strategy(str)- 所选策略的名称。应当是上面`get_all_sharing_strategies()`中系统支持的共享策略之一。
## 共享 CUDA 张量
只支持在 Python 3 中使用`spawn``forkserver`启动方法才支持在进程之间共享 CUDA 张量。
Python2 中的`multiprocessing`只能使用`fork`创建子进程,并且不支持 CUDA 运行时。
> **警告:** CUDA API 要求导出到其他进程的分配一直保持有效,只要它们被使用。您应该小心,确保您共享的 CUDA 张力不要超出范围,只要有必要。这不应该是共享模型参数的问题,但传递其他类型的数据应该小心。请注意,此限制不适用于共享 CPU 内存。
## 共享策略
本节简要概述了不同的共享策略如何工作。请注意,它只适用于 CPU 张量 - CUDA 张量将始终使用 CUDA API,因为它们是唯一的共享方式。
### 文件描述符 -`file_descripor`
> **注意:** 这是默认策略(除了不支持的 MacOS 和 OS X)。
此策略将使用文件描述符作为共享内存句柄。当存储器被移动到共享存储器时,每当存储器被移动到共享内存中时,从`shm_open`对象获取的文件描述符被缓存,并且当它被发送到其他进程时,文件描述符也将被传送(例如通过 UNIX 套接字)。接收器还将缓存文件描述符并且`mmap`它,以获得对存储数据的共享视图。
请注意,如果要共享很多张量,则此策略将保留大量文件描述符需要很多时间才能打开。如果您的系统对打开的文件描述符数量有限制,并且无法提高,你应该使用`file_system`策略。
### 文件系统 -file_system
该策略将使用给定的文件名`shm_open`来标识共享内存区域。这具有不需要实现缓存从其获得的文件描述符的优点,但是同时容易发生共享内存泄漏。该文件创建后不能被删除,因为其他进程需要访问它以打开其视图。如果进程死机或死机,并且不调用存储析构函数,则文件将保留在系统中。这是非常严重的,因为它们在系统重新启动之前不断使用内存,或者手动释放它们。
为了解决共享内存文件泄漏的问题,`torch.multiprocessing`将产生一个守护程序`torch_shm_manager`,它将自己与当前进程组隔离,并且将跟踪所有共享内存分配。一旦连接到它的所有进程退出,它将等待一会儿,以确保不会有新的连接,并且将遍历该组分配的所有共享内存文件。如果发现它们中的任何一个仍然存在,就释放掉它。我们已经测试了这种方法,并且证明对于各种故障是稳健的。不过,如果您的系统具有足够的限制,并且支持`file_descriptor`策略,我们不建议切换到该策略。
### 译者署名
| 用户名 | 头像 | 职能 | 签名 |
| --- | --- | --- | --- |
| [Song](https://ptorch.com) | ![](img/2018033000352689884.jpeg) | 翻译 | 人生总要追求点什么 |
\ No newline at end of file
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
# 遗留包 - torch.legacy
此包中包含从 Lua Torch 移植来的代码。
为了可以使用现有的模型并且方便当前 Lua Torch 使用者过渡,我们创建了这个包。 可以在`torch.legacy.nn`中找到`nn`代码,并在`torch.legacy.optim`中找到`optim`代码。 API 应该完全匹配 Lua Torch。
### 译者署名
| 用户名 | 头像 | 职能 | 签名 |
| --- | --- | --- | --- |
| [Song](https://ptorch.com) | ![](img/2018033000352689884.jpeg) | 翻译 | 人生总要追求点什么 |
\ No newline at end of file
# torchvision 参考
\ No newline at end of file
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册