...
 
Commits (22)
    https://gitcode.net/OpenDocCN/pytorch-doc-zh/-/commit/93bf5cae9faca24c14c72a4963032ce99000438d 迁移 python 0.x 版本到新的域名下 2023-08-07T15:56:24+08:00 片刻小哥哥 jiang-s@163.com https://gitcode.net/OpenDocCN/pytorch-doc-zh/-/commit/4ff6d9849527aa897f77b4e3d25db0e2380f7f34 更新 PyTorch 1.8版本 新特性 2023-08-07T16:07:44+08:00 片刻小哥哥 jiang-s@163.com https://gitcode.net/OpenDocCN/pytorch-doc-zh/-/commit/3b99edc43f97fa45097b869d165e1ab142bff7ca Merge pull request #626 from jiangzhonglian/main 2023-08-07T16:19:24+08:00 片刻 jiang-s@163.com 更新 PyTorch 1.8版本 新特性 https://gitcode.net/OpenDocCN/pytorch-doc-zh/-/commit/81377f6032f96a0a6b08b2ade584bf6d11521e1f 翻译 "用 YouTube 入门 PyTorch" 的 "PyTorch 入门 - YouTube 系列" 2023-08-08T12:01:04+08:00 fdc_mbp fudongcheng110@foxmail.com https://gitcode.net/OpenDocCN/pytorch-doc-zh/-/commit/7c5054c4d028414c2fcdc75d10a3cc28ada0e38b 代码块语法高亮开启 2023-08-08T16:39:18+08:00 fdc_mbp fudongcheng110@foxmail.com https://gitcode.net/OpenDocCN/pytorch-doc-zh/-/commit/edcdc059d5ce43af03d8092e81be96b5f7efdd34 翻译 "用 YouTube 入门 PyTorch" 的 "PyTorch 入门" 2023-08-08T20:50:56+08:00 fdc_mbp fudongcheng110@foxmail.com https://gitcode.net/OpenDocCN/pytorch-doc-zh/-/commit/31347ca6afce5a397f5293c094ea6d4767058580 finish flask_rest_api_tutorial 2023-08-09T00:58:59+08:00 masteryi-0018 1536474741@qq.com https://gitcode.net/OpenDocCN/pytorch-doc-zh/-/commit/c9d72db80dd319c6e9122f1f7abf6e7e09795153 Merge pull request #629 from masteryi-0018/master 2023-08-09T09:35:13+08:00 片刻 jiang-s@163.com finish flask_rest_api_tutorial https://gitcode.net/OpenDocCN/pytorch-doc-zh/-/commit/905d75db565d307e2cc49e53802f3baeab3869a0 Merge pull request #628 from Fadegentle/translate 2023-08-09T09:37:18+08:00 片刻 jiang-s@163.com Complete translation of "Introduction to PyTorch on YouTube" 《Introduction to PyTorch - YouTube Series》《Introduction to PyTorch》 https://gitcode.net/OpenDocCN/pytorch-doc-zh/-/commit/5012411899016f395611cfd86bf61be2ce505c02 更新 PyTorch 1.7版本 新特性 2023-08-09T10:31:45+08:00 片刻小哥哥 jiang-s@163.com https://gitcode.net/OpenDocCN/pytorch-doc-zh/-/commit/027a82988c4e7da3cf43580d226b9957277d08ec 修正中文教程2.0 文件路径 2023-08-09T10:32:29+08:00 片刻小哥哥 jiang-s@163.com https://gitcode.net/OpenDocCN/pytorch-doc-zh/-/commit/ed3086db3c4c2e50806973165c05b8bee0e38002 Merge pull request #630 from jiangzhonglian/main 2023-08-09T10:35:53+08:00 片刻 jiang-s@163.com 修正中文教程2.0 文件路径 https://gitcode.net/OpenDocCN/pytorch-doc-zh/-/commit/f7d297cb3cc93784c242d1cb498ab72dfe1e76f3 修正显示错误 2023-08-09T10:45:52+08:00 片刻小哥哥 jiang-s@163.com https://gitcode.net/OpenDocCN/pytorch-doc-zh/-/commit/1857f769a292b9c0131eb5d09584d1e2adbd20a5 Merge pull request #631 from jiangzhonglian/main 2023-08-09T10:50:16+08:00 片刻 jiang-s@163.com 修正显示错误 https://gitcode.net/OpenDocCN/pytorch-doc-zh/-/commit/a155f6a21fff52a1b57d64213465fcc72a9ee62a 修正 部分页面图片的相对路径 2023-08-09T14:28:41+08:00 片刻小哥哥 jiang-s@163.com https://gitcode.net/OpenDocCN/pytorch-doc-zh/-/commit/d9bd892a522c4d0a18fbcefd035a42603f876774 更新 PyTorch 1.6 版本 新特性 2023-08-09T14:54:14+08:00 片刻小哥哥 jiang-s@163.com https://gitcode.net/OpenDocCN/pytorch-doc-zh/-/commit/74a41378c444ac7eab5dbfef38a886ee0f824ed5 Merge pull request #632 from jiangzhonglian/main 2023-08-09T15:05:48+08:00 片刻 jiang-s@163.com 更新 PyTorch 1.6 版本 新特性 https://gitcode.net/OpenDocCN/pytorch-doc-zh/-/commit/8b8653eb28277215c83b3eeff7fc0162336b8317 翻译 "用 YouTube 入门 PyTorch" 的 "PyTorch 张量入门" 2023-08-09T17:05:03+08:00 fdc_mbp fudongcheng110@foxmail.com https://gitcode.net/OpenDocCN/pytorch-doc-zh/-/commit/574a081c22425b7747bdce2c704e36a044de06c6 修改称谓"你"->"您" 2023-08-09T17:08:38+08:00 fdc_mbp fudongcheng110@foxmail.com https://gitcode.net/OpenDocCN/pytorch-doc-zh/-/commit/c0f60cea502b8655cc9ed69a0fa40d4f111d0dc5 删除中文破折号周边空格 2023-08-09T17:09:37+08:00 fdc_mbp fudongcheng110@foxmail.com https://gitcode.net/OpenDocCN/pytorch-doc-zh/-/commit/00149e9df0f4200f2b13139c263fcf694c0511a5 翻译对齐"自动梯度"->"自动微分" 2023-08-09T17:32:00+08:00 fdc_mbp fudongcheng110@foxmail.com https://gitcode.net/OpenDocCN/pytorch-doc-zh/-/commit/aff111bd6e4e9ef3a486018791e385d04665a6ed Cool ! Merge pull request #633 from Fadegentle/master 2023-08-09T18:19:58+08:00 片刻 jiang-s@163.com Complete translation of "Introduction to PyTorch on YouTube" 《Introduction to PyTorch Tensors》
# PyTorch 0.2 中文文档
PyTorch 是使用 GPU 和 CPU 优化的深度学习张量库。
## 贡献者
本项目由 [awfssv](https://github.com/awfssv), [ycszen](https://github.com/ycszen), [KeithYin](https://github.com/KeithYin), [kophy](https://github.com/kophy), [swordspoet](https://github.com/swordspoet), [dyl745001196](https://github.com/dyl745001196), [koshinryuu](https://github.com/koshinryuu), [tfygg](https://github.com/tfygg), [weigp](https://github.com/weigq), [ZijunDeng](https://github.com/ZijunDeng), [yichuan9527](https://github.com/yichuan9527) 等 PyTorch 爱好者发起,并已获得 PyTorch 官方授权。我们目的是建立 [PyTorch](https://pytorch.org/docs/) 的中文文档,并力所能及地提供更多的帮助和建议。
本项目网址为 [pytorch-cn](http://pytorch-cn.readthedocs.io/zh/latest/),文档翻译 QQ 群:628478868
如果你在使用 pytorch 和 pytorch-cn 的过程中有任何问题,欢迎在 issue 中讨论,可能你的问题也是别人的问题。
## 翻译进度
第一个名字代表翻译人,第二个代表审阅人
### Notes
- [x] Autograd mechanics (*ycszen*) (DL-ljw)
- [x] CUDA semantics (*ycszen*)
- [x] Extending PyTorch (*KeithYin*)
- [x] Multiprocessing best practices (*ycszen*)
- [x] Serialization semantics (*ycszen*)
### Package Reference
- [x] torch (*koshinryuu*) (飞彦)
- [x] torch.Tensor (*weigp*) (飞彦)
- [x] torch.Storage (*kophy*)
- [ ] **torch.nn**
- [x] Parameters (*KeithYin*)
- [x] Containers (*KeithYin*)
- [x] Convolution Layers (*yichuan9527*)
- [x] Pooling Layers (*yichuan9527*)
- [x] Non-linear Activations (*swordspoet*)
- [x] Normalization layers (*XavierLin*)
- [x] Recurrent layers (*KeithYin*) (Mosout)
- [x] Linear layers ( ) (Mosout)
- [x] Dropout layers ( ) (Mosout)
- [x] Sparse layers (Mosout)
- [x] Distance functions
- [x] Loss functions (*KeithYin*) (DL-ljw)
- [x] Vision layers (*KeithYin*)
- [x] Multi-GPU layers (*KeithYin*)
- [x] Utilities (*KeithYin*)
- [x] torch.nn.functional
- [x] Convolution functions (*ycszen*) (铁血丹心)
- [x] Pooling functions (*ycszen*) (铁血丹心)
- [x] Non-linear activations functions (*ycszen*)
- [x] Normalization functions (*ycszen*)
- [x] Linear functions (*dyl745001196*)
- [x] Dropout functions (*dyl745001196*)
- [x] Distance functions (*dyl745001196*)
- [x] Loss functions (*tfygg*) (DL-ljw)
- [x] Vision functions (*KeithYin*)
- [x] torch.nn.init (*kophy*) (luc)
- [x] torch.optim (*ZijunDeng*) (祁杰)
- [x] torch.autograd (*KeithYin*) (祁杰)
- [x] torch.multiprocessing (*songbo.han*)
- [x] torch.legacy (*ycszen*)
- [x] torch.cuda (*ycszen*)
- [x] torch.utils.ffi (*ycszen*)
- [x] torch.utils.data (*ycszen*)
- [x] torch.utils.model_zoo (*ycszen*)
### torchvision Reference
- [x] torchvision (*KeithYin*)
- [x] torchvision.datasets (*KeithYin*) (loop)
- [x] torchvision.models (*KeithYin*)
- [x] torchvision.transforms (*KeithYin*) (loop)
- [x] torchvision.utils (*KeithYin*)
* [PyTorch 0.2 中文文档](README.md)
* 说明
* [自动求导机制](notes/autograd.md)
* [CUDA语义](notes/cuda.md)
* [扩展PyTorch](notes/extending.md)
* [多进程最佳实践](notes/multiprocessing.md)
* [序列化语义](notes/serialization.md)
* PACKAGE参考
* [torch](package_references/torch.md)
* [torch.Tensor](package_references/Tensor.md)
* [torch.Storage](package_references/Storage.md)
* [torch.nn](package_references/torch-nn.md)
* [torch.nn.functional](package_references/functional.md)
* [torch.autograd](package_references/torch-autograd.md)
* [torch.optim](package_references/torch-optim.md)
* [torch.nn.init](package_references/nn_init.md)
* [torch.multiprocessing](package_references/torch-multiprocessing.md)
* [torch.legacy](package_references/legacy.md)
* [torch.cuda](package_references/torch-cuda.md)
* [torch.utils.ffi](package_references/ffi.md)
* [torch.utils.data](package_references/data.md)
* [torch.utils.model_zoo](package_references/model_zoo.md)
* TORCHVISION参考
* [torchvision](torchvision/torchvision.md)
* [torchvision.datasets](torchvision/torchvision-datasets.md)
* [torchvision.models](torchvision/torchvision-models.md)
* [torchvision.transforms](torchvision/torchvision-transform.md)
* [torchvision.utils](torchvision/torchvision-utils.md)
* [致谢](acknowledgement.md)
# 致谢
本项目贡献者如下:
## 文档翻译
| 贡献者 | 页面 | 章节 |
|:----:|:----:|:----:|
|ycszen|主页||
|ycszen|说明|自动求导机制|
|ycszen|说明|CUDA语义|
|KeithYin|说明|扩展PyTorch|
|ycszen|说明|多进程最佳实践|
|ycszen|说明|序列化语义|
|koshinryuu|package参考|torch|
|weigp|package参考|torch.Tensor|
|kophy|package参考|torch.Storage|
|KeithYin|package参考|torch.nn/Parameters|
|KeithYin|package参考|torch.nn/Containers|
|yichuan9527|package参考|torch.nn/Convolution Layers|
|yichuan9527|package参考|torch.nn/Pooling Layers|
|swordspoet|package参考|torch.nn/Non-linear Activations|
|XavierLin|package参考|torch.nn/Normalization layers|
|KeithYin|package参考|torch.nn/Recurrent layers|
||package参考|torch.nn/Linear layers|
||package参考|torch.nn/Dropout layers|
||package参考|torch.nn/Distance functions|
|KeithYin|package参考|torch.nn/Loss functions|
|KeithYin|package参考|torch.nn/Vision layers|
|KeithYin|package参考|torch.nn/Multi-GPU layers|
|KeithYin|package参考|torch.nn/Utilities|
|ycszen|package参考|torch.nn.functional/Convolution functions|
|ycszen|package参考|torch.nn.functional/Pooling function|
|ycszen|package参考|torch.nn.functional/Non-linear activations functions|
|ycszen|package参考|torch.nn.functional/Normalization functions|
|dyl745001196|package参考|torch.nn.functional/Linear functions|
|dyl745001196|package参考|torch.nn.functional/Dropout functions|
|dyl745001196|package参考|torch.nn.functional/Distance functions|
|tfygg|package参考|torch.nn.functinal/Loss functions|
|KeithYin|package参考|torch.nn.functional/Vision functions|
|kophy|package参考|torch.nn.init|
|KeithYin|package参考|torch.autograd|
|songbo.han|package参考|torch.multiprocessing|
|ZijunDeng|package参考|torch.optim|
|ycszen|pacakge参考|torch.legacy|
|ycszen|package参考|torch.cuda|
|ycszen|pacakge参考|torch.utils.ffi|
|ycszen|package参考|torch.utils.model_zoo|
|ycszen|package参考|torch.utils.data|
|KeithYin|torchvision参考|torchvision|
|KeithYin|torchvision参考|torchvision.datasets|
|KeithYin|torchvision参考|torchvision.models|
|KeithYin|torchvision参考|torchvision.transforms|
|KeithYin|torchvision参考|torchvision.utils|
|ycszen|致谢||
# 自动求导机制
本说明将概述Autograd如何工作并记录操作。了解这些并不是绝对必要的,但我们建议您熟悉它,因为它将帮助您编写更高效,更简洁的程序,并可帮助您进行调试。
## 从后向中排除子图
每个变量都有两个标志:`requires_grad``volatile`。它们都允许从梯度计算中精细地排除子图,并可以提高效率。
### `requires_grad`
如果有一个单一的输入操作需要梯度,它的输出也需要梯度。相反,只有所有输入都不需要梯度,输出才不需要。如果其中所有的变量都不需要梯度进行,后向计算不会在子图中执行。
```python
>>> 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`标志就足够了,直到计算到最后一层才会保存中间缓冲区,其中的仿射变换将使用需要梯度的权重并且网络的输出也将需要它们。
```python
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)
```
### `volatile`
纯粹的inference模式下推荐使用`volatile`,当你确定你甚至不会调用`.backward()`时。它比任何其他自动求导的设置更有效——它将使用绝对最小的内存来评估模型。`volatile`也决定了`require_grad is False`
`volatile`不同于`require_grad`的传递。如果一个操作甚至只有有一个`volatile`的输入,它的输出也将是`volatile``Volatility`比“不需要梯度”更容易传递——只需要一个`volatile`的输入即可得到一个`volatile`的输出,相对的,需要所有的输入“不需要梯度”才能得到不需要梯度的输出。使用volatile标志,您不需要更改模型参数的任何设置来用于inference。创建一个`volatile`的输入就够了,这将保证不会保存中间状态。
```python
>>> regular_input = Variable(torch.randn(5, 5))
>>> volatile_input = Variable(torch.randn(5, 5), volatile=True)
>>> model = torchvision.models.resnet18(pretrained=True)
>>> model(regular_input).requires_grad
True
>>> model(volatile_input).requires_grad
False
>>> model(volatile_input).volatile
True
>>> model(volatile_input).creator is None
True
```
## 自动求导如何编码历史信息
每个变量都有一个`.creator`属性,它指向把它作为输出的函数。这是一个由`Function`对象作为节点组成的有向无环图(DAG)的入口点,它们之间的引用就是图的边。每次执行一个操作时,一个表示它的新`Function`就被实例化,它的`forward()`方法被调用,并且它输出的`Variable`的创建者被设置为这个`Function`。然后,通过跟踪从任何变量到叶节点的路径,可以重建创建数据的操作序列,并自动计算梯度。
需要注意的一点是,整个图在每次迭代时都是从头开始重新创建的,这就允许使用任意的Python控制流语句,这样可以在每次迭代时改变图的整体形状和大小。在启动训练之前不必对所有可能的路径进行编码—— what you run is what you differentiate.
## Variable上的In-place操作
在自动求导中支持in-place操作是一件很困难的事情,我们在大多数情况下都不鼓励使用它们。Autograd的缓冲区释放和重用非常高效,并且很少场合下in-place操作能实际上明显降低内存的使用量。除非您在内存压力很大的情况下,否则您可能永远不需要使用它们。
限制in-place操作适用性主要有两个原因:
1.覆盖梯度计算所需的值。这就是为什么变量不支持`log_`。它的梯度公式需要原始输入,而虽然通过计算反向操作可以重新创建它,但在数值上是不稳定的,并且需要额外的工作,这往往会与使用这些功能的目的相悖。
2.每个in-place操作实际上需要实现重写计算图。不合适的版本只需分配新对象并保留对旧图的引用,而in-place操作则需要将所有输入的`creator`更改为表示此操作的`Function`。这就比较棘手,特别是如果有许多变量引用相同的存储(例如通过索引或转置创建的),并且如果被修改输入的存储被任何其他`Variable`引用,则in-place函数实际上会抛出错误。
## In-place正确性检查
每个变量保留有version counter,它每次都会递增,当在任何操作中被使用时。当`Function`保存任何用于后向的tensor时,还会保存其包含变量的version counter。一旦访问`self.saved_tensors`,它将被检查,如果它大于保存的值,则会引起错误。
# CUDA语义
`torch.cuda`会记录当前选择的GPU,并且分配的所有CUDA张量将在上面创建。可以使用`torch.cuda.device`上下文管理器更改所选设备。
但是,一旦张量被分配,您可以直接对其进行操作,而不考虑所选择的设备,结果将始终放在与张量相同的设备上。
默认情况下,不支持跨GPU操作,唯一的例外是`copy_()`。 除非启用对等存储器访问,否则对分布不同设备上的张量任何启动操作的尝试都将会引发错误。
下面你可以找到一个展示如下的小例子:
```python
x = torch.cuda.FloatTensor(1)
# x.get_device() == 0
y = torch.FloatTensor(1).cuda()
# y.get_device() == 0
with torch.cuda.device(1):
# allocates a tensor on GPU 1
a = torch.cuda.FloatTensor(1)
# transfers a tensor from CPU to GPU 1
b = torch.FloatTensor(1).cuda()
# a.get_device() == b.get_device() == 1
c = a + b
# c.get_device() == 1
z = x + y
# z.get_device() == 0
# even within a context, you can give a GPU id to the .cuda call
d = torch.randn(2).cuda(2)
# d.get_device() == 2
```
## 最佳实践
### 使用固定的内存缓冲区
当副本来自固定(页锁)内存时,主机到GPU的复制速度要快很多。CPU张量和存储开放了一个`pin_memory()`方法,它返回该对象的副本,而它的数据放在固定区域中。
另外,一旦固定了张量或存储,就可以使用异步的GPU副本。只需传递一个额外的`async=True`参数到`cuda()`的调用。这可以用于将数据传输与计算重叠。
通过将`pin_memory=True`传递给其构造函数,可以使`DataLoader`将batch返回到固定内存中。
### 使用 nn.DataParallel 替代 multiprocessing
大多数涉及批量输入和多个GPU的情况应默认使用`DataParallel`来使用多个GPU。尽管有GIL的存在,单个python进程也可能使多个GPU饱和。
从0.1.9版本开始,大量的GPU(8+)可能未被充分利用。然而,这是一个已知的问题,也正在积极开发。和往常一样,测试你的用例吧。
调用`multiprocessing`来利用CUDA模型存在重要的注意事项;使用具有并行处理功能的CUDA模型有重要的注意事项; 除非就是需要谨慎地满足数据处理需求,否则您的程序很可能会出现错误或未定义的行为。
# 扩展PyTorch
本篇文章中包含如何扩展 `torch.nn`, `torch.autograd`和 使用我们的 `C 库`编写自定义的`C`扩展。
## 扩展 torch.autograd
如果你想要添加一个新的 `Operation``autograd`的话,你的`Operation`需要继承 `class Function``autograd`使用`Function`计算结果和梯度,同时编码 `operation`的历史。每个新的 `operation(function)` 都需要实现三个方法:
- `__init__ (optional)` - 如果你的`operation`包含非`Variable`参数,那么就将其作为`__init__`的参数传入到`operation`中。例如:`AddConstant Function`加一个常数,`Transpose Function`需要指定哪两个维度需要交换。如果你的`operation`不需要额外的参数,你可以忽略`__init__`
- `forward()` - 在里面写执行此`operation`的代码。可以有任意数量的参数。如果你对某些参数指定了默认值,则这些参数是可传可不传的。记住:`forward()`的参数只能是`Variable`。函数的返回值既可以是 `Variable`也可以是`Variables``tuple`。同时,请参考 `Function`[function]的 `doc`,查阅有哪些 方法是只能在`forward`中调用的。
- `backward()` - 梯度计算公式。 参数的个数和`forward`返回值的个数一样,每个参数代表传回到此`operation`的梯度. `backward()`的返回值的个数应该和此`operation`输入的个数一样,每个返回值对应了输入值的梯度。如果`operation`的输入不需要梯度,或者不可导,你可以返回`None`。 如果`forward()`存在可选参数,你可以返回比输入更多的梯度,只是返回的是`None`
下面是 `Linear` 的实现代码:
```python
# Inherit from Function
class Linear(Function):
# bias is an optional argument
def forward(self, input, weight, bias=None):
self.save_for_backward(input, weight, bias)
output = input.mm(weight.t())
if bias is not None:
output += bias.unsqueeze(0).expand_as(output)
return output
# This function has only a single output, so it gets only one gradient
def backward(self, grad_output):
# This is a pattern that is very convenient - at the top of backward
# unpack saved_tensors and initialize all gradients w.r.t. inputs to
# None. Thanks to the fact that additional trailing Nones are
# ignored, the return statement is simple even when the function has
# optional inputs.
input, weight, bias = self.saved_tensors
grad_input = grad_weight = grad_bias = None
# These needs_input_grad checks are optional and there only to
# improve efficiency. If you want to make your code simpler, you can
# skip them. Returning gradients for inputs that don't require it is
# not an error.
if self.needs_input_grad[0]:
grad_input = grad_output.mm(weight)
if self.needs_input_grad[1]:
grad_weight = grad_output.t().mm(input)
if bias is not None and self.needs_input_grad[2]:
grad_bias = grad_output.sum(0).squeeze(0)
return grad_input, grad_weight, grad_bias
```
现在,为了可以更简单的使用自定义的`operation`,我们建议将其用一个简单的 `helper function` 包装起来。 functions:
```python
def linear(input, weight, bias=None):
# First braces create a Function object. Any arguments given here
# will be passed to __init__. Second braces will invoke the __call__
# operator, that will then use forward() to compute the result and
# return it.
return Linear()(input, weight, bias)
```
你可能想知道你刚刚实现的 `backward`方法是否正确的计算了梯度。你可以使用 小的有限的差分进行数值估计。
```python
from torch.autograd import gradcheck
# gradchek takes a tuple of tensor as input, check if your gradient
# evaluated with these tensors are close enough to numerical
# approximations and returns True if they all verify this condition.
input = (Variable(torch.randn(20,20).double(), requires_grad=True),)
test = gradcheck.gradcheck(Linear(), input, eps=1e-6, atol=1e-4)
print(test)
```
## 扩展 torch.nn
`nn` 包含两种接口 - `modules`和他们的`functional`版本。通过这两个接口,你都可以扩展`nn`。但是我们建议,在扩展`layer`的时候,使用`modules`, 因为`modules`保存着参数和`buffer`。如果不需要参数的话,那么建议使用`functional`(激活函数,pooling,这些都不需要参数)。
增加一个`operation``functional`版本已经在上面一节介绍完毕。
增加一个模块(`module`)。
由于`nn`重度使用`autograd`。所以,添加一个新`module`需要实现一个 用来执行 计算 和 计算梯度 的`Function`。从现在开始,假定我们想要实现一个`Linear module`,记得之前我们已经实现了一个`Linear Funciton`。 只需要很少的代码就可以完成这个工作。 现在,我们需要实现两个方法:
- `__init__ (optional)` - 输入参数,例如`kernel sizes`, `numbers of features`, 等等。同时初始化 `parameters``buffers`
- `forward()` - 实例化一个执行`operation``Function`,使用它执行`operation`。和`functional wrapper(上面实现的那个简单的wrapper)`十分类似。
`Linear module`实现代码:
```python
class Linear(nn.Module):
def __init__(self, input_features, output_features, bias=True):
self.input_features = input_features
self.output_features = output_features
# nn.Parameter is a special kind of Variable, that will get
# automatically registered as Module's parameter once it's assigned
# as an attribute. Parameters and buffers need to be registered, or
# they won't appear in .parameters() (doesn't apply to buffers), and
# won't be converted when e.g. .cuda() is called. You can use
# .register_buffer() to register buffers.
# nn.Parameters can never be volatile and, different than Variables,
# they require gradients by default.
self.weight = nn.Parameter(torch.Tensor(input_features, output_features))
if bias:
self.bias = nn.Parameter(torch.Tensor(output_features))
else:
# You should always register all possible parameters, but the
# optional ones can be None if you want.
self.register_parameter('bias', None)
# Not a very smart way to initialize weights
self.weight.data.uniform_(-0.1, 0.1)
if bias is not None:
self.bias.data.uniform_(-0.1, 0.1)
def forward(self, input):
# See the autograd section for explanation of what happens here.
return Linear()(input, self.weight, self.bias)
#注意这个Linear是之前实现过的Linear
```
## 编写自定义`C`扩展
Coming soon. For now you can find an example at [GitHub](https://github.com/pytorch/extension-ffi).
# 多进程最佳实践
`torch.multiprocessing`是Python`multiprocessing`的替代品。它支持完全相同的操作,但扩展了它以便通过`multiprocessing.Queue`发送的所有张量将其数据移动到共享内存中,并且只会向其他进程发送一个句柄。
> **Note**
>
> 当`Variable`发送到另一个进程时,`Variable.data`和`Variable.grad.data`都将被共享。
这允许实现各种训练方法,如Hogwild,A3C或需要异步操作的任何其他方法。
## 共享CUDA张量
仅在Python 3中使用`spawn``forkserver`启动方法才支持在进程之间共享CUDA张量。Python 2中的`multiprocessing`只能使用`fork`创建子进程,并且不被CUDA运行时所支持。
>**Warning**
>
>CUDA API要求导出到其他进程的分配,只要它们被使用就要一直保持有效。您应该小心,确保您共享的CUDA张量只要有必要就不要超出范围。这不是共享模型参数的问题,但传递其他类型的数据应该小心。注意,此限制不适用于共享CPU内存。
参考:[使用 nn.DataParallel 替代 multiprocessing](cuda.md)
## 最佳实践和提示
### 避免和抵制死锁
当一个新进程被产生时,有很多事情可能会出错,最常见的死锁原因是后台线程。如果有任何线程持有锁或导入模块,并且`fork`被调用,则子进程很可能处于损坏的状态,并以不同的方式死锁或失败。注意,即使您没有,Python内置的库也可能会这样做 —— 不需要看得比`multiprocessing`更远。`multiprocessing.Queue`实际上是一个非常复杂的类,它产生用于序列化,发送和接收对象的多个线程,它们也可能引起上述问题。如果您发现自己处于这种情况,请尝试使用`multiprocessing.queues.SimpleQueue`,这不会使用任何其他线程。
我们正在竭尽全力把它设计得更简单,并确保这些死锁不会发生,但有些事情无法控制。如果有任何问题您无法一时无法解决,请尝试在论坛上提出,我们将看看是否可以解决问题。
### 重用经过队列的缓冲区
记住每次将`Tensor`放入`multiprocessing.Queue`时,必须将其移动到共享内存中。如果它已经被共享,它是一个无效的操作,否则会产生一个额外的内存副本,这会减缓整个进程。即使你有一个进程池来发送数据到一个进程,使它返回缓冲区 —— 这几乎是免费的,并且允许你在发送下一个batch时避免产生副本。
### 异步多进程训练(例如Hogwild)
使用`torch.multiprocessing`,可以异步地训练模型,参数可以一直共享,也可以定期同步。在第一种情况下,我们建议发送整个模型对象,而在后者中,我们建议只发送`state_dict()`
我们建议使用`multiprocessing.Queue`来在进程之间传递各种PyTorch对象。例如, 当使用fork启动方法时,可能会继承共享内存中的张量和存储器,但这是非常容易出错的,应谨慎使用,而且只能由高级用户使用。队列虽然有时是一个较不优雅的解决方案,但基本上能在所有情况下正常工作。
> **Warning**
> 你应该注意有关全局语句,它们没有被`if __name__ == '__main__'`保护。如果使用与`fork`不同的启动方法,则它们将在所有子进程中执行。
#### Hogwild
[examples repository](https://github.com/pytorch/examples/tree/master/mnist_hogwild)中可以找到具体的Hogwild实现,可以展示代码的整体结构。下面也有一个小例子:
```Python
import torch.multiprocessing as mp
from model import MyModel
def train(model):
# Construct data_loader, optimizer, etc.
for data, labels in data_loader:
optimizer.zero_grad()
loss_fn(model(data), labels).backward()
optimizer.step() # This will update the shared parameters
if __name__ == '__main__':
num_processes = 4
model = MyModel()
# NOTE: this is required for the ``fork`` method to work
model.share_memory()
processes = []
for rank in range(num_processes):
p = mp.Process(target=train, args=(model,))
p.start()
processes.append(p)
for p in processes:
p.join()
```
# 序列化语义
## 最佳实践
### 保存模型的推荐方法
这主要有两种方法序列化和恢复模型。
第一种(推荐)只保存和加载模型参数:
```python
torch.save(the_model.state_dict(), PATH)
```
然后:
```python
the_model = TheModelClass(*args, **kwargs)
the_model.load_state_dict(torch.load(PATH))
```
第二种保存和加载整个模型:
```python
torch.save(the_model, PATH)
```
然后:
```python
the_model = torch.load(PATH)
```
然而,在这种情况下,序列化的数据被绑定到特定的类和固定的目录结构,所以当在其他项目中使用时,或者在一些严重的重构器之后它可能会以各种方式break。
# torch.Storage
一个`torch.Storage`是一个单一数据类型的连续一维数组。
每个`torch.Tensor`都有一个对应的、相同数据类型的存储。
```python
class torch.FloatStorage
```
#### byte()
将此存储转为byte类型
#### char()
将此存储转为char类型
#### clone()
返回此存储的一个副本
#### copy_()
#### cpu()
如果当前此存储不在CPU上,则返回一个它的CPU副本
#### cuda(*device=None, async=False*)
返回此对象在CUDA内存中的一个副本。
如果此对象已在CUDA内存中且在正确的设备上,那么不会执行复制操作,直接返回原对象。
**参数:**
- **device** (*[int]()*) - 目标GPU的id。默认值是当前设备。
- **async** (*[bool]()*) -如果值为True,且源在锁定内存中,则副本相对于宿主是异步的。否则此参数不起效果。
#### data_ptr()
#### double()
将此存储转为double类型
#### element_size()
#### fill_()
#### float()
将此存储转为float类型
#### from_buffer()
#### half()
将此存储转为half类型
#### int()
将此存储转为int类型
#### is_cuda = *False*
#### is_pinned()
#### is_shared()
#### is_sparse = *False*
#### long()
将此存储转为long类型
#### new()
#### pin_memory()
如果此存储当前未被锁定,则将它复制到锁定内存中。
#### resize_()
#### share_memory_()
将此存储移动到共享内存中。
对于已经在共享内存中的存储或者CUDA存储,这是一条空指令,它们不需要移动就能在进程间共享。共享内存中的存储不能改变大小。
返回:self
#### short()
将此存储转为short类型
#### size()
#### tolist()
返回一个包含此存储中元素的列表
#### type(*new_type=None, async=False*)
将此对象转为指定类型。
如果已经是正确类型,不会执行复制操作,直接返回原对象。
**参数:**
- **new_type** (*[type]() or [string]()*) -需要转成的类型
- **async** (*[bool]()*) -如果值为True,且源在锁定内存中而目标在GPU中——或正好相反,则复制操作相对于宿主异步执行。否则此参数不起效果。
\ No newline at end of file
此差异已折叠。
# torch.utils.data
```python
class torch.utils.data.Dataset
```
表示Dataset的抽象类。
所有其他数据集都应该进行子类化。所有子类应该override`__len__``__getitem__`,前者提供了数据集的大小,后者支持整数索引,范围从0到len(self)。
```python
class torch.utils.data.TensorDataset(data_tensor, target_tensor)
```
包装数据和目标张量的数据集。
通过沿着第一个维度索引两个张量来恢复每个样本。
**参数:**
- **data_tensor** (*Tensor*) - 包含样本数据
- **target_tensor** (*Tensor*) - 包含样本目标(标签)
```python
class torch.utils.data.DataLoader(dataset, batch_size=1, shuffle=False, sampler=None, num_workers=0, collate_fn=<function default_collate>, pin_memory=False, drop_last=False)
```
数据加载器。组合数据集和采样器,并在数据集上提供单进程或多进程迭代器。
**参数:**
- **dataset** (*Dataset*) – 加载数据的数据集。
- **batch_size** (*int*, optional) – 每个batch加载多少个样本(默认: 1)。
- **shuffle** (*bool*, optional) – 设置为`True`时会在每个epoch重新打乱数据(默认: False).
- **sampler** (*Sampler*, optional) – 定义从数据集中提取样本的策略。如果指定,则忽略`shuffle`参数。
- **num_workers** (*int*, optional) – 用多少个子进程加载数据。0表示数据将在主进程中加载(默认: 0)
- **collate_fn** (*callable*, optional) –
- **pin_memory** (*bool*, optional) –
- **drop_last** (*bool*, optional) – 如果数据集大小不能被batch size整除,则设置为True后可删除最后一个不完整的batch。如果设为False并且数据集的大小不能被batch size整除,则最后一个batch将更小。(默认: False)
```python
class torch.utils.data.sampler.Sampler(data_source)
```
所有采样器的基础类。
每个采样器子类必须提供一个`__iter__`方法,提供一种迭代数据集元素的索引的方法,以及返回迭代器长度的`__len__`方法。
```python
class torch.utils.data.sampler.SequentialSampler(data_source)
```
样本元素顺序排列,始终以相同的顺序。
**参数:**
- **data_source** (*Dataset*) – 采样的数据集。
```python
class torch.utils.data.sampler.RandomSampler(data_source)
```
样本元素随机,没有替换。
**参数:**
- **data_source** (*Dataset*) – 采样的数据集。
```python
class torch.utils.data.sampler.SubsetRandomSampler(indices)
```
样本元素从指定的索引列表中随机抽取,没有替换。
**参数:**
- **indices** (*list*) – 索引的列表
```python
class torch.utils.data.sampler.WeightedRandomSampler(weights, num_samples, replacement=True)
```
样本元素来自于[0,..,len(weights)-1],给定概率(weights)。
**参数:**
- **weights** (*list*) – 权重列表。没必要加起来为1
- **num_samples** (*int*) – 抽样数量
# torch.utils.ffi
```python
torch.utils.ffi.create_extension(name, headers, sources, verbose=True, with_cuda=False, package=False, relative_to='.', **kwargs)
```
创建并配置一个cffi.FFI对象,用于PyTorch的扩展。
**参数:**
- **name** (*str*) – 包名。可以是嵌套模块,例如 `.ext.my_lib`
- **headers** (*str* or List[*str*]) – 只包含导出函数的头文件列表
- **sources** (List[*str*]) – 用于编译的sources列表
- **verbose** (*bool*, optional) – 如果设置为False,则不会打印输出(默认值:`True`)。
- **with_cuda** (*bool*, optional) – 设置为True以使用CUDA头文件进行编译(默认值:`False`)。
- **package** (*bool*, optional) – 设置为True以在程序包模式下构建(对于要作为pip程序包安装的模块)(默认值:`False`)。
- **relative_to** (*str*, optional) –构建文件的路径。`package``True`时需要。最好使用`__file__`作为参数。
- **kwargs** – 传递给ffi以声明扩展的附加参数。有关详细信息,请参阅[Extension API reference](https://docs.python.org/3/distutils/apiref.html#distutils.core.Extension)
# torch.nn.functional
## Convolution 函数
```python
torch.nn.functional.conv1d(input, weight, bias=None, stride=1, padding=0, dilation=1, groups=1)
```
对几个输入平面组成的输入信号应用1D卷积。
有关详细信息和输出形状,请参见`Conv1d`
**参数:**
- **input** – 输入张量的形状 (minibatch x in_channels x iW)
- **weight** – 过滤器的形状 (out_channels, in_channels, kW)
- **bias** – 可选偏置的形状 (out_channels)
- **stride** – 卷积核的步长,默认为1
**例子:**
```python
>>> filters = autograd.Variable(torch.randn(33, 16, 3))
>>> inputs = autograd.Variable(torch.randn(20, 16, 50))
>>> F.conv1d(inputs, filters)
```
```python
torch.nn.functional.conv2d(input, weight, bias=None, stride=1, padding=0, dilation=1, groups=1)
```
对几个输入平面组成的输入信号应用2D卷积。
有关详细信息和输出形状,请参见`Conv2d`
**参数:**
- **input** – 输入张量 (minibatch x in_channels x iH x iW)
- **weight** – 过滤器张量 (out_channels, in_channels/groups, kH, kW)
- **bias** – 可选偏置张量 (out_channels)
- **stride** – 卷积核的步长,可以是单个数字或一个元组 (sh x sw)。默认为1
- **padding** – 输入上隐含零填充。可以是单个数字或元组。 默认值:0
- **groups** – 将输入分成组,in_channels应该被组数除尽
**例子:**
```python
>>> # With square kernels and equal stride
>>> filters = autograd.Variable(torch.randn(8,4,3,3))
>>> inputs = autograd.Variable(torch.randn(1,4,5,5))
>>> F.conv2d(inputs, filters, padding=1)
```
```python
torch.nn.functional.conv3d(input, weight, bias=None, stride=1, padding=0, dilation=1, groups=1)
```
对几个输入平面组成的输入信号应用3D卷积。
有关详细信息和输出形状,请参见`Conv3d`
**参数:**
- **input** – 输入张量的形状 (minibatch x in_channels x iT x iH x iW)
- **weight** – 过滤器张量的形状 (out_channels, in_channels, kT, kH, kW)
- **bias** – 可选偏置张量的形状 (out_channels)
- **stride** – 卷积核的步长,可以是单个数字或一个元组 (sh x sw)。默认为1
- **padding** – 输入上隐含零填充。可以是单个数字或元组。 默认值:0
**例子:**
```python
>>> filters = autograd.Variable(torch.randn(33, 16, 3, 3, 3))
>>> inputs = autograd.Variable(torch.randn(20, 16, 50, 10, 20))
>>> F.conv3d(inputs, filters)
```
```python
torch.nn.functional.conv_transpose1d(input, weight, bias=None, stride=1, padding=0, output_padding=0, groups=1)
```
```python
torch.nn.functional.conv_transpose2d(input, weight, bias=None, stride=1, padding=0, output_padding=0, groups=1)
```
在由几个输入平面组成的输入图像上应用二维转置卷积,有时也称为“去卷积”。
有关详细信息和输出形状,请参阅`ConvTranspose2d`
**参数:**
- **input** – 输入张量的形状 (minibatch x in_channels x iH x iW)
- **weight** – 过滤器的形状 (in_channels x out_channels x kH x kW)
- **bias** – 可选偏置的形状 (out_channels)
- **stride** – 卷积核的步长,可以是单个数字或一个元组 (sh x sw)。默认: 1
- **padding** – 输入上隐含零填充。可以是单个数字或元组。 (padh x padw)。默认: 0
- **groups** – 将输入分成组,`in_channels`应该被组数除尽
- **output_padding** – 0 <= padding <stride的零填充,应该添加到输出。可以是单个数字或元组。默认值:0
```python
torch.nn.functional.conv_transpose3d(input, weight, bias=None, stride=1, padding=0, output_padding=0, groups=1)
```
在由几个输入平面组成的输入图像上应用三维转置卷积,有时也称为“去卷积”。
有关详细信息和输出形状,请参阅`ConvTranspose3d`
**参数:**
- **input** – 输入张量的形状 (minibatch x in_channels x iT x iH x iW)
- **weight** – 过滤器的形状 (in_channels x out_channels x kH x kW)
- **bias** – 可选偏置的形状 (out_channels)
- **stride** – 卷积核的步长,可以是单个数字或一个元组 (sh x sw)。默认: 1
- **padding** – 输入上隐含零填充。可以是单个数字或元组。 (padh x padw)。默认: 0
## Pooling 函数
```python
torch.nn.functional.avg_pool1d(input, kernel_size, stride=None, padding=0, ceil_mode=False, count_include_pad=True)
```
对由几个输入平面组成的输入信号进行一维平均池化。
有关详细信息和输出形状,请参阅`AvgPool1d`
**参数:**
- **kernel_size** – 窗口的大小
- **stride** – 窗口的步长。默认值为`kernel_size`
- **padding** – 在两边添加隐式零填充
- **ceil_mode** – 当为True时,将使用`ceil`代替`floor`来计算输出形状
- **count_include_pad** – 当为True时,这将在平均计算时包括补零
**例子:**
```python
>>> # pool of square window of size=3, stride=2
>>> input = Variable(torch.Tensor([[[1,2,3,4,5,6,7]]]))
>>> F.avg_pool1d(input, kernel_size=3, stride=2)
Variable containing:
(0 ,.,.) =
2 4 6
[torch.FloatTensor of size 1x1x3]
```
```python
torch.nn.functional.avg_pool2d(input, kernel_size, stride=None, padding=0, ceil_mode=False, count_include_pad=True)
```
在kh x kw区域中应用步长为dh x dw的二维平均池化操作。输出特征的数量等于输入平面的数量。
有关详细信息和输出形状,请参阅`AvgPool2d`
**参数:**
- **input** – 输入的张量 (minibatch x in_channels x iH x iW)
- **kernel_size** – 池化区域的大小,可以是单个数字或者元组 (kh x kw)
- **stride** – 池化操作的步长,可以是单个数字或者元组 (sh x sw)。默认等于核的大小
- **padding** – 在输入上隐式的零填充,可以是单个数字或者一个元组 (padh x padw),默认: 0
- **ceil_mode** – 定义空间输出形状的操作
- **count_include_pad** – 除以原始非填充图像内的元素数量或kh * kw
```python
torch.nn.functional.avg_pool3d(input, kernel_size, stride=None)
```
在kt x kh x kw区域中应用步长为dt x dh x dw的二维平均池化操作。输出特征的数量等于 input planes / dt。
```python
torch.nn.functional.max_pool1d(input, kernel_size, stride=None, padding=0, dilation=1, ceil_mode=False, return_indices=False)
```
```python
torch.nn.functional.max_pool2d(input, kernel_size, stride=None, padding=0, dilation=1, ceil_mode=False, return_indices=False)
```
```python
torch.nn.functional.max_pool3d(input, kernel_size, stride=None, padding=0, dilation=1, ceil_mode=False, return_indices=False)
```
```python
torch.nn.functional.max_unpool1d(input, indices, kernel_size, stride=None, padding=0, output_size=None)
```
```python
torch.nn.functional.max_unpool2d(input, indices, kernel_size, stride=None, padding=0, output_size=None)
```
```python
torch.nn.functional.max_unpool3d(input, indices, kernel_size, stride=None, padding=0, output_size=None)
```
```python
torch.nn.functional.lp_pool2d(input, norm_type, kernel_size, stride=None, ceil_mode=False)
```
```python
torch.nn.functional.adaptive_max_pool1d(input, output_size, return_indices=False)
```
在由几个输入平面组成的输入信号上应用1D自适应最大池化。
有关详细信息和输出形状,请参阅`AdaptiveMaxPool1d`
**参数:**
- **output_size** – 目标输出大小(单个整数)
- **return_indices** – 是否返回池化的指数
```python
torch.nn.functional.adaptive_max_pool2d(input, output_size, return_indices=False)
```
在由几个输入平面组成的输入信号上应用2D自适应最大池化。
有关详细信息和输出形状,请参阅`AdaptiveMaxPool2d`
**参数:**
- **output_size** – 目标输出大小(单整数或双整数元组)
- **return_indices** – 是否返回池化的指数
```python
torch.nn.functional.adaptive_avg_pool1d(input, output_size)
```
在由几个输入平面组成的输入信号上应用1D自适应平均池化。
有关详细信息和输出形状,请参阅`AdaptiveAvgPool1d`
**参数:**
- **output_size** – 目标输出大小(单整数或双整数元组)
```python
torch.nn.functional.adaptive_avg_pool2d(input, output_size)
```
在由几个输入平面组成的输入信号上应用2D自适应平均池化。
有关详细信息和输出形状,请参阅`AdaptiveAvgPool2d`
**参数:**
- **output_size** – 目标输出大小(单整数或双整数元组)
## 非线性激活函数
```python
torch.nn.functional.threshold(input, threshold, value, inplace=False)
```
```python
torch.nn.functional.relu(input, inplace=False)
```
```python
torch.nn.functional.hardtanh(input, min_val=-1.0, max_val=1.0, inplace=False)
```
```python
torch.nn.functional.relu6(input, inplace=False)
```
```python
torch.nn.functional.elu(input, alpha=1.0, inplace=False)
```
```python
torch.nn.functional.leaky_relu(input, negative_slope=0.01, inplace=False)
```
```python
torch.nn.functional.prelu(input, weight)
```
```python
torch.nn.functional.rrelu(input, lower=0.125, upper=0.3333333333333333, training=False, inplace=False)
```
```python
torch.nn.functional.logsigmoid(input)
```
```python
torch.nn.functional.hardshrink(input, lambd=0.5)
```
```python
torch.nn.functional.tanhshrink(input)
```
```python
torch.nn.functional.softsign(input)
```
```python
torch.nn.functional.softplus(input, beta=1, threshold=20)
```
```python
torch.nn.functional.softmin(input)
```
```python
torch.nn.functional.softmax(input)
```
```python
torch.nn.functional.softshrink(input, lambd=0.5)
```
```python
torch.nn.functional.log_softmax(input)
```
```python
torch.nn.functional.tanh(input)
```
```python
torch.nn.functional.sigmoid(input)
```
## Normalization 函数
```python
torch.nn.functional.batch_norm(input, running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-05)
```
## 线性函数
```python
torch.nn.functional.linear(input, weight, bias=None)
```
## Dropout 函数
```python
torch.nn.functional.dropout(input, p=0.5, training=False, inplace=False)
```
## 距离函数(Distance functions)
```python
torch.nn.functional.pairwise_distance(x1, x2, p=2, eps=1e-06)
```
计算向量v1、v2之间的距离(成次或者成对,意思是可以计算多个,可以参看后面的参数)
$$
\left \| x \right \|_{p}:=\left ( \sum_{i=1}^{N}\left | x_{i}^{p} \right | \right )^{1/p}
$$
**参数:**
* x1:第一个输入的张量
* x2:第二个输入的张量
* p:矩阵范数的维度。默认值是2,即二范数。
**规格:**
- 输入:(N,D)其中D等于向量的维度
- 输出:(N,1)
**例子:**
```python
>>> input1 = autograd.Variable(torch.randn(100, 128))
>>> input2 = autograd.Variable(torch.randn(100, 128))
>>> output = F.pairwise_distance(input1, input2, p=2)
>>> output.backward()
```
## 损失函数(Loss functions)
```python
torch.nn.functional.nll_loss(input, target, weight=None, size_average=True)
```
负的log likelihood损失函数. 详细请看[NLLLoss](...).
**参数:**
- **input** - (N,C) C 是类别的个数
- **target** - (N) 其大小是 0 <= targets[i] <= C-1
- **weight** (Variable, optional) – 一个可手动指定每个类别的权重。如果给定的话,必须是大小为nclasses的Variable
- **size_average** (bool, optional) – 默认情况下,是``mini-batch``loss的平均值,然而,如果size_average=False,则是``mini-batch``loss的总和。
**Variables:**
- **weight** – 对于constructor而言,每一类的权重作为输入
```python
torch.nn.functional.kl_div(input, target, size_average=True)
```
KL 散度损失函数,详细请看[KLDivLoss](...)
**参数:**
- **input** – 任意形状的 Variable
- **target** – 与输入相同形状的 Variable
- **size_average** – 如果为TRUE,loss则是平均值,需要除以输入 tensor 中 element 的数目
```python
torch.nn.functional.cross_entropy(input, target, weight=None, size_average=True)
```
该函数使用了 log_softmax 和 nll_loss,详细请看[CrossEntropyLoss](...)
**参数:**
- **input** - (N,C) 其中,C 是类别的个数
- **target** - (N) 其大小是 0 <= targets[i] <= C-1
- **weight** (Variable, optional) – 一个可手动指定每个类别的权重。如果给定的话,必须是大小为nclasses的Variable
- **size_average** (bool, optional) – 默认情况下,是``mini-batch``loss的平均值,然而,如果size_average=False,则是``mini-batch``loss的总和。
```python
torch.nn.functional.binary_cross_entropy(input, target, weight=None, size_average=True)
```
该函数计算了输出与target之间的二进制交叉熵,详细请看[BCELoss](...)
**参数:**
- **input** – 任意形状的 Variable
- **target** – 与输入相同形状的 Variable
- **weight** (Variable, optional) – 一个可手动指定每个类别的权重。如果给定的话,必须是大小为nclasses的Variable
- **size_average** (bool, optional) – 默认情况下,是``mini-batch``loss的平均值,然而,如果size_average=False,则是``mini-batch``loss的总和。
```python
torch.nn.functional.smooth_l1_loss(input, target, size_average=True)
```
## Vision functions
### torch.nn.functional.pixel_shuffle(input, upscale_factor)[source]
将形状为`[*, C*r^2, H, W]``Tensor`重新排列成形状为`[C, H*r, W*r]`的Tensor.
详细请看[PixelShuffle](..).
形参说明:
- input (Variable) – 输入
- upscale_factor (int) – 增加空间分辨率的因子.
例子:
```python
ps = nn.PixelShuffle(3)
input = autograd.Variable(torch.Tensor(1, 9, 4, 4))
output = ps(input)
print(output.size())
torch.Size([1, 1, 12, 12])
```
### torch.nn.functional.pad(input, pad, mode='constant', value=0)[source]
填充`Tensor`.
目前为止,只支持`2D``3D`填充.
Currently only 2D and 3D padding supported.
当输入为`4D Tensor`的时候,`pad`应该是一个4元素的`tuple (pad_l, pad_r, pad_t, pad_b )` ,当输入为`5D Tensor`的时候,`pad`应该是一个6元素的`tuple (pleft, pright, ptop, pbottom, pfront, pback)`.
形参说明:
- input (Variable) – 4D 或 5D `tensor`
- pad (tuple) – 4元素 或 6-元素 `tuple`
- mode – 'constant', 'reflect' or 'replicate'
- value – 用于`constant padding` 的值.
# 遗产包 - torch.legacy
此包中包含从Lua Torch移植来的代码。
为了可以使用现有的模型并且方便当前Lua Torch使用者过渡,我们创建了这个包。 可以在`torch.legacy.nn`中找到`nn`代码,并在`torch.legacy.optim`中找到`optim`代码。 API应该完全匹配Lua Torch。
# torch.utils.model_zoo
```python
torch.utils.model_zoo.load_url(url, model_dir=None)
```
在给定URL上加载Torch序列化对象。
如果对象已经存在于 *model_dir* 中,则将被反序列化并返回。URL的文件名部分应遵循命名约定`filename-<sha256>.ext`,其中`<sha256>`是文件内容的SHA256哈希的前八位或更多位数字。哈希用于确保唯一的名称并验证文件的内容。
*model_dir* 的默认值为`$TORCH_HOME/models`,其中`$TORCH_HOME`默认为`~/.torch`。可以使用`$TORCH_MODEL_ZOO`环境变量来覆盖默认目录。
**参数:**
- **url** (*string*) - 要下载对象的URL
- **model_dir** (*string*, optional) - 保存对象的目录
**例子:**
```python
>>> state_dict = torch.utils.model_zoo.load_url('https://s3.amazonaws.com/pytorch/models/resnet18-5c106cde.pth')
```
# torch.nn.init
```python
torch.nn.init.calculate_gain(nonlinearity,param=None)
```
对于给定的非线性函数,返回推荐的增益值。这些值如下所示:
| nonlinearity | gain |
| ------------ | ---------------------------- |
| linear | 1 |
| conv{1,2,3}d | 1 |
| sigmoid | 1 |
| tanh | 5/3 |
| relu | sqrt(2) |
| leaky_relu | sqrt(2/(1+negative_slope^2)) |
**参数:**
- **nonlinearity** - 非线性函数(`nn.functional`名称)
- **param** - 非线性函数的可选参数
**例子:**
```python
>>> gain = nn.init.gain('leaky_relu')
```
```python
torch.nn.init.uniform(tensor, a=0, b=1)
```
从均匀分布U(a, b)中生成值,填充输入的张量或变量
**参数:**
- **tensor** - n维的torch.Tensor
- **a** - 均匀分布的下界
- **b** - 均匀分布的上界
**例子**
```python
>>> w = torch.Tensor(3, 5)
>>> nn.init.uniform(w)
```
```python
torch.nn.init.normal(tensor, mean=0, std=1)
```
从给定均值和标准差的正态分布N(mean, std)中生成值,填充输入的张量或变量
**参数:**
- **tensor** – n维的torch.Tensor
- **mean** – 正态分布的均值
- **std** – 正态分布的标准差
**例子**
```python
>>> w = torch.Tensor(3, 5)
>>> nn.init.normal(w)
```
```python
torch.nn.init.constant(tensor, val)
```
*val*的值填充输入的张量或变量
**参数:**
- **tensor** – n维的torch.Tensor或autograd.Variable
- **val** – 用来填充张量的值
**例子:**
```python
>>> w = torch.Tensor(3, 5)
>>> nn.init.constant(w)
```
```python
torch.nn.init.eye(tensor)
```
用单位矩阵来填充2维输入张量或变量。在线性层尽可能多的保存输入特性。
**参数:**
- **tensor** – 2维的torch.Tensor或autograd.Variable
**例子:**
```python
>>> w = torch.Tensor(3, 5)
>>> nn.init.eye(w)
```
```python
torch.nn.init.dirac(tensor)
```
用Dirac $\delta$ 函数来填充{3, 4, 5}维输入张量或变量。在卷积层尽可能多的保存输入通道特性。
**参数:**
- **tensor** – {3, 4, 5}维的torch.Tensor或autograd.Variable
**例子:**
```python
>>> w = torch.Tensor(3, 16, 5, 5)
>>> nn.init.dirac(w)
```
```python
torch.nn.init.xavier_uniform(tensor, gain=1)
```
根据Glorot, X.和Bengio, Y.在“Understanding the difficulty of training deep feedforward neural networks”中描述的方法,用一个均匀分布生成值,填充输入的张量或变量。结果张量中的值采样自U(-a, a),其中a= gain * sqrt( 2/(fan_in + fan_out))* sqrt(3). 该方法也被称为Glorot initialisation
**参数:**
- **tensor** – n维的torch.Tensor
- **gain** - 可选的缩放因子
**例子:**
```python
>>> w = torch.Tensor(3, 5)
>>> nn.init.xavier_uniform(w, gain=math.sqrt(2.0))
```
```python
torch.nn.init.xavier_normal(tensor, gain=1)
```
根据Glorot, X.和Bengio, Y. 于2010年在“Understanding the difficulty of training deep feedforward neural networks”中描述的方法,用一个正态分布生成值,填充输入的张量或变量。结果张量中的值采样自均值为0,标准差为gain * sqrt(2/(fan_in + fan_out))的正态分布。也被称为Glorot initialisation.
**参数:**
- **tensor** – n维的torch.Tensor
- **gain** - 可选的缩放因子
**例子:**
```python
>>> w = torch.Tensor(3, 5)
>>> nn.init.xavier_normal(w)
```
```python
torch.nn.init.kaiming_uniform(tensor, a=0, mode='fan_in')
```
根据He, K等人于2015年在“Delving deep into rectifiers: Surpassing human-level performance on ImageNet classification”中描述的方法,用一个均匀分布生成值,填充输入的张量或变量。结果张量中的值采样自U(-bound, bound),其中bound = sqrt(2/((1 + a^2) * fan_in)) * sqrt(3)。也被称为He initialisation.
**参数:**
- **tensor** – n维的torch.Tensor或autograd.Variable
- **a** -这层之后使用的rectifier的斜率系数(ReLU的默认值为0)
- **mode** -可以为“fan_in”(默认)或“fan_out”。“fan_in”保留前向传播时权值方差的量级,“fan_out”保留反向传播时的量级。
**例子:**
```python
>>> w = torch.Tensor(3, 5)
>>> nn.init.kaiming_uniform(w, mode='fan_in')
```
```python
torch.nn.init.kaiming_normal(tensor, a=0, mode='fan_in')
```
根据He, K等人在“Delving deep into rectifiers: Surpassing human-level performance on ImageNet classification”中描述的方法,用一个正态分布生成值,填充输入的张量或变量。结果张量中的值采样自均值为0,标准差为sqrt(2/((1 + a^2) * fan_in))的正态分布。
**参数:**
- **tensor** – n维的torch.Tensor或 autograd.Variable
- **a** -这层之后使用的rectifier的斜率系数(ReLU的默认值为0)
- **mode** -可以为“fan_in”(默认)或“fan_out”。“fan_in”保留前向传播时权值方差的量级,“fan_out”保留反向传播时的量级。
**例子:**
```python
>>> w = torch.Tensor(3, 5)
>>> nn.init.kaiming_normal(w, mode='fan_out')
```
```python
torch.nn.init.orthogonal(tensor, gain=1)
```
用(半)正交矩阵填充输入的张量或变量。输入张量必须至少是2维的,对于更高维度的张量,超出的维度会被展平,视作行等于第一个维度,列等于稀疏矩阵乘积的2维表示。其中非零元素生成自均值为0,标准差为std的正态分布。
参考:Saxe, A等人(2013)的“Exact solutions to the nonlinear dynamics of learning in deep linear neural networks”
**参数:**
- **tensor** – n维的torch.Tensor或 autograd.Variable,其中n>=2
- **gain** -可选
**例子:**
```python
>>> w = torch.Tensor(3, 5)
>>> nn.init.orthogonal(w)
```
```python
torch.nn.init.sparse(tensor, sparsity, std=0.01)
```
将2维的输入张量或变量当做稀疏矩阵填充,其中非零元素根据一个均值为0,标准差为std的正态分布生成。
参考Martens, J.(2010)的 “Deep learning via Hessian-free optimization”.
**参数:**
- **tensor** – n维的torch.Tensor或autograd.Variable
- **sparsity** - 每列中需要被设置成零的元素比例
- **std** - 用于生成非零值的正态分布的标准差
**例子:**
```python
>>> w = torch.Tensor(3, 5)
>>> nn.init.sparse(w, sparsity=0.1)
```
\ No newline at end of file
# Automatic differentiation package - torch.autograd
`torch.autograd`提供了类和函数用来对任意标量函数进行求导。要想使用自动求导,只需要对已有的代码进行微小的改变。只需要将所有的`tensor`包含进`Variable`对象中即可。
### torch.autograd.backward(variables, grad_variables, retain_variables=False)
Computes the sum of gradients of given variables w.r.t. graph leaves.
给定图的叶子节点`variables`, 计算图中变量的梯度和。
计算图可以通过链式法则求导。如果`variables`中的任何一个`variable`是 非标量(`non-scalar`)的,且`requires_grad=True`。那么此函数需要指定`grad_variables`,它的长度应该和`variables`的长度匹配,里面保存了相关`variable`的梯度(对于不需要`gradient tensor``variable``None`是可取的)。
此函数累积`leaf variables`计算的梯度。你可能需要在调用此函数之前将`leaf variable`的梯度置零。
参数说明:
- variables (variable 列表) – 被求微分的叶子节点,即 `ys`
- grad_variables (`Tensor` 列表) – 对应`variable`的梯度。仅当`variable`不是标量且需要求梯度的时候使用。
- retain_variables (bool) – `True`,计算梯度时所需要的`buffer`在计算完梯度后不会被释放。如果想对一个子图多次求微分的话,需要设置为`True`
## Variable
### API 兼容性
`Variable API` 几乎和 `Tensor API`一致 (除了一些`in-place`方法,这些`in-place`方法会修改 `required_grad=True``input` 的值)。多数情况下,将`Tensor`替换为`Variable`,代码一样会正常的工作。由于这个原因,我们不会列出`Variable`的所有方法,你可以通过`torch.Tensor`的文档来获取相关知识。
### In-place operations on Variables
`autograd`中支持`in-place operations`是非常困难的。同时在很多情况下,我们阻止使用`in-place operations``Autograd`的贪婪的 释放`buffer`和 复用使得它效率非常高。只有在非常少的情况下,使用`in-place operations`可以降低内存的使用。除非你面临很大的内存压力,否则不要使用`in-place operations`
### In-place 正确性检查
所有的`Variable`都会记录用在他们身上的 `in-place operations`。如果`pytorch`检测到`variable`在一个`Function`中已经被保存用来`backward`,但是之后它又被`in-place operations`修改。当这种情况发生时,在`backward`的时候,`pytorch`就会报错。这种机制保证了,如果你用了`in-place operations`,但是在`backward`过程中没有报错,那么梯度的计算就是正确的。
### class torch.autograd.Variable [source]
包装一个`Tensor`,并记录用在它身上的`operations`
`Variable``Tensor`对象的一个`thin wrapper`,它同时保存着`Variable`的梯度和创建这个`Variable``Function`的引用。这个引用可以用来追溯创建这个`Variable`的整条链。如果`Variable`是被用户所创建的,那么它的`creator``None`,我们称这种对象为 `leaf Variables`
由于`autograd`只支持标量值的反向求导(即:`y`是标量),梯度的大小总是和数据的大小匹配。同时,仅仅给`leaf variables`分配梯度,其他`Variable`的梯度总是为0.
**`变量:`**
- data – 包含的`Tensor`
- grad – 保存着`Variable`的梯度。这个属性是懒分配的,且不能被重新分配。
- requires_grad – 布尔值,指示这个`Variable`是否是被一个包含`Variable`的子图创建的。更多细节请看`Excluding subgraphs from backward`。只能改变`leaf variable`的这个标签。
- volatile – 布尔值,指示这个`Variable`是否被用于推断模式(即,不保存历史信息)。更多细节请看`Excluding subgraphs from backward`。只能改变`leaf variable`的这个标签。
- creator – 创建这个`Variable``Function`,对于`leaf variable`,这个属性为`None`。只读属性。
**`属性:`**
- data (any tensor class) – 被包含的`Tensor`
- requires_grad (bool) – `requires_grad`标记. 只能通过`keyword`传入.
- volatile (bool) – `volatile`标记. 只能通过`keyword`传入.
#### backward(gradient=None, retain_variables=False)[source]
当前`Variable``leaf variable`求偏导。
计算图可以通过链式法则求导。如果`Variable`是 非标量(`non-scalar`)的,且`requires_grad=True`。那么此函数需要指定`gradient`,它的形状应该和`Variable`的长度匹配,里面保存了`Variable`的梯度。
此函数累积`leaf variable`的梯度。你可能需要在调用此函数之前将`Variable`的梯度置零。
**`参数:`**
- gradient (Tensor) – 其他函数对于此`Variable`的导数。仅当`Variable`不是标量的时候使用,类型和位形状应该和`self.data`一致。
- retain_variables (bool) – `True`, 计算梯度所必要的`buffer`在经历过一次`backward`过程后不会被释放。如果你想多次计算某个子图的梯度的时候,设置为`True`。在某些情况下,使用`autograd.backward()`效率更高。
#### detach()[source]
Returns a new Variable, detached from the current graph.
返回一个新的`Variable`,从当前图中分离下来的。
返回的`Variable` `requires_grad=False`,如果输入 `volatile=True`,那么返回的`Variable` `volatile=True`
**`注意:`**
返回的`Variable`和原始的`Variable`公用同一个`data tensor``in-place`修改会在两个`Variable`上同时体现(因为它们共享`data tensor`),可能会导致错误。
#### detach_()[source]
将一个`Variable`从创建它的图中分离,并把它设置成`leaf variable`
#### register_hook(hook)[source]
注册一个`backward`钩子。
每次`gradients`被计算的时候,这个`hook`都被调用。`hook`应该拥有以下签名:
`hook(grad) -> Variable or None`
`hook`不应该修改它的输入,但是它可以选择性的返回一个替代当前梯度的新梯度。
这个函数返回一个 句柄(`handle`)。它有一个方法 `handle.remove()`,可以用这个方法将`hook``module`移除。
Example
```python
v = Variable(torch.Tensor([0, 0, 0]), requires_grad=True)
h = v.register_hook(lambda grad: grad * 2) # double the gradient
v.backward(torch.Tensor([1, 1, 1]))
#先计算原始梯度,再进hook,获得一个新梯度。
print(v.grad.data)
2
2
2
[torch.FloatTensor of size 3]
>>> h.remove() # removes the hook
```
```python
def w_hook(grad):
print("hello")
return None
w1 = Variable(torch.FloatTensor([1, 1, 1]),requires_grad=True)
w1.register_hook(w_hook) # 如果hook返回的是None的话,那么梯度还是原来计算的梯度。
w1.backward(gradient=torch.FloatTensor([1, 1, 1]))
print(w1.grad)
```
```
hello
Variable containing:
1
1
1
[torch.FloatTensor of size 3]
```
#### reinforce(reward)[source]
注册一个奖励,这个奖励是由一个随机过程得到的。
微分一个随机节点需要提供一个奖励值。如果你的计算图中包含随机 `operations`,你需要在他们的输出上调用这个函数。否则的话,会报错。
**`参数:`**
- reward (Tensor) – 每个元素的reward。必须和`Varaible`形状相同,并在同一个设备上。
### class torch.autograd.Function[source]
Records operation history and defines formulas for differentiating ops.
记录`operation`的历史,定义微分公式。
每个执行在`Varaibles`上的`operation`都会创建一个`Function`对象,这个`Function`对象执行计算工作,同时记录下来。这个历史以有向无环图的形式保存下来,有向图的节点为`functions`,有向图的边代表数据依赖关系(`input<-output`)。之后,当`backward`被调用的时候,计算图以拓扑顺序处理,通过调用每个`Function`对象的`backward()`,同时将返回的梯度传递给下一个`Function`
通常情况下,用户能和`Functions`交互的唯一方法就是创建`Function`的子类,定义新的`operation`。这是扩展`torch.autograd`的推荐方法。
由于`Function`逻辑在很多脚本上都是热点,所有我们把几乎所有的`Function`都使用`C`实现,通过这种策略保证框架的开销是最小的。
每个`Function`只被使用一次(在forward过程中)。
**`变量:`**
- saved_tensors – 调用`forward()`时需要被保存的 `Tensors``tuple`
- needs_input_grad – 长度为 输入数量的 布尔值组成的 `tuple`。指示给定的`input`是否需要梯度。这个被用来优化用于`backward`过程中的`buffer`,忽略`backward`中的梯度计算。
- num_inputs – `forward` 的输入参数数量。
- num_outputs – `forward`返回的`Tensor`数量。
- requires_grad – 布尔值。指示`backward`以后会不会被调用。
- previous_functions – 长度为 `num_inputs`的 Tuple of (int, Function) pairs。`Tuple`中的每单元保存着创建 `input``Function`的引用,和索引。
#### backward(* grad_output)[source]
定义了`operation`的微分公式。
所有的`Function`子类都应该重写这个方法。
所有的参数都是`Tensor`。他必须接收和`forward`的输出 相同个数的参数。而且它需要返回和`forward`的输入参数相同个数的`Tensor`
即:`backward`的输入参数是 此`operation`的输出的值的梯度。`backward`的返回值是此`operation`输入值的梯度。
#### forward(* input)[source]
执行`operation`
所有的`Function`子类都需要重写这个方法。
可以接收和返回任意个数 `tensors`
#### mark_dirty(* args)[source]
将输入的 `tensors` 标记为被`in-place operation`修改过。
这个方法应当至多调用一次,仅仅用在 `forward`方法里,而且`mark_dirty`的实参只能是`forward`的实参。
每个在`forward`方法中被`in-place operations`修改的`tensor`都应该传递给这个方法。这样,可以保证检查的正确性。这个方法在`tensor`修改前后调用都可以。
#### mark_non_differentiable(* args)[source]
将输出标记为不可微。
这个方法至多只能被调用一次,只能在`forward`中调用,而且实参只能是`forward`的返回值。
这个方法会将输出标记成不可微,会增加`backward`过程中的效率。在`backward`中,你依旧需要接收`forward`输出值的梯度,但是这些梯度一直是`None`
This is used e.g. for indices returned from a max Function.
#### mark_shared_storage(* pairs)[source]
将给定的`tensors pairs`标记为共享存储空间。
这个方法至多只能被调用一次,只能在`forward`中调用,而且所有的实参必须是`(input, output)`对。
如果一些 `inputs``outputs` 是共享存储空间的,所有的这样的 `(input, output)`对都应该传给这个函数,保证 `in-place operations` 检查的正确性。唯一的特例就是,当 `output``input`是同一个`tensor`(`in-place operations`的输入和输出)。这种情况下,就没必要指定它们之间的依赖关系,因为这个很容易就能推断出来。
这个函数在很多时候都用不到。主要是用在 索引 和 转置 这类的 `op` 中。
#### save_for_backward(* tensors)[source]
将传入的 `tensor` 保存起来,留着`backward`的时候用。
这个方法至多只能被调用一次,只能在`forward`中调用。
之后,被保存的`tensors`可以通过 `saved_tensors`属性获取。在返回这些`tensors`之前,`pytorch`做了一些检查,保证这些`tensor`没有被`in-place operations`修改过。
实参可以是`None`
# torch.cuda
该包增加了对CUDA张量类型的支持,实现了与CPU张量相同的功能,但使用GPU进行计算。
它是懒惰的初始化,所以你可以随时导入它,并使用`is_available()`来确定系统是否支持CUDA。
[CUDA语义](../notes/cuda.md)中有关于使用CUDA的更多细节。
```python
torch.cuda.current_blas_handle()
```
返回cublasHandle_t指针,指向当前cuBLAS句柄
```python
torch.cuda.current_device()
```
返回当前所选设备的索引。
```python
torch.cuda.current_stream()
```
返回一个当前所选的`Stream`
```python
class torch.cuda.device(idx)
```
上下文管理器,可以更改所选设备。
**参数:**
- **idx** (*int*) – 设备索引选择。如果这个参数是负的,则是无效操作。
```python
torch.cuda.device_count()
```
返回可得到的GPU数量。
```python
class torch.cuda.device_of(obj)
```
将当前设备更改为给定对象的上下文管理器。
可以使用张量和存储作为参数。如果给定的对象不是在GPU上分配的,这是一个无效操作。
**参数:**
- **obj** (*Tensor* or *Storage*) – 在选定设备上分配的对象。
```python
torch.cuda.is_available()
```
返回一个bool值,指示CUDA当前是否可用。
```python
torch.cuda.set_device(device)
```
设置当前设备。
不鼓励使用此函数来设置。在大多数情况下,最好使用`CUDA_VISIBLE_DEVICES`环境变量。
**参数:**
- **device** (*int*) – 所选设备。如果此参数为负,则此函数是无效操作。
```python
torch.cuda.stream(stream)
```
选择给定流的上下文管理器。
在其上下文中排队的所有CUDA核心将在所选流上入队。
**参数:**
- **stream** (*Stream*) – 所选流。如果是`None`,则这个管理器是无效的。
```python
torch.cuda.synchronize()
```
等待当前设备上所有流中的所有核心完成。
## 交流集
```python
torch.cuda.comm.broadcast(tensor, devices)
```
向一些GPU广播张量。
**参数:**
- **tensor** (*Tensor*) – 将要广播的张量
- **devices** (*Iterable*) – 一个可以广播的设备的迭代。注意,它的形式应该像(src,dst1,dst2,...),其第一个元素是广播来源的设备。
**返回:** 一个包含张量副本的元组,放置在与设备的索引相对应的设备上。
```python
torch.cuda.comm.reduce_add(inputs, destination=None)
```
将来自多个GPU的张量相加。
所有输入应具有匹配的形状。
**参数:**
- **inputs** (*Iterable[Tensor]*) – 要相加张量的迭代
- **destination** (*int*, optional) – 将放置输出的设备(默认值:当前设备)。
**返回:** 一个包含放置在`destination`设备上的所有输入的元素总和的张量。
```python
torch.cuda.comm.scatter(tensor, devices, chunk_sizes=None, dim=0, streams=None)
```
打散横跨多个GPU的张量。
**参数:**
- **tensor** (*Tensor*) – 要分散的张量
- **devices** (*Iterable[int]*) – int的迭代,指定哪些设备应该分散张量。
- **chunk_sizes** (*Iterable[int]*, optional) – 要放置在每个设备上的块大小。它应该匹配`devices`的长度并且总和为`tensor.size(dim)`。 如果没有指定,张量将被分成相等的块。
- **dim** (*int*, optional) – 沿着这个维度来chunk张量
**返回:** 包含`tensor`块的元组,分布在给定的`devices`上。
```python
torch.cuda.comm.gather(tensors, dim=0, destination=None)
```
从多个GPU收集张量。
张量尺寸在不同于`dim`的所有维度上都应该匹配。
**参数:**
- **tensors** (*Iterable[Tensor]*) – 要收集的张量的迭代。
- **dim** (*int*) – 沿着此维度张量将被连接。
- **destination** (*int*, optional) – 输出设备(-1表示CPU,默认值:当前设备)。
**返回:** 一个张量位于`destination`设备上,这是沿着`dim`连接`tensors`的结果。
## 流和事件
```python
class torch.cuda.Stream
```
CUDA流的包装。
**参数:**
- **device** (*int*, optional) – 分配流的设备。
- **priority** (*int*, optional) – 流的优先级。较低的数字代表较高的优先级。
> query()
检查所有提交的工作是否已经完成。
**返回:** 一个布尔值,表示此流中的所有核心是否完成。
> record_event(event=None)
记录一个事件。
**参数:** **event** (*Event*, optional) – 要记录的事件。如果没有给出,将分配一个新的。
**返回:** 记录的事件。
> synchronize()
等待此流中的所有核心完成。
> wait_event(event)
将所有未来的工作提交到流等待事件。
**参数:** **event** (*Event*) – 等待的事件
> wait_stream(stream)
与另一个流同步。
提交到此流的所有未来工作将等待直到所有核心在调用完成时提交给给定的流。
```python
class torch.cuda.Event(enable_timing=False, blocking=False, interprocess=False, _handle=None)
```
CUDA事件的包装。
**参数:**
- **enable_timing** (*bool*) – 指示事件是否应该测量时间(默认值:False)
- **blocking** (*bool*) – 如果为true,`wait()`将被阻塞(默认值:False)
- **interprocess** (*bool*) – 如果为true,则可以在进程之间共享事件(默认值:False)
> elapsed_time(end_event)
返回事件记录之前经过的时间。
> ipc_handle()
返回此事件的IPC句柄。
> query()
检查事件是否已被记录。
**返回:** 一个布尔值,指示事件是否已被记录。
> record(stream=None)
记录给定流的事件。
> synchronize()
与事件同步。
> wait(stream=None)
使给定的流等待事件。
# torch.multiprocessing
封装了`multiprocessing`模块。用于在相同数据的不同进程中共享视图。
一旦张量或者存储被移动到共享单元(见`share_memory_()`),它可以不需要任何其他复制操作的发送到其他的进程中。
这个API与原始模型完全兼容,为了让张量通过队列或者其他机制共享,移动到内存中,我们可以
由原来的`import multiprocessing`改为`import torch.multiprocessing`
由于API的相似性,我们没有记录这个软件包的大部分内容,我们建议您参考原始模块的非常好的文档。
**`warning:`**
如果主要的进程突然退出(例如,因为输入信号),Python中的`multiprocessing`有时会不能清理他的子节点。
这是一个已知的警告,所以如果您在中断解释器后看到任何资源泄漏,这可能意味着这刚刚发生在您身上。
## Strategy management
```python
torch.multiprocessing.get_all_sharing_strategies()
```
返回一组由当前系统所支持的共享策略
```python
torch.multiprocessing.get_sharing_strategy()
```
返回当前策略共享CPU中的张量。
```python
torch.multiprocessing.set_sharing_strategy(new_strategy)
```
设置共享CPU张量的策略
参数: new_strategy(str)-被选中策略的名字。应当是`get_all_sharing_strategies()`中值当中的一个。
## Sharing CUDA tensors
共享CUDA张量进程只支持Python3,使用`spawn`或者`forkserver`开始方法。
Python2中的`multiprocessing`只能使用`fork`创建子进程,并且不被CUDA支持。
**`warning:`**
CUDA API要求导出到其他进程的分配一直保持有效,只要它们被使用。
你应该小心,确保您共享的CUDA张量不要超出范围。
这不应该是共享模型参数的问题,但传递其他类型的数据应该小心。请注意,此限制不适用于共享CPU内存。
## Sharing strategies
本节简要概述了不同的共享策略如何工作。
请注意,它仅适用于CPU张量 - CUDA张量将始终使用CUDA API,因为它们是唯一的共享方式。
### File descriptor-`file_descripor`
**`NOTE:`**
这是默认策略(除了不支持的MacOS和OS X)。
此策略将使用文件描述符作为共享内存句柄。当存储被移动到共享内存中,一个由`shm_open`获得的文件描述符被缓存,
并且当它将被发送到其他进程时,文件描述符将被传送(例如通过UNIX套接字)。
接收者也将缓存文件描述符,并且`mmap`它,以获得对存储数据的共享视图。
请注意,如果要共享很多张量,则此策略将保留大量文件描述符。
如果你的系统对打开的文件描述符数量有限制,并且无法提高,你应该使用`file_system`策略。
### File system -file_system
这个策略将提供文件名称给`shm_open`去定义共享内存区域。
该策略不需要缓存从其获得的文件描述符的优点,但是容易发生共享内存泄漏。
该文件创建后不能被删除,因为其他进程需要访问它以打开其视图。
如果进程崩溃或死机,并且不能调用存储析构函数,则文件将保留在系统中。
这是非常严重的,因为它们在系统重新启动之前不断使用内存,或者手动释放它们。
为了记录共享内存文件泄露数量,`torch.multiprocessing`将产生一个守护进程叫做`torch_shm_manager`
将自己与当前进程组隔离,并且将跟踪所有共享内存分配。一旦连接到它的所有进程退出,
它将等待一会儿,以确保不会有新的连接,并且将遍历该组分配的所有共享内存文件。
如果发现它们中的任何一个仍然存在,它们将被释放。我们已经测试了这种方法,并且它已被证明对于各种故障都是稳健的。
如果你的系统有足够高的限制,并且`file_descriptor`是被支持的策略,我们不建议切换到这个。
此差异已折叠。
# torch.optim
`torch.optim`是一个实现了各种优化算法的库。大部分常用的方法得到支持,并且接口具备足够的通用性,使得未来能够集成更加复杂的方法。
## 如何使用optimizer
为了使用`torch.optim`,你需要构建一个optimizer对象。这个对象能够保持当前参数状态并基于计算得到的梯度进行参数更新。
### 构建
为了构建一个`Optimizer`,你需要给它一个包含了需要优化的参数(必须都是`Variable`对象)的iterable。然后,你可以设置optimizer的参
数选项,比如学习率,权重衰减,等等。
例子:
```python
optimizer = optim.SGD(model.parameters(), lr = 0.01, momentum=0.9)
optimizer = optim.Adam([var1, var2], lr = 0.0001)
```
### 为每个参数单独设置选项
`Optimizer`也支持为每个参数单独设置选项。若想这么做,不要直接传入`Variable`的iterable,而是传入`dict`的iterable。每一个dict都分别定
义了一组参数,并且包含一个`param`键,这个键对应参数的列表。其他的键应该optimizer所接受的其他参数的关键字相匹配,并且会被用于对这组参数的
优化。
**`注意:`**
你仍然能够传递选项作为关键字参数。在未重写这些选项的组中,它们会被用作默认值。当你只想改动一个参数组的选项,但其他参数组的选项不变时,这是
非常有用的。
例如,当我们想指定每一层的学习率时,这是非常有用的:
```python
optim.SGD([
{'params': model.base.parameters()},
{'params': model.classifier.parameters(), 'lr': 1e-3}
], lr=1e-2, momentum=0.9)
```
这意味着`model.base`的参数将会使用`1e-2`的学习率,`model.classifier`的参数将会使用`1e-3`的学习率,并且`0.9`的momentum将会被用于所
有的参数。
### 进行单次优化
所有的optimizer都实现了`step()`方法,这个方法会更新所有的参数。它能按两种方式来使用:
**`optimizer.step()`**
这是大多数optimizer所支持的简化版本。一旦梯度被如`backward()`之类的函数计算好后,我们就可以调用这个函数。
例子
```python
for input, target in dataset:
optimizer.zero_grad()
output = model(input)
loss = loss_fn(output, target)
loss.backward()
optimizer.step()
```
**`optimizer.step(closure)`**
一些优化算法例如Conjugate Gradient和LBFGS需要重复多次计算函数,因此你需要传入一个闭包去允许它们重新计算你的模型。这个闭包应当清空梯度,
计算损失,然后返回。
例子:
```python
for input, target in dataset:
def closure():
optimizer.zero_grad()
output = model(input)
loss = loss_fn(output, target)
loss.backward()
return loss
optimizer.step(closure)
```
## 算法
### class torch.optim.Optimizer(params, defaults) [source]
Base class for all optimizers.
**参数:**
* params (iterable) —— `Variable` 或者 `dict`的iterable。指定了什么参数应当被优化。
* defaults —— (dict):包含了优化选项默认值的字典(一个参数组没有指定的参数选项将会使用默认值)。
#### load_state_dict(state_dict) [source]
加载optimizer状态
**参数:**
state_dict (`dict`) —— optimizer的状态。应当是一个调用`state_dict()`所返回的对象。
#### state_dict() [source]
`dict`返回optimizer的状态。
它包含两项。
* state - 一个保存了当前优化状态的dict。optimizer的类别不同,state的内容也会不同。
* param_groups - 一个包含了全部参数组的dict。
#### step(closure) [source]
进行单次优化 (参数更新).
**参数:**
* closure (`callable`) – 一个重新评价模型并返回loss的闭包,对于大多数参数来说是可选的。
#### zero_grad() [source]
清空所有被优化过的Variable的梯度.
### class torch.optim.Adadelta(params, lr=1.0, rho=0.9, eps=1e-06, weight_decay=0)[source]
实现Adadelta算法。
它在[ADADELTA: An Adaptive Learning Rate Method.](https://arxiv.org/abs/1212.5701)中被提出。
**参数:**
* params (iterable) – 待优化参数的iterable或者是定义了参数组的dict
* rho (`float`, 可选) – 用于计算平方梯度的运行平均值的系数(默认:0.9)
* eps (`float`, 可选) – 为了增加数值计算的稳定性而加到分母里的项(默认:1e-6)
* lr (`float`, 可选) – 在delta被应用到参数更新之前对它缩放的系数(默认:1.0)
* weight_decay (`float`, 可选) – 权重衰减(L2惩罚)(默认: 0)
#### step(closure) [source]
进行单次优化 (参数更新).
**参数:**
* closure (`callable`) – 一个重新评价模型并返回loss的闭包,对于大多数参数来说是可选的。
### class torch.optim.Adagrad(params, lr=0.01, lr_decay=0, weight_decay=0)[source]
实现Adagrad算法。
它在 [Adaptive Subgradient Methods for Online Learning and Stochastic Optimization](
http://jmlr.org/papers/v12/duchi11a.html)中被提出。
**参数:**
* params (iterable) – 待优化参数的iterable或者是定义了参数组的dict
* lr (`float`, 可选) – 学习率(默认: 1e-2)
* lr_decay (`float`, 可选) – 学习率衰减(默认: 0)
* weight_decay (`float`, 可选) – 权重衰减(L2惩罚)(默认: 0)
#### step(closure) [source]
进行单次优化 (参数更新).
**参数:**
* closure (`callable`) – 一个重新评价模型并返回loss的闭包,对于大多数参数来说是可选的。
### class torch.optim.Adam(params, lr=0.001, betas=(0.9, 0.999), eps=1e-08, weight_decay=0)[source]
实现Adam算法。
它在[Adam: A Method for Stochastic Optimization](https://arxiv.org/abs/1412.6980)中被提出。
**参数:**
* params (iterable) – 待优化参数的iterable或者是定义了参数组的dict
* lr (`float`, 可选) – 学习率(默认:1e-3)
* betas (Tuple[`float`, `float`], 可选) – 用于计算梯度以及梯度平方的运行平均值的系数(默认:0.9,0.999)
* eps (`float`, 可选) – 为了增加数值计算的稳定性而加到分母里的项(默认:1e-8)
* weight_decay (`float`, 可选) – 权重衰减(L2惩罚)(默认: 0)
#### step(closure) [source]
进行单次优化 (参数更新).
**参数:**
* closure (`callable`) – 一个重新评价模型并返回loss的闭包,对于大多数参数来说是可选的。
### class torch.optim.Adamax(params, lr=0.002, betas=(0.9, 0.999), eps=1e-08, weight_decay=0)[source]
实现Adamax算法(Adam的一种基于无穷范数的变种)。
它在[Adam: A Method for Stochastic Optimization](https://arxiv.org/abs/1412.6980)中被提出。
**参数:**
* params (iterable) – 待优化参数的iterable或者是定义了参数组的dict
* lr (`float`, 可选) – 学习率(默认:2e-3)
* betas (Tuple[`float`, `float`], 可选) – 用于计算梯度以及梯度平方的运行平均值的系数
* eps (`float`, 可选) – 为了增加数值计算的稳定性而加到分母里的项(默认:1e-8)
* weight_decay (`float`, 可选) – 权重衰减(L2惩罚)(默认: 0)
#### step(closure) [source]
进行单次优化 (参数更新).
**参数:**
* closure (`callable`) – 一个重新评价模型并返回loss的闭包,对于大多数参数来说是可选的。
### class torch.optim.ASGD(params, lr=0.01, lambd=0.0001, alpha=0.75, t0=1000000.0, weight_decay=0)[source]
实现平均随机梯度下降算法。
它在[Acceleration of stochastic approximation by averaging](http://dl.acm.org/citation.cfm?id=131098)中被提出。
**参数:**
* params (iterable) – 待优化参数的iterable或者是定义了参数组的dict
* lr (`float`, 可选) – 学习率(默认:1e-2)
* lambd (`float`, 可选) – 衰减项(默认:1e-4)
* alpha (`float`, 可选) – eta更新的指数(默认:0.75)
* t0 (`float`, 可选) – 指明在哪一次开始平均化(默认:1e6)
* weight_decay (`float`, 可选) – 权重衰减(L2惩罚)(默认: 0)
#### step(closure) [source]
进行单次优化 (参数更新).
**参数:**
* closure (`callable`) – 一个重新评价模型并返回loss的闭包,对于大多数参数来说是可选的。
### class torch.optim.LBFGS(params, lr=1, max_iter=20, max_eval=None, tolerance_grad=1e-05, tolerance_change=1e-09, history_size=100, line_search_fn=None)[source]
实现L-BFGS算法。
#### 警告
这个optimizer不支持为每个参数单独设置选项以及不支持参数组(只能有一个)
#### 警告
目前所有的参数不得不都在同一设备上。在将来这会得到改进。
#### 注意
这是一个内存高度密集的optimizer(它要求额外的`param_bytes * (history_size + 1)` 个字节)。如果它不适应内存,尝试减小history size,或者使用不同的算法。
**参数:**
* lr (`float`) – 学习率(默认:1)
* max_iter (`int`) – 每一步优化的最大迭代次数(默认:20))
* max_eval (`int`) – 每一步优化的最大函数评价次数(默认:max * 1.25)
* tolerance_grad (`float`) – 一阶最优的终止容忍度(默认:1e-5)
* tolerance_change (`float`) – 在函数值/参数变化量上的终止容忍度(默认:1e-9)
* history_size (`int`) – 更新历史的大小(默认:100)
#### step(closure) [source]
进行单次优化 (参数更新).
**参数:**
* closure (`callable`) – 一个重新评价模型并返回loss的闭包,对于大多数参数来说是可选的。
### class torch.optim.RMSprop(params, lr=0.01, alpha=0.99, eps=1e-08, weight_decay=0, momentum=0, centered=False)[source]
实现RMSprop算法。
由G. H`int`on在他的[课程](http://www.cs.toronto.edu/~tijmen/csc321/slides/lecture_slides_lec6.pdf)中提出.
中心版本首次出现在[Generating Sequences With Recurrent Neural Networks](
https://arxiv.org/pdf/1308.0850v5.pdf).
**参数:**
* params (iterable) – 待优化参数的iterable或者是定义了参数组的dict
* lr (`float`, 可选) – 学习率(默认:1e-2)
* momentum (`float`, 可选) – 动量因子(默认:0)
* alpha (`float`, 可选) – 平滑常数(默认:0.99)
* eps (`float`, 可选) – 为了增加数值计算的稳定性而加到分母里的项(默认:1e-8)
* centered (`bool`, 可选) – 如果为True,计算中心化的RMSProp,并且用它的方差预测值对梯度进行归一化
* weight_decay (`float`, 可选) – 权重衰减(L2惩罚)(默认: 0)
#### step(closure) [source]
进行单次优化 (参数更新).
**参数:**
* closure (`callable`) – 一个重新评价模型并返回loss的闭包,对于大多数参数来说是可选的。
### class torch.optim.Rprop(params, lr=0.01, etas=(0.5, 1.2), step_sizes=(1e-06, 50))[source]
实现弹性反向传播算法。
**参数:**
* params (iterable) – 待优化参数的iterable或者是定义了参数组的dict
* lr (`float`, 可选) – 学习率(默认:1e-2)
* etas (Tuple[`float`, `float`], 可选) – 一对(etaminus,etaplis), 它们分别是乘法的增加和减小的因子(默认:0.5,1.2)
* step_sizes (Tuple[`float`, `float`], 可选) – 允许的一对最小和最大的步长(默认:1e-6,50)
#### step(closure) [source]
进行单次优化 (参数更新).
**参数:**
* closure (`callable`) – 一个重新评价模型并返回loss的闭包,对于大多数参数来说是可选的。
### class torch.optim.SGD(params, lr=<object object>, momentum=0, dampening=0, weight_decay=0, nesterov=False)[source]
实现随机梯度下降算法(momentum可选)。
Nesterov动量基于[On the importance of initialization and momentum in deep learning](
http://www.cs.toronto.edu/~h`int`on/absps/momentum.pdf)中的公式.
**参数:**
* params (iterable) – 待优化参数的iterable或者是定义了参数组的dict
* lr (`float`) – 学习率
* momentum (`float`, 可选) – 动量因子(默认:0)
* weight_decay (`float`, 可选) – 权重衰减(L2惩罚)(默认:0)
* dampening (`float`, 可选) – 动量的抑制因子(默认:0)
* nesterov (`bool`, 可选) – 使用Nesterov动量(默认:False)
**例子:**
```python
>>> optimizer = torch.optim.SGD(model.parameters(), lr=0.1, momentum=0.9)
>>> optimizer.zero_grad()
>>> loss_fn(model(input), target).backward()
>>> optimizer.step()
```
#### Note
带有动量/Nesterov的SGD的实现稍微不同于Sutskever等人以及其他框架中的实现。
考虑动量的具体情况,更新可以写成
v=ρ*v+g
p=p-lr*v
其中,p、g、v和ρ分别是参数、梯度、速度和动量。
这跟Sutskever等人以及其他框架的实现是相反的,它们采用这样的更新
v=ρ*v+lr*g
p=p-v
Nesterov的版本也类似地被修改了。
#### step(closure) [source]
进行单次优化 (参数更新).
**参数:**
* closure (`callable`) – 一个重新评价模型并返回loss的闭包,对于大多数参数来说是可选的。
\ No newline at end of file
此差异已折叠。
# torchvision.datasets
`torchvision.datasets`中包含了以下数据集
- MNIST
- COCO(用于图像标注和目标检测)(Captioning and Detection)
- LSUN Classification
- ImageFolder
- Imagenet-12
- CIFAR10 and CIFAR100
- STL10
`Datasets` 拥有以下`API`:
`__getitem__`
`__len__`
由于以上`Datasets`都是 `torch.utils.data.Dataset`的子类,所以,他们也可以通过`torch.utils.data.DataLoader`使用多线程(python的多进程)。
举例说明:
`torch.utils.data.DataLoader(coco_cap, batch_size=args.batchSize, shuffle=True, num_workers=args.nThreads)`
在构造函数中,不同的数据集直接的构造函数会有些许不同,但是他们共同拥有 `keyword` 参数。
In the constructor, each dataset has a slightly different API as needed, but they all take the keyword args:
- `transform`: 一个函数,原始图片作为输入,返回一个转换后的图片。(详情请看下面关于`torchvision-tranform`的部分)
- `target_transform` - 一个函数,输入为`target`,输出对其的转换。例子,输入的是图片标注的`string`,输出为`word`的索引。
## MNIST
```python
dset.MNIST(root, train=True, transform=None, target_transform=None, download=False)
```
参数说明:
- root : `processed/training.pt``processed/test.pt` 的主目录
- train : `True` = 训练集, `False` = 测试集
- download : `True` = 从互联网上下载数据集,并把数据集放在`root`目录下. 如果数据集之前下载过,将处理过的数据(minist.py中有相关函数)放在`processed`文件夹下。
## COCO
需要安装[COCO API](https://github.com/pdollar/coco/tree/master/PythonAPI)
### 图像标注:
```python
dset.CocoCaptions(root="dir where images are", annFile="json annotation file", [transform, target_transform])
```
例子:
```python
import torchvision.datasets as dset
import torchvision.transforms as transforms
cap = dset.CocoCaptions(root = 'dir where images are',
annFile = 'json annotation file',
transform=transforms.ToTensor())
print('Number of samples: ', len(cap))
img, target = cap[3] # load 4th sample
print("Image Size: ", img.size())
print(target)
```
输出:
```
Number of samples: 82783
Image Size: (3L, 427L, 640L)
[u'A plane emitting smoke stream flying over a mountain.',
u'A plane darts across a bright blue sky behind a mountain covered in snow',
u'A plane leaves a contrail above the snowy mountain top.',
u'A mountain that has a plane flying overheard in the distance.',
u'A mountain view with a plume of smoke in the background']
```
### 检测:
```
dset.CocoDetection(root="dir where images are", annFile="json annotation file", [transform, target_transform])
```
## LSUN
```python
dset.LSUN(db_path, classes='train', [transform, target_transform])
```
参数说明:
- db_path = 数据集文件的根目录
- classes = 'train' (所有类别, 训练集), 'val' (所有类别, 验证集), 'test' (所有类别, 测试集)
['bedroom\_train', 'church\_train', …] : a list of categories to load
## ImageFolder
一个通用的数据加载器,数据集中的数据以以下方式组织
```
root/dog/xxx.png
root/dog/xxy.png
root/dog/xxz.png
root/cat/123.png
root/cat/nsdf3.png
root/cat/asd932_.png
```
```python
dset.ImageFolder(root="root folder path", [transform, target_transform])
```
他有以下成员变量:
- self.classes - 用一个list保存 类名
- self.class_to_idx - 类名对应的 索引
- self.imgs - 保存(img-path, class) tuple的list
## Imagenet-12
This is simply implemented with an ImageFolder dataset.
The data is preprocessed [as described here](https://github.com/facebook/fb.resnet.torch/blob/master/INSTALL.md#download-the-imagenet-dataset)
[Here is an example](https://github.com/pytorch/examples/blob/27e2a46c1d1505324032b1d94fc6ce24d5b67e97/imagenet/main.py#L48-L62)
## CIFAR
```python
dset.CIFAR10(root, train=True, transform=None, target_transform=None, download=False)
dset.CIFAR100(root, train=True, transform=None, target_transform=None, download=False)
```
参数说明:
- root : `cifar-10-batches-py` 的根目录
- train : `True` = 训练集, `False` = 测试集
- download : `True` = 从互联上下载数据,并将其放在`root`目录下。如果数据集已经下载,什么都不干。
## STL10
```python
dset.STL10(root, split='train', transform=None, target_transform=None, download=False)
```
参数说明:
- root : `stl10_binary`的根目录
- split : 'train' = 训练集, 'test' = 测试集, 'unlabeled' = 无标签数据集, 'train+unlabeled' = 训练 + 无标签数据集 (没有标签的标记为-1)
- download : `True` = 从互联上下载数据,并将其放在`root`目录下。如果数据集已经下载,什么都不干。
# torchvision.models
`torchvision.models`模块的 子模块中包含以下模型结构。
- AlexNet
- VGG
- ResNet
- SqueezeNet
- DenseNet
You can construct a model with random weights by calling its constructor:
你可以使用随机初始化的权重来创建这些模型。
```python
import torchvision.models as models
resnet18 = models.resnet18()
alexnet = models.alexnet()
squeezenet = models.squeezenet1_0()
densenet = models.densenet_161()
```
We provide pre-trained models for the ResNet variants and AlexNet, using the PyTorch torch.utils.model_zoo. These can constructed by passing pretrained=True:
对于`ResNet variants``AlexNet`,我们也提供了预训练(`pre-trained`)的模型。
```python
import torchvision.models as models
#pretrained=True就可以使用预训练的模型
resnet18 = models.resnet18(pretrained=True)
alexnet = models.alexnet(pretrained=True)
```
ImageNet 1-crop error rates (224x224)
|Network |Top-1 error |Top-5 error|
|------|------|------|
|ResNet-18| 30.24| 10.92|
|ResNet-34| 26.70| 8.58|
|ResNet-50 |23.85 |7.13|
|ResNet-101| 22.63| 6.44|
|ResNet-152 |21.69 |5.94|
|Inception v3| 22.55| 6.44|
|AlexNet |43.45 |20.91|
|VGG-11| 30.98| 11.37|
|VGG-13 |30.07 |10.75|
|VGG-16| 28.41| 9.62|
|VGG-19 |27.62 |9.12|
|SqueezeNet 1.0| 41.90| 19.58|
|SqueezeNet 1.1 |41.81 |19.38|
|Densenet-121| 25.35| 7.83|
|Densenet-169 |24.00 |7.00|
|Densenet-201| 22.80| 6.43|
|Densenet-161| 22.35 |6.20|
## torchvision.models.alexnet(pretrained=False, ** kwargs)
`AlexNet` 模型结构 [paper地址](https://arxiv.org/abs/1404.5997)
- pretrained (bool) – `True`, 返回在ImageNet上训练好的模型。
## torchvision.models.resnet18(pretrained=False, ** kwargs)
构建一个`resnet18`模型
- pretrained (bool) – `True`, 返回在ImageNet上训练好的模型。
## torchvision.models.resnet34(pretrained=False, ** kwargs)
构建一个`ResNet-34` 模型.
Parameters: pretrained (bool) – `True`, 返回在ImageNet上训练好的模型。
## torchvision.models.resnet50(pretrained=False, ** kwargs)
构建一个`ResNet-50`模型
- pretrained (bool) – `True`, 返回在ImageNet上训练好的模型。
## torchvision.models.resnet101(pretrained=False, ** kwargs)
Constructs a ResNet-101 model.
- pretrained (bool) – `True`, 返回在ImageNet上训练好的模型。
## torchvision.models.resnet152(pretrained=False, ** kwargs)
Constructs a ResNet-152 model.
- pretrained (bool) – `True`, 返回在ImageNet上训练好的模型。
## torchvision.models.vgg11(pretrained=False, ** kwargs)
VGG 11-layer model (configuration “A”)
- pretrained (bool) – `True`, 返回在ImageNet上训练好的模型。
## torchvision.models.vgg11_bn(** kwargs)
VGG 11-layer model (configuration “A”) with batch normalization
## torchvision.models.vgg13(pretrained=False, ** kwargs)
VGG 13-layer model (configuration “B”)
- pretrained (bool) – `True`, 返回在ImageNet上训练好的模型。
## torchvision.models.vgg13_bn(** kwargs)
VGG 13-layer model (configuration “B”) with batch normalization
## torchvision.models.vgg16(pretrained=False, ** kwargs)
VGG 16-layer model (configuration “D”)
Parameters: pretrained (bool) – If True, returns a model pre-trained on ImageNet
## torchvision.models.vgg16_bn(** kwargs)
VGG 16-layer model (configuration “D”) with batch normalization
## torchvision.models.vgg19(pretrained=False, ** kwargs)
VGG 19-layer model (configuration “E”)
- pretrained (bool) – `True`, 返回在ImageNet上训练好的模型。
## torchvision.models.vgg19_bn(** kwargs)
VGG 19-layer model (configuration 'E') with batch normalization
# pytorch torchvision transform
## 对PIL.Image进行变换
### class torchvision.transforms.Compose(transforms)
将多个`transform`组合起来使用。
`transforms`: 由`transform`构成的列表.
例子:
```python
transforms.Compose([
transforms.CenterCrop(10),
transforms.ToTensor(),
])
```
### class torchvision.transforms.Scale(size, interpolation=2)
将输入的`PIL.Image`重新改变大小成给定的`size``size`是最小边的边长举个例子如果原图的`height>width`,那么改变大小后的图片大小是`(size*height/width, size)`
**用例:**
```python
from torchvision import transforms
from PIL import Image
crop = transforms.Scale(12)
img = Image.open('test.jpg')
print(type(img))
print(img.size)
croped_img=crop(img)
print(type(croped_img))
print(croped_img.size)
```
```
<class 'PIL.PngImagePlugin.PngImageFile'>
(10, 10)
<class 'PIL.Image.Image'>
(12, 12)
```
### class torchvision.transforms.CenterCrop(size)
将给定的`PIL.Image`进行中心切割,得到给定的`size``size`可以是`tuple``(target_height, target_width)``size`也可以是一个`Integer`,在这种情况下,切出来的图片的形状是正方形。
### class torchvision.transforms.RandomCrop(size, padding=0)
切割中心点的位置随机选取。`size`可以是`tuple`也可以是`Integer`
### class torchvision.transforms.RandomHorizontalFlip
随机水平翻转给定的`PIL.Image`,概率为`0.5`。即:一半的概率翻转,一半的概率不翻转。
### class torchvision.transforms.RandomSizedCrop(size, interpolation=2)
先将给定的`PIL.Image`随机切,然后再`resize`成给定的`size`大小。
### class torchvision.transforms.Pad(padding, fill=0)
将给定的`PIL.Image`的所有边用给定的`pad value`填充。
`padding:`要填充多少像素
`fill:`用什么值填充
例子:
```python
from torchvision import transforms
from PIL import Image
padding_img = transforms.Pad(padding=10, fill=0)
img = Image.open('test.jpg')
print(type(img))
print(img.size)
padded_img=padding(img)
print(type(padded_img))
print(padded_img.size)
```
```
<class 'PIL.PngImagePlugin.PngImageFile'>
(10, 10)
<class 'PIL.Image.Image'>
(30, 30) #由于上下左右都要填充10个像素,所以填充后的size是(30,30)
```
## 对Tensor进行变换
### class torchvision.transforms.Normalize(mean, std)
给定均值:`(R,G,B)` 方差:`(R,G,B)`,将会把`Tensor`正则化。即:`Normalized_image=(image-mean)/std`
## Conversion Transforms
### class torchvision.transforms.ToTensor
把一个取值范围是`[0,255]``PIL.Image`或者`shape``(H,W,C)``numpy.ndarray`,转换成形状为`[C,H,W]`,取值范围是`[0,1.0]``torch.FloadTensor`
```python
data = np.random.randint(0, 255, size=300)
img = data.reshape(10,10,3)
print(img.shape)
img_tensor = transforms.ToTensor()(img) # 转换成tensor
print(img_tensor)
```
### class torchvision.transforms.ToPILImage
`shape``(C,H,W)``Tensor``shape``(H,W,C)``numpy.ndarray`转换成`PIL.Image`,值不变。
## 通用变换
### class torchvision.transforms.Lambda(lambd)
使用`lambd`作为转换器。
# torchvision.utils
## torchvision.utils.make_grid(tensor, nrow=8, padding=2, normalize=False, range=None, scale_each=False)
猜测,用来做 `雪碧图的`(`sprite image`)。
给定 `4D mini-batch Tensor`, 形状为 `(B x C x H x W)`,或者一个`a list of image`,做成一个`size``(B / nrow, nrow)`的雪碧图。
- normalize=True ,会将图片的像素值归一化处理
- 如果 range=(min, max), min和max是数字,那么`min``max`用来规范化`image`
- scale_each=True ,每个图片独立规范化,而不是根据所有图片的像素最大最小值来规范化
[Example usage is given in this notebook](https://gist.github.com/anonymous/bf16430f7750c023141c562f3e9f2a91)
## torchvision.utils.save_image(tensor, filename, nrow=8, padding=2, normalize=False, range=None, scale_each=False)
将给定的`Tensor`保存成image文件。如果给定的是`mini-batch tensor`,那就用`make-grid`做成雪碧图,再保存。
# torchvision
`torchvision`包 包含了目前流行的数据集,模型结构和常用的图片转换工具。
# PyTorch 0.3 中文文档 & 教程
![](../img/logo.svg)
> 维护组织:[@ApacheCN](https://github.com/apachecn)
>
> 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/)
>
> 欢迎任何人参与和完善:一个人可以走的很快,但是一群人却可以走的更远。
+ [在线阅读](http://pytorch.apachecn.org)
+ [ApacheCN 学习资源](http://www.apachecn.org/)
+ [PyTorch 中文翻译组 | ApacheCN 713436582](http://shang.qq.com/wpa/qunwpa?idkey=349eb1bbaeeff1cf20408899cbe75669132ef145ff5ee6599f78a77dd144c367)
<!-- break -->
+ [在线阅读](https://pytorch.apachecn.org/docs/0.3/)
+ [PDF格式](https://www.gitbook.com/download/pdf/book/wizardforcel/pytorch-03-doc)
+ [EPUB格式](https://www.gitbook.com/download/epub/book/wizardforcel/pytorch-03-doc)
+ [MOBI格式](https://www.gitbook.com/download/mobi/book/wizardforcel/pytorch-03-doc)
+ [代码仓库](https://github.com/apachecn/pytorch-doc-zh)
## 目录结构
* [PyTorch 0.3 中文文档 & 教程](README.md)
* [中文教程](tut.md)
* [初学者教程](beginner_tutorials.md)
* [PyTorch 深度学习: 60 分钟极速入门教程](deep_learning_60min_blitz.md)
* [PyTorch 是什么?](blitz_tensor_tutorial.md)
* [自动求导: 自动微分](blitz_autograd_tutorial.md)
* [神经网络](blitz_neural_networks_tutorial.md)
* [训练一个分类器](blitz_cifar10_tutorial.md)
* [可选: 数据并行](blitz_data_parallel_tutorial.md)
* [PyTorch for former Torch users](former_torchies_tutorial.md)
* [Tensors](former_torchies_tensor_tutorial.md)
* [Autograd (自动求导)](former_torchies_autograd_tutorial.md)
* [nn package](former_torchies_nn_tutorial.md)
* [Multi-GPU examples](former_torchies_parallelism_tutorial.md)
* [跟着例子学习 PyTorch](pytorch_with_examples.md)
* [Warm-up: numpy](pytorch_with_examples_warm-up-numpy.md)
* [PyTorch: Tensors](pytorch_with_examples_pytorch-tensors.md)
* [PyTorch: 变量和autograd](pytorch_with_examples_pytorch-variables-and-autograd.md)
* [PyTorch: 定义新的autograd函数](pytorch_with_examples_pytorch-defining-new-autograd-functions.md)
* [TensorFlow: 静态图](pytorch_with_examples_tensorflow-static-graphs.md)
* [PyTorch: nn包](pytorch_with_examples_pytorch-nn.md)
* [PyTorch: optim包](pytorch_with_examples_pytorch-optim.md)
* [PyTorch: 定制化nn模块](pytorch_with_examples_pytorch-custom-nn-modules.md)
* [PyTorch: 动态控制流程 + 权重共享](pytorch_with_examples_pytorch-control-flow-weight-sharing.md)
* [迁移学习教程](transfer_learning_tutorial.md)
* [数据加载和处理教程](data_loading_tutorial.md)
* [针对NLP的Pytorch深度学习](deep_learning_nlp_tutorial.md)
* [PyTorch介绍](nlp_pytorch_tutorial.md)
* [PyTorch深度学习](nlp_deep_learning_tutorial.md)
* [词汇嵌入:编码词汇语义](nlp_word_embeddings_tutorial.md)
* [序列模型和 LSTM 网络(长短记忆网络)](nlp_sequence_models_tutorial.md)
* [高级教程: 作出动态决策和 Bi-LSTM CRF](nlp_advanced_tutorial.md)
* [中级教程](intermediate_tutorials.md)
* [用字符级RNN分类名称](char_rnn_classification_tutorial.md)
* [基与字符级RNN(Char-RNN)的人名生成](char_rnn_generation_tutorial.md)
* [用基于注意力机制的seq2seq神经网络进行翻译](seq2seq_translation_tutorial.md)
* [强化学习(DQN)教程](reinforcement_q_learning.md)
* [Writing Distributed Applications with PyTorch](dist_tuto.md)
* [空间转换网络 (Spatial Transformer Networks) 教程](spatial_transformer_tutorial.md)
* [高级教程](advanced_tutorials.md)
* [用 PyTorch 做 神经转换 (Neural Transfer)](neural_style_tutorial.md)
* [使用 numpy 和 scipy 创建扩展](numpy_extensions_tutorial.md)
* [使用 ONNX 将模型从 PyTorch 迁移到 Caffe2 和 Mobile](super_resolution_with_caffe2.md)
* [为 pytorch 自定义 C 扩展](c_extension.md)
* [中文文档](doc.md)
* [介绍](notes.md)
* [自动求导机制](notes_autograd.md)
* [广播语义](notes_broadcasting.md)
* [CUDA 语义](notes_cuda.md)
* [扩展 PyTorch](notes_extending.md)
* [多进程的最佳实践](notes_multiprocessing.md)
* [序列化语义](notes_serialization.md)
* [Package 参考](package_reference.md)
* [torch](torch.md)
* [torch.Tensor](tensors.md)
* [torch.sparse](sparse.md)
* [torch.Storage](storage.md)
* [torch.nn](nn.md)
* [torch.optim](optim.md)
* [Automatic differentiation package - torch.autograd](autograd.md)
* [Probability distributions - torch.distributions](distributions.md)
* [Multiprocessing package - torch.multiprocessing](multiprocessing.md)
* [Distributed communication package - torch.distributed](distributed.md)
* [Legacy package - torch.legacy](legacy.md)
* [torch.cuda](cuda.md)
* [torch.utils.ffi](ffi.md)
* [torch.utils.data](data.md)
* [torch.utils.model_zoo](model_zoo.md)
* [torch.onnx](onnx.md)
* [torchvision 参考](torchvision_reference.md)
* [torchvision](torchvision.md)
* [torchvision.datasets](datasets.md)
* [torchvision.models](models.md)
* [torchvision.transforms](transforms.md)
* [torchvision.utils](utils.md)
* [PyTorch 0.3 中文文档 & 教程](README.md)
* [中文教程](tut.md)
* [初学者教程](beginner_tutorials.md)
* [PyTorch 深度学习: 60 分钟极速入门教程](deep_learning_60min_blitz.md)
* [PyTorch 是什么?](blitz_tensor_tutorial.md)
* [自动求导: 自动微分](blitz_autograd_tutorial.md)
* [神经网络](blitz_neural_networks_tutorial.md)
* [训练一个分类器](blitz_cifar10_tutorial.md)
* [可选: 数据并行](blitz_data_parallel_tutorial.md)
* [PyTorch for former Torch users](former_torchies_tutorial.md)
* [Tensors](former_torchies_tensor_tutorial.md)
* [Autograd (自动求导)](former_torchies_autograd_tutorial.md)
* [nn package](former_torchies_nn_tutorial.md)
* [Multi-GPU examples](former_torchies_parallelism_tutorial.md)
* [跟着例子学习 PyTorch](pytorch_with_examples.md)
* [Warm-up: numpy](pytorch_with_examples_warm-up-numpy.md)
* [PyTorch: Tensors](pytorch_with_examples_pytorch-tensors.md)
* [PyTorch: 变量和autograd](pytorch_with_examples_pytorch-variables-and-autograd.md)
* [PyTorch: 定义新的autograd函数](pytorch_with_examples_pytorch-defining-new-autograd-functions.md)
* [TensorFlow: 静态图](pytorch_with_examples_tensorflow-static-graphs.md)
* [PyTorch: nn包](pytorch_with_examples_pytorch-nn.md)
* [PyTorch: optim包](pytorch_with_examples_pytorch-optim.md)
* [PyTorch: 定制化nn模块](pytorch_with_examples_pytorch-custom-nn-modules.md)
* [PyTorch: 动态控制流程 + 权重共享](pytorch_with_examples_pytorch-control-flow-weight-sharing.md)
* [迁移学习教程](transfer_learning_tutorial.md)
* [数据加载和处理教程](data_loading_tutorial.md)
* [针对NLP的Pytorch深度学习](deep_learning_nlp_tutorial.md)
* [PyTorch介绍](nlp_pytorch_tutorial.md)
* [PyTorch深度学习](nlp_deep_learning_tutorial.md)
* [词汇嵌入:编码词汇语义](nlp_word_embeddings_tutorial.md)
* [序列模型和 LSTM 网络(长短记忆网络)](nlp_sequence_models_tutorial.md)
* [高级教程: 作出动态决策和 Bi-LSTM CRF](nlp_advanced_tutorial.md)
* [中级教程](intermediate_tutorials.md)
* [用字符级RNN分类名称](char_rnn_classification_tutorial.md)
* [基与字符级RNN(Char-RNN)的人名生成](char_rnn_generation_tutorial.md)
* [用基于注意力机制的seq2seq神经网络进行翻译](seq2seq_translation_tutorial.md)
* [强化学习(DQN)教程](reinforcement_q_learning.md)
* [Writing Distributed Applications with PyTorch](dist_tuto.md)
* [空间转换网络 (Spatial Transformer Networks) 教程](spatial_transformer_tutorial.md)
* [高级教程](advanced_tutorials.md)
* [用 PyTorch 做 神经转换 (Neural Transfer)](neural_style_tutorial.md)
* [使用 numpy 和 scipy 创建扩展](numpy_extensions_tutorial.md)
* [使用 ONNX 将模型从 PyTorch 迁移到 Caffe2 和 Mobile](super_resolution_with_caffe2.md)
* [为 pytorch 自定义 C 扩展](c_extension.md)
* [中文文档](doc.md)
* [介绍](notes.md)
* [自动求导机制](notes_autograd.md)
* [广播语义](notes_broadcasting.md)
* [CUDA 语义](notes_cuda.md)
* [扩展 PyTorch](notes_extending.md)
* [多进程的最佳实践](notes_multiprocessing.md)
* [序列化语义](notes_serialization.md)
* [Package 参考](package_reference.md)
* [torch](torch.md)
* [torch.Tensor](tensors.md)
* [torch.sparse](sparse.md)
* [torch.Storage](storage.md)
* [torch.nn](nn.md)
* [torch.optim](optim.md)
* [Automatic differentiation package - torch.autograd](autograd.md)
* [Probability distributions - torch.distributions](distributions.md)
* [Multiprocessing package - torch.multiprocessing](multiprocessing.md)
* [Distributed communication package - torch.distributed](distributed.md)
* [Legacy package - torch.legacy](legacy.md)
* [torch.cuda](cuda.md)
* [torch.utils.ffi](ffi.md)
* [torch.utils.data](data.md)
* [torch.utils.model_zoo](model_zoo.md)
* [torch.onnx](onnx.md)
* [torchvision 参考](torchvision_reference.md)
* [torchvision](torchvision.md)
* [torchvision.datasets](datasets.md)
* [torchvision.models](models.md)
* [torchvision.transforms](transforms.md)
* [torchvision.utils](utils.md)
# 高级教程
\ No newline at end of file
# Automatic differentiation package - torch.autograd
> 译者:[@ZhenLei Xu](https://github.com/HadXu)
>
> 校对者:[@青梅往事](https://github.com/2556120684)
torch.autograd 提供了类和函数用来对任意标量函数进行求导.只需要对已有的代码进行微小的改变-只需要将所有的 tensors 包含在 `Variable` 对象中即可.
```py
torch.autograd.backward(variables, grad_variables=None, retain_graph=None, create_graph=None, retain_variables=None)
```
给定图某一个的节点变量variables,计算对该变量求导的梯度和.
计算图可以通过链式法则求导.如果任何 `variables` 都是非标量(比如 他们的 data 属性中有多个元素)并且需要求导, 那么此函数需要指定 `grad_variables`. 它的长度应该和variables的长度匹配,里面保存了相关 variable 的梯度 (对于不需要 gradient tensor 的 variable, 应制定为 None).
此函数累积叶子节点 variables 计算的梯度 - 调用此函数之前应先将叶子节点 variables 梯度置零.
参数:
* `variables (Variable 列表)`: 被求微分的叶子节点.
* `grad_variables ((Tensor, Variable 或 None) 列表)`:对应 variable 的梯度. 任何张量将自动转换为变量除非`create_graph``True`. 没有值可以被指定为标量变量或者不需要被求导. 如果没有值被所有的grad_variables接受, 那么该参数是可以被省略的.
* `retain_graph (bool, 可选)`: 如果是 `False`, 该图计算过的梯度被释放掉.注意的是,几乎所有情况都设置为``True``并不是必须的并且能够高效的计算.将该 `create_graph` 参数值设置为默认即可.
* `create_graph (bool, 可选)`: 如果是 `True`, 将会建立一个梯度图, 用来求解高阶导数.默认为 `False`, 除非 `grad_variables` 拥有不止一个 易变的 Variable.
```py
torch.autograd.grad(outputs, inputs, grad_outputs=None, retain_graph=None, create_graph=None, only_inputs=True, allow_unused=False)
```
计算并返回给定值的梯度的和.
`grad_outputs` 是一个列表同时长度与 `output` 一样, 存放了预先计算 input 的梯度的和. 如果 output 不需要被求导, 那么梯度将为 `None`). 当不需要派生图时,可以将梯度作为张量,或者作为变量,在这种情况下,图将被创建.
如果参数 `only_inputs``True`, 该方法将会返回给定输入的梯度值列表.如果为 `False`, 那么遗留下来的所有叶子节点的梯度都会被计算, 被且会被列加到 `.grad` 参数中.
参数:
* `outputs (变量序列)`: 梯度函数的返回值.
* `inputs (变量序列)`: 需要计算的梯度的输入 (并且不会被累加到 `.grad` 参数中).
* `grad_outputs (张量或变量序列)`: 每一个输出的梯度. 所有的张量都会变成变量并且是可变的除非参数 `create_graph``True`. 没有值可以被指定为标量变量或者不需要变化的值. 如果所有 grad_variabls 都可以接受 None 值,那么这个参数是可选的.
* `retain_graph (bool, 可选)`: 如果是 `False`, 用于计算 grad 的图将被释放. 几乎所有情况都设置为``True`` 并不是必须的并且能够高效地运行. 默认与 `create_graph` 参数一样.
* `create_graph (bool, 可选)`: 如果是 `True`, 梯度图将会被建立,用来求解高阶导数. 默认为 `False` , 除非参数 `grad_variables` 包含不只一个变量.
* `only_inputs (bool, 可选)`: 如果是 `True`, 叶子节点的导数将会在图中, 但是不会出现在参数 `inputs` 也不会被计算以及累加. 默认为 `True`.
* `allow_unused (bool, 可选)`: 如果是 `False`, 指定计算输出时未使用的输入(因此它们的 grad 始终为零)是错误的. 默认为 `False`.
## Variable (变量)
### API compatibility
Variable API 几乎与常规 Tensor API 相同(一些会覆盖梯度计算输入的内置方法除外). 在大多数情况下, 变量量可以安全地替换张量并且代码将保持正常工作. 因为这个, 我们没有记录变量上的所有操作, 你应该参阅 [`torch.Tensor`](tensors.html#torch.Tensor "torch.Tensor") 文档来查看变量上的所有操作.
### In-place operations on Variables
在 autograd 支持就地操作是一件困难的事情, 在大多数情况下我们不鼓励使用. Autograd 积极的缓冲区释放和重用使得它非常高效, 而且很少有就地操作实际上大量地降低了内存使用量的情况. 除非你正在大量的的内存压力下运行, 否则你可能永远不需要使用它们.
### In-place correctness checks
所有的 `Variable` 跟踪适用于它们的就地操作, 并且如果实现检测到一个变量是否被其中一个函数后台保存, 但是之后它被就地修改了, 会在开始求导时会报出异常. 这确保了如果你在就地使用函数并没有看到任何错误, 你可以肯定的是计算变量是正确的.
```py
class torch.autograd.Variable
```
封装一个张量用来各种操作.
变量是张量对象周围的轻包装,能够拥有导数等数据, 这个引用允许回溯整个操作链创建数据. 如果变量已经由用户创建, 它的 grad_fn 为 `None` 我们称之为叶子节点.
由于 autograd 只支持标量值函数微分, grad 大小始终与数据大小匹配. 此外,导数通常只分配 叶变量,否则将始终为零.
参数:
* `data`: 包裹任何类型的张量.
* `grad`: 变量保持类型和位置匹配的变量 `.data`. 这个属性是懒惰的分配,不能被重新分配.
* `requires_grad`: 指示变量是否已被使用的布尔值由包含任何变量的子图创建,需要它. 有关更多详细信息,请参阅 excluded-subgraphs.只能在叶变量上进行更改.
* `volatile`: 布尔值表示应该使用变量推理模式,即不保存历史. 查看 [反向排除 subgraphs (子图)](notes/autograd.html#excluding-subgraphs) 更多细节. 只能在叶变量上进行更改.
* `is_leaf`: 指示是否为叶子节点,即是否由用户创建的节点.
* `grad_fn`: 导数函数跟踪.
参数:
* `data (任何 tensor 类)`: 用来包装的张量.
* `requires_grad (bool)`: 指示是否要被求导. **仅限关键字.**
* `volatile (bool)`: 指示是否可变. **仅限关键字.**
```py
backward(gradient=None, retain_graph=None, create_graph=None, retain_variables=None)
```
给定图叶子节点计算导数.
该图使用链式规则进行计算. 如果变量是非标量(即其数据具有多个元素)并且需要 改变,该功能另外需要指定“梯度”.它应该是一个包含匹配类型和位置的张量 微分函数的梯度w.r.t. `self` .
这个功能在叶子上累积梯度 - 你可能需要调用之前将它们置零.
参数:
* `gradient (Tensor, Variable or None)`: 计算变量的梯度. 如果是张量,则会自动转换到一个变量,这是挥发性的,除非 `create_graph` 为真.没有值可以被指定为标量变量或那些 不要求毕业. 如果一个None值是可以接受的这个参数是可选的.
* `retain_graph (bool, 可选)`: 如果 “False” ,则用于计算的图形导数将被释放. 请注意,在几乎所有情况下设置这个选项为 True 是不需要的,通常可以解决在一个更有效的方式. 默认值为`create_graph`.
* `create_graph (bool, 可选)`: 如果“真”,派生图将会被构造,允许计算更高阶的导数. 默认为 `False`,除非 `gradient` 是一个volatile变量.
```py
detach()
```
将一个Variable从创建它的图中分离,并把它设置成 leaf variable.
返回变量使用与原始数据张量相同的数据张量,其中任何一个的就地修改都将被看到,并可能触发 错误在正确性检查.
```py
detach_()
```
将一个 Variable 从创建它的图中分离,并把它设置成 leaf variable.
```py
register_hook(hook)
```
注册一个backward钩子.
每次gradients被计算的时候,这个 hook 都被调用 .hook 应该拥有以下签名:
> hook(grad) -&gt; Variable or None
hook不应该修改它的输入,但是它可以选择性的返回一个替代当前梯度的新梯度.
这个函数返回一个 句柄 (handle).它有一个方法 handle.remove(),可以用这个方法将 hook 从 module 移除.
示例:
```py
>>> v = Variable(torch.Tensor([0, 0, 0]), requires_grad=True)
>>> h = v.register_hook(lambda grad: grad * 2) # double the gradient
>>> v.backward(torch.Tensor([1, 1, 1]))
>>> v.grad.data
2
2
2
[torch.FloatTensor of size 3]
>>> h.remove() # removes the hook
```
```py
retain_grad()
```
为非叶变量启用 .grad 属性.
## Function (函数)
```py
class torch.autograd.Function
```
记录操作历史记录并定义区分操作的方法.
> 每个执行在 Varaibles 上的 operation 都会创建一个 Function 对象,这个 Function 对象执行计算工作,同时记录下来.这个历史以有向无环图的形式保存下来, 有向图的节点为 functions ,有向图的边代表数据依赖关系 (input&lt;-output).之后,当 backward 被调用的时候,计算图以拓扑顺序处理,通过调用每个 Function 对象的 backward(), 同时将返回的梯度传递给下一个 Function.
通常情况下,用户能和 Functions 交互的唯一方法就是创建 Function 的子类,定义新的 operation. 这是扩展 torch.autograd 的推荐方法.
每个 Function 只被使用一次(在forward过程中).
参数: `requires_grad`: 布尔类型依赖于方法 `backward()` 会不会还会被使用.
比如:
```py
>>> class Exp(Function):
>>>
>>> @staticmethod
>>> def forward(ctx, i):
>>> result = i.exp()
>>> ctx.save_for_backward(result)
>>> return result
>>>
>>> @staticmethod
>>> def backward(ctx, grad_output):
>>> result, = ctx.saved_variables
>>> return grad_output * result
```
_static_ `backward`(_ctx_, _*grad_outputs_)[[source]](_modules/torch/autograd/function.html#Function.backward)
定义反向传播操作
这个方法将会被继承他的所有子类覆盖.
第一个参数为上下文参数, 接下来可以输入任何张量或变量 (张量或其他类型), 并且有多个返回值, 并且为函数 `forward()` 的输入. 每个参数都是给定输出的导数, 并且每一个输出都是输入的导数.
上下文可以用来检索转发过程中保存的变量.
```py
static forward(ctx, *args, **kwargs)
```
进行操作.
这个方法将会被继承他的所有子类覆盖.
第一个参数为上下文参数,接下来可以输入任何张量或变量 (张量或其他类型).
上下文可以用来存储可以在回传期间检索的变量.
## Profiler(分析器)
Autograd 包含一个分析器, 可以让你检查你的模型在CPU 和 GPU 上不同运算的成本. 目前实现有两种模式 - 只使用 CPU 的 `profile`. 和基于 nvprof (注册 CPU 和 GPU 活动) 的方式使用 `emit_nvtx`.
```py
class torch.autograd.profiler.profile(enabled=True)
```
结果的评价指标.
参数:`enabled (bool, 可选)` – 如果设置为 False ,则没有评价指标. Default: `True`.
示例:
```py
>>> x = Variable(torch.randn(1, 1), requires_grad=True)
>>> with torch.autograd.profiler.profile() as prof:
... y = x ** 2
... y.backward()
>>> # NOTE: some columns were removed for brevity
... print(prof)
------------------------------------- --------------- ---------------
Name CPU time CUDA time
------------------------------------- --------------- ---------------
PowConstant 142.036us 0.000us
N5torch8autograd9GraphRootE 63.524us 0.000us
PowConstantBackward 184.228us 0.000us
MulConstant 50.288us 0.000us
PowConstant 28.439us 0.000us
Mul 20.154us 0.000us
N5torch8autograd14AccumulateGradE 13.790us 0.000us
N5torch8autograd5CloneE 4.088us 0.000us
```
```py
export_chrome_trace(path)
```
将EventList导出为Chrome跟踪工具文件.
断点能够通过 `chrome://tracing` URL来读取.
参数:`path (str)` – 制定断点写的路径.
```py
key_averages()
```
平均所有的功能指标通过他们的键.
返回值:包含 FunctionEventAvg 对象的 EventList.
```py
table(sort_by=None)
```
打印操作表
参数:`sort_by (str, 可选)` – 用来对参数进行排序. 默认情况下,它们以与登记相同的顺序打印. 有效的键: `cpu_time`, `cuda_time`, `cpu_time_total`, `cuda_time_total`, `count`.
返回值:包含表的字符串.
```py
total_average()
```
所有事件的平均指标.
返回值:一个 FunctionEventAvg 对象.
```py
class torch.autograd.profiler.emit_nvtx(enabled=True)
```
使每个autograd操作都发出一个NVTX范围的上下文管理器.
如下使用是正确的:
```py
nvprof --profile-from-start off -o trace_name.prof -- <regular command here>
```
不幸的是,没有办法强制nvprof刷新收集到的数据到磁盘,因此对于 CUDA 分析,必须使用此上下文管理器进行注释 nvprof 跟踪并等待进程在检查之前退出. 然后,可以使用NVIDIA Visual Profiler(nvvp)来显示时间轴,或者 `torch.autograd.profiler.load_nvprof()` 可以加载检查结果.
参数:`enabled (bool, 可选)` – 如果设置为 False ,则没有评价指标. 默认: `True`.
示例:
```py
>>> with torch.cuda.profiler.profile():
... model(x) # Warmup CUDA memory allocator and profiler
... with torch.autograd.profiler.emit_nvtx():
... model(x)
```
```py
torch.autograd.profiler.load_nvprof(path)
```
打开 nvprof trace 文件.
参数:`path (str)` – nvprof trace 文件路径.
# 初学者教程
\ No newline at end of file
# 自动求导: 自动微分
> 译者:[@小王子](https://github.com/VPrincekin)
>
> 校对者:[@李子文](https://github.com/liziwenzzzz)
PyTorch 中所有神经网络的核心是 `autograd` 自动求导包. 我们先来简单介绍一下, 然后我们会去训练我们的第一个神经网络.
`autograd` 自动求导包针对张量上的所有操作都提供了自动微分操作. 这是一个逐个运行的框架, 这意味着您的反向传播是由您的代码如何运行来定义的, 每个单一的迭代都可以不一样.
让我们用一些更简单的术语与例子来了解这些套路.
## Variable(变量)
`autograd.Variable` 是包的核心类. 它包装了张量, 并且支持几乎所有的操作. 一旦你完成了你的计算, 你就可以调用 `.backward()` 方法, 然后所有的梯度计算会自动进行.
你还可以通过 `.data` 属性来访问原始的张量, 而关于该 variable(变量)的梯度会被累计到 `.grad` 上去.
![Variable](img/53342bedc6e02d3774e2d0a899a142bd.jpg)
Variable
还有一个针对自动求导实现来说非常重要的类 - `Function`.
`Variable``Function` 是相互联系的, 并且它们构建了一个非循环的图, 编码了一个完整的计算历史信息. 每一个 variable(变量)都有一个 `.grad_fn` 属性, 它引用了一个已经创建了 `Variable``Function` (除了用户创建的 `Variable` 之外 - 它们的 `grad_fn``None` ).
如果你想计算导数, 你可以在 `Variable` 上调用 `.backward()` 方法. 如果 `Variable` 是标量的形式(例如, 它包含一个元素数据), 你不必指定任何参数给 `backward()`, 但是, 如果它有更多的元素. 你需要去指定一个 `grad_output` 参数, 该参数是一个匹配 shape(形状)的张量.
```py
import torch
from torch.autograd import Variable
```
创建 variable(变量):
```py
x = Variable(torch.ones(2, 2), requires_grad = True)
print(x)
```
variable(变量)的操作:
```py
y = x + 2
print(y)
```
`y` 由操作创建,所以它有 `grad_fn` 属性.
```py
print(y.grad_fn)
```
y 的更多操作
```py
z = y * y * 3
out = z.mean()
print(z, out)
```
## 梯度
我们现在开始了解反向传播, `out.backward()``out.backward(torch.Tensor([1.0]))` 这样的方式一样
```py
out.backward()
```
但因 d(out)/dx 的梯度
```py
print(x.grad)
```
你应该得到一个 `4.5` 的矩阵. 让我们推导出 `out` _Variable_ “![o](img/tex-d95679752134a2d9eb61dbd7b91c4bcc.gif)”. 我们有 ![o = \frac{1}{4}\sum_i z_i](img/tex-ba11185b8ae8744e5adfdac1ca62dcfb.gif), ![z_i = 3(x_i+2)^2](img/tex-f7eff769a5663e4412e4e6483638f4c9.gif) 和 ![z_i\bigr\rvert_{x_i=1} = 27](img/tex-f1a50245be3659871451046c9482df17.gif). 因此, ![\frac{\partial o}{\partial x_i} = \frac{3}{2}(x_i+2)](img/tex-ed2f2fc7d6057bacf602691edf5f1df7.gif), 所以 ![\frac{\partial o}{\partial x_i}\bigr\rvert_{x_i=1} = \frac{9}{2} = 4.5](img/tex-c2787604874dd1fdfa79483e5366c8df.gif).
你可以使用自动求导来做很多有趣的事情
```py
x = torch.randn(3)
x = Variable(x, requires_grad = True)
y = x * 2
while y.data.norm() < 1000:
y = y * 2
print(y)
```
```py
gradients = torch.FloatTensor([0.1, 1.0, 0.0001])
y.backward(gradients)
print(x.grad)
```
**稍候阅读:**
`Variable``Function` 的文档请参阅 [http://pytorch.apachecn.org/cn/docs/0.3.0/autograd.html](http://pytorch.apachecn.org/cn/docs/0.3.0/autograd.html)
\ No newline at end of file
# 训练一个分类器
> 译者:[@小王子](https://github.com/VPrincekin)
>
> 校对者:[@李子文](https://github.com/liziwenzzzz)
就是这个, 你已经看到了如何定义神经网络, 计算损失并更新网络的权重.
现在你可能会想,
## 数据呢?
一般来说, 当你不得不处理图像, 文本, 音频或者视频数据时, 你可以使用标准的 Python 包将数据加载到一个 numpy 数组中. 然后你可以将这个数组转换成一个 `torch.*Tensor`.
* 对于图像, 会用到的包有 Pillow, OpenCV .
* 对于音频, 会用的包有 scipy 和 librosa.
* 对于文本, 原始 Python 或基于 Cython 的加载, 或者 NLTK 和 Spacy 都是有用的.
特别是对于 `vision`, 我们已经创建了一个叫做 `torchvision`, 其中有对普通数据集如 Imagenet, CIFAR10, MNIST 等和用于图像数据的转换器, 即 `torchvision.datasets``torch.utils.data.DataLoader`.
这提供了巨大的便利, 避免了编写重复代码.
在本教程中, 我们将使用 CIFAR10 数据集. 它有: 'airplane', 'automobile', 'bird', 'cat', 'deer','dog', 'frog', 'horse', 'ship', 'truck' 这些类别. CIFAR10 中的图像大小为 3x32x32 , 即 32x32 像素的 3 通道彩色图像.
![cifar10](img/cb805abc7e02147df7cad524404cecf6.jpg)
cifar10
## 训练一个图像分类器
我们将按顺序执行以下步骤:
1. 加载 CIFAR10 测试和训练数据集并规范化 `torchvision`
2. 定义一个卷积神经网络
3. 定义一个损失函数
4. 在训练数据上训练网络
5. 在测试数据上测试网络
### 1\. 加载并规范化 CIFAR10
使用 `torchvision`, 加载 CIFAR10 非常简单.
```py
import torch
import torchvision
import torchvision.transforms as transforms
```
torchvision 数据集的输出是范围 [0, 1] 的 PILImage 图像. 我们将它们转换为归一化范围是[-1,1]的张量
```py
transform = transforms.Compose(
[transforms.ToTensor(),
transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])
trainset = torchvision.datasets.CIFAR10(root='./data', train=True,
download=True, transform=transform)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=4,
shuffle=True, num_workers=2)
testset = torchvision.datasets.CIFAR10(root='./data', train=False,
download=True, transform=transform)
testloader = torch.utils.data.DataLoader(testset, batch_size=4,
shuffle=False, num_workers=2)
classes = ('plane', 'car', 'bird', 'cat',
'deer', 'dog', 'frog', 'horse', 'ship', 'truck')
```
让我们展示一些训练图像, 只是为了好玩 (0.0).
```py
import matplotlib.pyplot as plt
import numpy as np
# 定义函数来显示图像
def imshow(img):
img = img / 2 + 0.5 # 非标准化
npimg = img.numpy()
plt.imshow(np.transpose(npimg, (1, 2, 0)))
# 得到一些随机的训练图像
dataiter = iter(trainloader)
images, labels = dataiter.next()
# 显示图像
imshow(torchvision.utils.make_grid(images))
# 输出类别
print(' '.join('%5s' % classes[labels[j]] for j in range(4)))
```
### 2\. 定义一个卷积神经网络
从神经网络部分复制神经网络, 并修改它以获取 3 通道图像(而不是定义的 1 通道图像).
```py
from torch.autograd import Variable
import torch.nn as nn
import torch.nn.functional as F
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.conv1 = nn.Conv2d(3, 6, 5)
self.pool = nn.MaxPool2d(2, 2)
self.conv2 = nn.Conv2d(6, 16, 5)
self.fc1 = nn.Linear(16 * 5 * 5, 120)
self.fc2 = nn.Linear(120, 84)
self.fc3 = nn.Linear(84, 10)
def forward(self, x):
x = self.pool(F.relu(self.conv1(x)))
x = self.pool(F.relu(self.conv2(x)))
x = x.view(-1, 16 * 5 * 5)
x = F.relu(self.fc1(x))
x = F.relu(self.fc2(x))
x = self.fc3(x)
return x
net = Net()
```
### 3\. 定义一个损失函数和优化器
我们使用交叉熵损失函数( CrossEntropyLoss )和随机梯度下降( SGD )优化器.
```py
import torch.optim as optim
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)
```
### 4\. 训练网络
这是事情开始变得有趣的时候. 我们只需循环遍历数据迭代器, 并将输入提供给网络和优化器.
```py
for epoch in range(2): # 循环遍历数据集多次
running_loss = 0.0
for i, data in enumerate(trainloader, 0):
# 得到输入数据
inputs, labels = data
# 包装数据
inputs, labels = Variable(inputs), Variable(labels)
# 梯度清零
optimizer.zero_grad()
# forward + backward + optimize
outputs = net(inputs)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
# 打印信息
running_loss += loss.data[0]
if i % 2000 == 1999: # 每2000个小批量打印一次
print('[%d, %5d] loss: %.3f' %
(epoch + 1, i + 1, running_loss / 2000))
running_loss = 0.0
print('Finished Training')
```
### 5\. 在测试数据上测试网络
我们在训练数据集上训练了2遍网络, 但是我们需要检查网络是否学到了什么.
我们将通过预测神经网络输出的类标签来检查这个问题, 并根据实际情况进行检查. 如果预测是正确的, 我们将样本添加到正确预测的列表中.
好的, 第一步. 让我们显示测试集中的图像以便熟悉.
```py
dataiter = iter(testloader)
images, labels = dataiter.next()
# 打印图像
imshow(torchvision.utils.make_grid(images))
print('GroundTruth: ', ' '.join('%5s' % classes[labels[j]] for j in range(4)))
```
好的, 现在让我们看看神经网络认为这些例子是什么:
```py
outputs = net(Variable(images))
```
输出的是10个类别的能量. 一个类别的能量越高, 则可以理解为网络认为越多的图像是该类别的. 那么, 让我们得到最高能量的索引:
```py
_, predicted = torch.max(outputs.data, 1)
print('Predicted: ', ' '.join('%5s' % classes[predicted[j]]
for j in range(4)))
```
结果看起来不错.
让我们看看网络如何在整个数据集上执行.
```py
correct = 0
total = 0
for data in testloader:
images, labels = data
outputs = net(Variable(images))
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
correct += (predicted == labels).sum()
print('Accuracy of the network on the 10000 test images: %d %%' % (
100 * correct / total))
```
训练的准确率远比随机猜测(准确率10%)好, 证明网络确实学到了东西.
嗯, 我们来看看哪些类别表现良好, 哪些类别表现不佳:
```py
class_correct = list(0. for i in range(10))
class_total = list(0. for i in range(10))
for data in testloader:
images, labels = data
outputs = net(Variable(images))
_, predicted = torch.max(outputs.data, 1)
c = (predicted == labels).squeeze()
for i in range(4):
label = labels[i]
class_correct[label] += c[i]
class_total[label] += 1
for i in range(10):
print('Accuracy of %5s : %2d %%' % (
classes[i], 100 * class_correct[i] / class_total[i]))
```
好的, 接下来呢?
我们如何在 GPU 上运行这些神经网络?
## 在 GPU 上训练
就像你如何将一个张量传递给GPU一样, 你将神经网络转移到GPU上. 这将递归遍历所有模块, 并将其参数和缓冲区转换为CUDA张量:
```py
net.cuda()
```
请记住, 您必须将输入和目标每一步都发送到GPU:
```py
inputs, labels = Variable(inputs.cuda()), Variable(labels.cuda())
```
如果发现在 GPU 上并没有比 CPU 提速很多, 实际上是因为网络比较小, GPU 没有完全发挥自己的真正实力.
**练习:** 尝试增加网络的宽度(第一个 `nn.Conv2d` 的参数2和第二个 `nn.Conv2d` 的参数1 它们需要是相同的数字), 看看你得到什么样的加速.
**目标达成**:
* 深入了解PyTorch的张量库和神经网络.
* 训练一个小的神经网络来分类图像.
## 在多个GPU上进行训练
如果你希望使用所有 GPU 来看更多的 MASSIVE 加速, 请查看可选 [可选: 数据并行](data_parallel_tutorial.html).
## 我下一步去哪里?
* [训练神经网络玩电子游戏](../../intermediate/reinforcement_q_learning.html)
* `在 imagenet 上训练最先进的 ResNet 网络`
* `利用生成对抗网络训练人脸生成器`
* `使用 Recurrent LSTM 网络训练单词语言模型`
* `更多的例子`
* `更多教程`
* `在论坛上讨论 PyTorch`
* `与 Slack 上与其他用户聊天`
# 可选: 数据并行
> 译者:[@小王子](https://github.com/VPrincekin)
>
> 校对者:[@李子文](https://github.com/liziwenzzzz)
**作者**: [Sung Kim](https://github.com/hunkim)[Jenny Kang](https://github.com/jennykang)
在这个教程中, 我们将会学习如何在多个GPU上使用 `DataParallel` .
在 PyTorch 中使用 GPU 是一件很容易的事情.你可以像下面这样轻松的将一个模型分配到一个 GPU 上.
```py
model.gpu()
```
随后, 你可以将你的所有张量拷贝到上面的GPU:
```py
mytensor = my_tensor.gpu()
```
此处请注意: 如果只是调用 `mytensor.gpu()` 是不会将张量拷贝到 GPU 的.你需要将它赋给一个 新的张量, 这个张量就能在 GPU 上使用了.
在多个 GPU 上运行前向、反向传播是一件很自然的事情, 然而, PyTorch 默认情况下只会用到一个GPU, 可以通过使用 `DataParallel` 使你的模型并行运行, 在多个GPU上运行这些操作也将变得非常简单:
```py
model = nn.DataParallel(model)
```
这是教程的核心内容, 我们将在随后进行详细讲解
## 导入和参数
导入PyTorch模块和参数定义
```py
import torch
import torch.nn as nn
from torch.autograd import Variable
from torch.utils.data import Dataset, DataLoader
# 参数和数据加载
input_size = 5
output_size = 2
batch_size = 30
data_size = 100
```
## 伪数据集
只需要实现 getitem 就可以轻松的生成一个(随机)伪数据集, 如下代码所示:
```py
class RandomDataset(Dataset):
def __init__(self, size, length):
self.len = length
self.data = torch.randn(length, size)
def __getitem__(self, index):
return self.data[index]
def __len__(self):
return self.len
rand_loader = DataLoader(dataset=RandomDataset(input_size, 100),
batch_size=batch_size, shuffle=True)
```
## 简单模型
在下面的示例中, 我们的模型只需要一个输入并且完成一个线性操作, 最后得 到一个输出.当然, 你可以在任意模型 (CNN,RNN,Capsule Net等) 运用 `DataParallel`
我们在模型中设置了打印指令来监控输入和输出的张量大小, 请注意批数据次序为0时的输出.
```py
class Model(nn.Module):
# Our model
def __init__(self, input_size, output_size):
super(Model, self).__init__()
self.fc = nn.Linear(input_size, output_size)
def forward(self, input):
output = self.fc(input)
print(" In Model: input size", input.size(),
"output size", output.size())
return output
```
## 创建模型和 DataParallel
这是本教程的核心部分. 首先, 我们需要生成一个模型的实例并且检测我们是否拥有多个 GPU.如果有多个GPU , 我们可以使用 `nn.DataParallel` 来包装我们的模型, 然后我们 就可以将我们的模型通过 `model.gpu()` 施加于这些GPU上.
```py
model = Model(input_size, output_size)
if torch.cuda.device_count() > 1:
print("Let's use", torch.cuda.device_count(), "GPUs!")
# dim = 0 [30, xxx] -> [10, ...], [10, ...], [10, ...] on 3 GPUs
model = nn.DataParallel(model)
if torch.cuda.is_available():
model.cuda()
```
## 运行模型
现在我们可以看到输入和输出张量的大小了.
```py
for data in rand_loader:
if torch.cuda.is_available():
input_var = Variable(data.cuda())
else:
input_var = Variable(data)
output = model(input_var)
print("Outside: input size", input_var.size(),
"output_size", output.size())
```
## 结果
当我们将输入设置为30批, 模型也产生了30批的输出.但是当我们使用多个GPU, 然后你 会得到类似下面这样的输出.
### 2 GPUs
如果有2个GPU, 我们将会看到这样的结果:
```py
# on 2 GPUs
Let's use 2 GPUs!
In Model: input size torch.Size([15, 5]) output size torch.Size([15, 2])
In Model: input size torch.Size([15, 5]) output size torch.Size([15, 2])
Outside: input size torch.Size([30, 5]) output_size torch.Size([30, 2])
In Model: input size torch.Size([15, 5]) output size torch.Size([15, 2])
In Model: input size torch.Size([15, 5]) output size torch.Size([15, 2])
Outside: input size torch.Size([30, 5]) output_size torch.Size([30, 2])
In Model: input size torch.Size([15, 5]) output size torch.Size([15, 2])
In Model: input size torch.Size([15, 5]) output size torch.Size([15, 2])
Outside: input size torch.Size([30, 5]) output_size torch.Size([30, 2])
In Model: input size torch.Size([5, 5]) output size torch.Size([5, 2])
In Model: input size torch.Size([5, 5]) output size torch.Size([5, 2])
Outside: input size torch.Size([10, 5]) output_size torch.Size([10, 2])
```
### 3 GPUs
如果有3个GPU, 我们将会看到这样的结果:
```py
Let's use 3 GPUs!
In Model: input size torch.Size([10, 5]) output size torch.Size([10, 2])
In Model: input size torch.Size([10, 5]) output size torch.Size([10, 2])
In Model: input size torch.Size([10, 5]) output size torch.Size([10, 2])
Outside: input size torch.Size([30, 5]) output_size torch.Size([30, 2])
In Model: input size torch.Size([10, 5]) output size torch.Size([10, 2])
In Model: input size torch.Size([10, 5]) output size torch.Size([10, 2])
In Model: input size torch.Size([10, 5]) output size torch.Size([10, 2])
Outside: input size torch.Size([30, 5]) output_size torch.Size([30, 2])
In Model: input size torch.Size([10, 5]) output size torch.Size([10, 2])
In Model: input size torch.Size([10, 5]) output size torch.Size([10, 2])
In Model: input size torch.Size([10, 5]) output size torch.Size([10, 2])
Outside: input size torch.Size([30, 5]) output_size torch.Size([30, 2])
In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])
In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])
In Model: input size torch.Size([2, 5]) output size torch.Size([2, 2])
Outside: input size torch.Size([10, 5]) output_size torch.Size([10, 2])
```
### 8 GPUs
如果有8个GPU, 我们将会看到这样的结果:
```py
Let's use 8 GPUs!
In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])
In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])
In Model: input size torch.Size([2, 5]) output size torch.Size([2, 2])
In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])
In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])
In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])
In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])
In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])
Outside: input size torch.Size([30, 5]) output_size torch.Size([30, 2])
In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])
In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])
In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])
In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])
In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])
In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])
In Model: input size torch.Size([2, 5]) output size torch.Size([2, 2])
In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])
Outside: input size torch.Size([30, 5]) output_size torch.Size([30, 2])
In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])
In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])
In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])
In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])
In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])
In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])
In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])
In Model: input size torch.Size([2, 5]) output size torch.Size([2, 2])
Outside: input size torch.Size([30, 5]) output_size torch.Size([30, 2])
In Model: input size torch.Size([2, 5]) output size torch.Size([2, 2])
In Model: input size torch.Size([2, 5]) output size torch.Size([2, 2])
In Model: input size torch.Size([2, 5]) output size torch.Size([2, 2])
In Model: input size torch.Size([2, 5]) output size torch.Size([2, 2])
In Model: input size torch.Size([2, 5]) output size torch.Size([2, 2])
Outside: input size torch.Size([10, 5]) output_size torch.Size([10, 2])
```
## 总结
DataParallel 自动地将数据分割并且将任务送入多个GPU上的多个模型中进行处理. 在每个模型完成任务后, DataParallel 采集和合并所有结果, 并将最后的结果呈现给你.
想了解更多信息, 请点击: [https://pytorch.org/tutorials/beginner/former_torchies/parallelism_tutorial.html](https://pytorch.org/tutorials/beginner/former_torchies/parallelism_tutorial.html).
# 神经网络
> 译者:[@小王子](https://github.com/VPrincekin)
>
> 校对者:[@李子文](https://github.com/liziwenzzzz)
神经网络可以使用 `torch.nn` 包构建.
`autograd` 实现了反向传播功能, 但是直接用来写深度学习的代码在很多情况下还是稍显复杂, `torch.nn` 是专门为神经网络设计的模块化接口. `nn` 构建于 `Autograd` 之上, 可用来定义和运行神经网络. `nn.Module``nn` 中最重要的类, 可把它看成是一个网络的封装, 包含网络各层定义以及 `forward` 方法, 调用 `forward(input)` 方法, 可返回前向传播的结果.
例如, 看看这个分类数字图像的网络:
![convnet](img/f8cf1acb14973bf5d0129c2e135b4a13.jpg)
convnet
这是一个基础的前向传播(feed-forward)网络: 接收输入, 经过层层传递运算, 得到输出.
一个典型的神经网络训练过程如下:
* 定义具有一些可学习参数(或权重)的神经网络
* 迭代输入数据集
* 通过网络处理输入
* 计算损失(输出的预测值与实际值之间的距离)
* 将梯度传播回网络
* 更新网络的权重, 通常使用一个简单的更新规则: `weight = weight - learning_rate * gradient`
## 定义网络
让我们来定义一个网络:
```py
import torch
from torch.autograd import Variable
import torch.nn as nn
import torch.nn.functional as F
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
# 卷积层 '1'表示输入图片为单通道, '6'表示输出通道数, '5'表示卷积核为5*5
# 核心
self.conv1 = nn.Conv2d(1, 6, 5)
self.conv2 = nn.Conv2d(6, 16, 5)
# 仿射层/全连接层: y = Wx + b
self.fc1 = nn.Linear(16 * 5 * 5, 120)
self.fc2 = nn.Linear(120, 84)
self.fc3 = nn.Linear(84, 10)
def forward(self, x):
#在由多个输入平面组成的输入信号上应用2D最大池化.
# (2, 2) 代表的是池化操作的步幅
x = F.max_pool2d(F.relu(self.conv1(x)), (2, 2))
# 如果大小是正方形, 则只能指定一个数字
x = F.max_pool2d(F.relu(self.conv2(x)), 2)
x = x.view(-1, self.num_flat_features(x))
x = F.relu(self.fc1(x))
x = F.relu(self.fc2(x))
x = self.fc3(x)
return x
def num_flat_features(self, x):
size = x.size()[1:] # 除批量维度外的所有维度
num_features = 1
for s in size:
num_features *= s
return num_features
net = Net()
print(net)
```
你只要在 `nn.Module` 的子类中定义了 `forward` 函数, `backward` 函数就会自动被实现(利用 `autograd` ). 在 `forward` 函数中可使用任何 Tensor 支持的操作.
> 网络的可学习参数通过 `net.parameters()` 返回, `net.named_parameters` 可同时返回学习的参数以及名称.
```py
params = list(net.parameters())
print(len(params))
print(params[0].size()) # conv1的weight
```
向前的输入是一个 `autograd.Variable`, 输出也是如此. 注意: 这个网络(LeNet)的预期输入大小是 32x32, 使用这个网上 MNIST 数据集, 请将数据集中的图像调整为 32x32.
```py
input = Variable(torch.randn(1, 1, 32, 32))
out = net(input)
print(out)
```
将网络中所有参数的梯度清零.
```py
net.zero_grad()
out.backward(torch.randn(1, 10))
```
注解:
`torch.nn` 只支持小批量(mini-batches), 不支持一次输入一个样本, 即一次必须是一个 batch.
例如, `nn.Conv2d` 的输入必须是 4 维的, 形如 `nSamples x nChannels x Height x Width`.
如果你只想输入一个样本, 需要使用 `input.unsqueeze(0)` 将 batch_size 设置为 1.
在继续之前, 让我们回顾一下迄今为止所有见过的类.
**概括:**
* `torch.Tensor` - 一个 _多维数组_.
* `autograd.Variable` - _包装张量并记录应用于其上的历史操作_. 具有和 `Tensor` 相同的 API ,还有一些补充, 如 `backward()`. 另外 _拥有张量的梯度_.
* `nn.Module` - 神经网络模块. _方便的方式封装参数_, 帮助将其移动到GPU, 导出, 加载等.
* `nn.Parameter` - 一种变量, 当被指定为 `Model` 的属性时, 它会自动注册为一个参数.
* `autograd.Function` - 实现 _autograd 操作的向前和向后定义_ . 每个 `Variable` 操作, 至少创建一个 `Function` 节点, 连接到创建 `Variable` 的函数, 并 _编码它的历史_.
**在这一点上, 我们涵盖:**
* 定义一个神经网络
* 处理输入并反向传播
**还剩下:**
* 计算损失函数
* 更新网络的权重
## 损失函数
损失函数采用 (output,target) 输入对, 并计算预测输出结果与实际目标的距离.
`nn` 包下有几种不同的 [损失函数](https://pytorch.org/docs/nn.html#loss-functions) . 一个简单的损失函数是: `nn.MSELoss` 计算输出和目标之间的均方误差
例如:
```py
output = net(input)
target = Variable(torch.arange(1, 11)) # 一个虚拟的目标
criterion = nn.MSELoss()
loss = criterion(output, target)
print(loss)
```
现在, 如果你沿着 `loss` 反向传播的方向使用 `.grad_fn` 属性, 你将会看到一个如下所示的计算图:
```py
input -> conv2d -> relu -> maxpool2d -> conv2d -> relu -> maxpool2d
-> view -> linear -> relu -> linear -> relu -> linear
-> MSELoss
-> loss
```
所以, 当我们调用 `loss.backward()`, 整个图与损失是有区别的, 图中的所有变量都将用 `.grad` 梯度累加它们的变量.
为了说明, 让我们向后走几步:
```py
print(loss.grad_fn) # MSELoss
print(loss.grad_fn.next_functions[0][0]) # Linear
print(loss.grad_fn.next_functions[0][0].next_functions[0][0]) # ReLU
```
## 反向传播
为了反向传播误差, 我们所要做的就是 `loss.backward()`. 你需要清除现有的梯度, 否则梯度会累加之前的梯度.
现在我们使用 `loss.backward()`, 看看反向传播之前和之后 `conv1` 的梯度.
```py
net.zero_grad() # 把之前的梯度清零
print('conv1.bias.grad before backward')
print(net.conv1.bias.grad)
loss.backward()
print('conv1.bias.grad after backward')
print(net.conv1.bias.grad)
```
现在, 我们已经看到了如何使用损失函数.
**稍后阅读:**
> 神经网络包包含各种模块和损失函数, 形成深度神经网络的构建模块. 完整的文件列表 [在这里](https://pytorch.org/docs/nn)
**接下来学习的唯一东西是:**
> * 更新网络的权重
## 更新权重
实践中使用的最简单的更新规则是随机梯度下降( SGD ):
> `weight = weight - learning_rate * gradient`
我们可以使用简单的 python 代码来实现这个:
```py
learning_rate = 0.01
for f in net.parameters():
f.data.sub_(f.grad.data * learning_rate)
```
然而, 当你使用神经网络时, 你需要使用各种不同的更新规则, 比如 SGD, Nesterov-SGD, Adam, RMSProp等. 为了实现这个功能, 我们建立了一个包: `torch.optim` 实现所有这些方法. 使用它非常的简单:
```py
import torch.optim as optim
# 新建一个优化器, 指定要调整的参数和学习率
optimizer = optim.SGD(net.parameters(), lr = 0.01)
# 在训练过程中:
optimizer.zero_grad() # 首先梯度清零(与 net.zero_grad() 效果一样)
output = net(input)
loss = criterion(output, target)
loss.backward()
optimizer.step() # 更新参数
```
注解:
观察如何使用手动设置梯度清零 `optimizer.zero_grad()` . 需要手动清零的原因在 `Backprop`_ 中已经说明了(梯度会累加之前的梯度).
# PyTorch 是什么?
> 译者:[@小王子](https://github.com/VPrincekin)
>
> 校对者:[@李子文](https://github.com/liziwenzzzz)
它是一个基于 Python 的科学计算包, 其主要是为了解决两类场景:
* NumPy 的替代品, 以使用 GPU 的强大加速功能
* 一个深度学习研究平台, 提供最大的灵活性和速度
## 新手入门
### Tensors(张量)
Tensors 与 NumPy 的 ndarrays 非常相似, 除此之外还可以在 GPU 上使用张量来加速计算.
```py
from __future__ import print_function
import torch
```
构建一个 5x3 的矩阵, 未初始化的:
```py
x = torch.Tensor(5, 3)
print(x)
```
构建一个随机初始化的矩阵:
```py
x = torch.rand(5, 3)
print(x)
```
获得 size:
```py
print(x.size())
```
注解:
`torch.Size` 实际上是一个 tuple(元组), 所以它支持所有 tuple(元组)的操作.
### 操作
针对操作有许多语法. 在下面的例子中, 我们来看看加法运算.
加法: 语法 1
```py
y = torch.rand(5, 3)
print(x + y)
```
加法: 语法 2
```py
print(torch.add(x, y))
```
加法: 提供一个输出 tensor 作为参数
```py
result = torch.Tensor(5, 3)
torch.add(x, y, out = result)
print(result)
```
加法: in-place(就地操作)
```py
# adds x to y
y.add_(x)
print(y)
```
注解:
任何改变张量的操作方法都是以后缀 `_` 结尾的. 例如: `x.copy_(y)`, `x.t_()`, 将改变张量 `x`.
你可以用类似Numpy的索引来处理所有的张量!
```py
print(x[:, 1])
```
改变大小: 如果你想要去改变tensor的大小, 可以使用 `torch.view`:
```py
x = torch.randn(4, 4)
y = x.view(16)
z = x.view(-1, 8) # the size -1 is inferred from other dimensions
print(x.size(), y.size(), z.size())
```
**稍候阅读:**
> 100+ Tensor 操作, 包括换位, 索引, 切片, 数学运算, 线性代数, 随机数, 等等, 都在 [这里](http://pytorch.apachecn.org/cn/docs/0.3.0/torch.html) 有描述.
## NumPy Bridge
将一个 Torch Tensor 转换为 NumPy 数组, 反之亦然.
Torch Tensor 和 NumPy 数组将会共享它们的实际的内存位置, 改变一个另一个也会跟着改变.
### 转换一个 Torch Tensor 为 NumPy 数组
```py
a = torch.ones(5)
print(a)
```
```py
b = a.numpy()
print(b)
```
查看 numpy 数组是如何改变的.
```py
a.add_(1)
print(a)
print(b)
```
### 转换 NumPy 数组为 Torch Tensor
看看改变 np 数组之后 Torch Tensor 是如何自动改变的
```py
import numpy as np
a = np.ones(5)
b = torch.from_numpy(a)
np.add(a, 1, out = a)
print(a)
print(b)
```
除了 CharTensor 之外, CPU 上的所有 Tensor 都支持与Numpy进行互相转换
## CUDA Tensors
可以使用 `.cuda` 方法将 Tensors 在GPU上运行.
```py
# 只要在 CUDA 是可用的情况下, 我们可以运行这段代码
if torch.cuda.is_available():
x = x.cuda()
y = y.cuda()
x + y
```
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
# PyTorch 深度学习: 60 分钟极速入门教程
> 译者:[@小王子](https://github.com/VPrincekin)
>
> 校对者:[@李子文](https://github.com/liziwenzzzz)
**Author**: [Soumith Chintala](http://soumith.ch)
本教程的目标:
* 更高层次地理解 PyTorch 的 Tensor (张量) 库以及神经网络.
* 学会训练一个小的神经网络用来对图像进行分类
_本教程假设您对 numpy 有基本的了解_
注解:
请确认您已经安装了 [torch](https://github.com/pytorch/pytorch)[torchvision](https://github.com/pytorch/vision) 包.
![http://pytorch.apachecn.org/cn/tutorials/_images/tensor_illustration_flat.png](img/75d27b35d421d5786f8ea5cc5470b45a.jpg)
[PyTorch 是什么?](blitz/tensor_tutorial.html#sphx-glr-beginner-blitz-tensor-tutorial-py)
![http://pytorch.apachecn.org/cn/tutorials/_images/Variable1.png](img/616522c728d2b088b499e65d7761d6e4.jpg)
[自动求导: 自动微分](blitz/autograd_tutorial.html#sphx-glr-beginner-blitz-autograd-tutorial-py)
![http://pytorch.apachecn.org/cn/tutorials/_images/mnist1.png](img/2d7fd2e65de866a644e368ee88d9b431.jpg)
[神经网络](blitz/neural_networks_tutorial.html#sphx-glr-beginner-blitz-neural-networks-tutorial-py)
![http://pytorch.apachecn.org/cn/tutorials/_images/cifar101.png](img/f9c93128249858e80aba15672aa47d64.jpg)
[训练一个分类器](blitz/cifar10_tutorial.html#sphx-glr-beginner-blitz-cifar10-tutorial-py)
![http://pytorch.apachecn.org/cn/tutorials/_images/data_parallel.png](img/3648d88c9df1506d7e1f52ebd9b04b09.jpg)
[可选: 数据并行](blitz/data_parallel_tutorial.html#sphx-glr-beginner-blitz-data-parallel-tutorial-py)
\ No newline at end of file
# 针对NLP的Pytorch深度学习
> 译者:[@JingTao](https://github.com/jingwangfei)、[@friedhelm739](https://github.com/friedhelm739)
**作者**: [Robert Guthrie](https://github.com/rguthrie3/DeepLearningForNLPInPytorch)
本教程将带你浏览基于Pytorch深度学习编程的核心思想.其中很多思想(例如计算图形抽象化以及自动求导) 并不是Pytorch特有的,他们和任何深度学习工具包都是相关的.
本教程针对那些从未在任何深度学习框架下编写过代码的人(例如TensorFlow,Theano, Keras, Dynet),并 专注于NLP.它提出了应用知识中NLP的核心问题:词性标注,语言建模等.它同样提出了在AI入门级别熟悉神经 网络(例如Russel和Norvig的书).通常情况下, 这些课程包括了基于前馈神经网络的基本的反向传播算法, 并使你了解到它们是线性和非线性组成的链条.本教程目的使你开始编写深度学习代码并给你首要必备的知识.
提示一下, 这仅关乎于 _模型_ , 并非是数据.针对所有模型,我仅仅提出了一些低纬度的例子 以便于你可以观察当训练时权重的变化.如果你有一些真实数据去尝试,可以将本教程中模型 复制下并将数据应用到模型上.
![http://pytorch.apachecn.org/cn/tutorials/_images/sphx_glr_pytorch_tutorial_thumb.png](img/dda91356348c84bcd84a220e521b4d96.jpg)
[PyTorch介绍](nlp/pytorch_tutorial.html#sphx-glr-beginner-nlp-pytorch-tutorial-py)
![http://pytorch.apachecn.org/cn/tutorials/_images/sphx_glr_deep_learning_tutorial_thumb.png](img/ebc2ff9705d5819431a5f5f5f8dec724.jpg)
[PyTorch深度学习](nlp/deep_learning_tutorial.html#sphx-glr-beginner-nlp-deep-learning-tutorial-py)
![http://pytorch.apachecn.org/cn/tutorials/_images/sphx_glr_word_embeddings_tutorial_thumb.png](img/5e01fc89a0e79c22304558b04ce1b21e.jpg)
[词汇嵌入:编码词汇语义](nlp/word_embeddings_tutorial.html#sphx-glr-beginner-nlp-word-embeddings-tutorial-py)
![http://pytorch.apachecn.org/cn/tutorials/_images/sphx_glrsequencemodels_tutorial_thumb.png](img/d039aef9c9fb8610d9dcaa67c63a2a8e.jpg)
[序列模型和 LSTM 网络(长短记忆网络)](nlp/sequence_models_tutorial.html#sphx-glr-beginner-nlp-sequence-models-tutorial-py)
![http://pytorch.apachecn.org/cn/tutorials/_images/sphx_glr_advanced_tutorial_thumb.png](img/602c0e119f456abdd0a45bf6dfcc4405.jpg)
[高级教程: 作出动态决策和 Bi-LSTM CRF](nlp/advanced_tutorial.html#sphx-glr-beginner-nlp-advanced-tutorial-py)
\ No newline at end of file
此差异已折叠。
此差异已折叠。
此差异已折叠。
# torch.utils.ffi
> 译者:[@之茗](https://github.com/mayuanucas)
>
> 校对者:[@aleczhang](http://community.apachecn.org/?/people/aleczhang)
```py
torch.utils.ffi.create_extension(name, headers, sources, verbose=True, with_cuda=False, package=False, relative_to='.', **kwargs)
```
创建并配置一个 cffi.FFI 对象, 用于构建 PyTorch 的扩展.
参数:
* `name (str)` – 包名. 可以是嵌套模块, 例如. `.ext.my_lib`.
* `headers (str 或 List[str])` – 只包含导出函数的头文件列表.
* `sources (List[str])` – 用于编译的sources列表.
* `verbose (bool, 可选)` – 如果设置为 `False`, 则不会打印输出 (默认值: True).
* `with_cuda (bool, 可选)` – 设置为 `True` 以使用 CUDA 头文件进行编译 (默认值: False)
* `package (bool, 可选)` – 设置为 `True` 以在包模式下构建 (对于要作为 pip 程序包安装的模块) (默认值: False).
* `relative_to (str, 可选)` – 构建文件的路径. 当 `package 为 True` 时需要. 最好使用 `__file__` 作为参数.
* `kwargs` – 传递给 ffi 以声明扩展的附件参数. 参考 [Extension API reference](https://docs.python.org/3/distutils/apiref.html#distutils.core.Extension) 查阅更详细内容.
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。