【读书笔记】PyTorch
复习了下pytorch。
自动求导机制
从后向排除子图
- 每个变量有两个标志:requires_grad和volatile
- requires_grad
- 如果有一个单一的输入操作需要梯度,它的输出也需要梯度,反之亦然。
- 如果其中所有的变量都不需要梯度进行,后向计算不会执行
- 如果想冻结部分模型,或者不会使用某些参数的梯度。
- volatile
- 纯粹的inference模式下推荐使用
- 一个操作甚至只有有一个 volatile的输入,输出就是volatile
- 使用volatile不需要更改模型参数的任何设置来用于inference
自动求导如何编码历史信息
- 每个变量都有一个.creator属性,指向把它作为输出的函数。
- 由Function对象作为节点组成的DAG的入口点,它们之间的引用是图的边
- 每执行一个操作,它的forward()方法被调用,它的Variable的创建者被设置为这个Function。
Variable上的In-place操作
- 大多数情况下不使用它们。原因如下:
- 覆盖梯度计算所需的值
- 每个in-place操作实际上需要实现重写计算图
In-place正确性检查
- 每个变量保留有version counter,每次在操作中使用时会递增。
- 一旦访问self.saved_tensors,它将被检查,大于保存值则错误
CUDA语义
cuda
- torch.cuda会记录当前选择的GPU,并且分配所有的CUDA张量将在上面创建。
- 张量一旦被分配,可以对其进行操作,而不考虑所选择的设备。结果存在设备上。
- 默认情况下不支持跨GPU操作。除非启用对等存储器访问,否则对分布不同设备上的张量任何启动操作的尝试都会引发错误
最佳实践
- 使用固定的内存缓冲区
- CPU张量和存储开放了一个pin_memory()方法,它返回该对象的副本,而它的数据放在固定区域中
- 一旦固定了张量或存储,就可以使用异步的GPU副本。只需要传递一个额外的async = True到cuda()的调用。p.s 数据传输和计算重叠
- 通过将pin_memory=True传递给构造函数,可以使DataLoader将batch返回到固定内存中
- 使用 nn.DataParallel 替代 multiprocessing
- 大多数涉及批量输入和多个GPU的情况应默认使用DataParallel来使用多个GPU
- 调用multiprocessing来利用CUDA模型存在重要的注意事项
扩展PyTorch
扩展torch.autograd
- 想要添加一个新的operation到autograd的话,需要继承class function
- 每个新的operation(function)需要实现三个方法:
- init(optional):如果operation包含非Variable参数,就传入。
- forward():在里面编写执行此operation的代码。forward()的参数只能是variable
- backward():梯度计算公式。参数的个数和forward返回值个数一样,每个参数代表传回到此operation的梯度。
扩展 torch.nn
- nn有两种接口-modules和他们的functional版本。在扩展layer的时候,使用modules。如果不需要参数的话,那么建议使用functional
- 增加一个operation的funtional版本
- 增加一个module。添加一个新的module需要实现一个function的两个方法:
- init(optional):输入参数。同时初始化parameters和buffers
- forward():实例化一个执行operation的function.
多进程最佳实践
多进程
- torch.multiprocessing 是Pythonmultiprocessing 的替代品。
- 当Variable发送到另一个进程时,Variable.data和Variable.grad.data都将被共享。
共享CUDA张量
- 仅在Python 3中使用spawn或forkserver启动方法才支持在进程之间共享CUDA张量。
最佳实践
- 避免死锁和抵制死锁
- 最常见的死锁原因是后台线程。如果有任何线程持有锁或导入模块,并且fork被调用,会死锁和失败
- multiprocessing.Queue可能也会引起上述问题。出现问题时尝试使用multiprocessing.queues.SimpleQueue
- 重用经过队列的缓冲区
- 每次将Tensor放入multiprocessing.Queue必须将它移动到共享内存中
- 异步多进程训练
- 使用torch.multiprocessing,可以异步地训练模型,参数可以一直共享,也可以定期同步。
- 我们建议使用multiprocessing.Queue来在进程之间传递各种PyTorch对象。
序列化语义
保存模型的推荐方法
- 只保存和加载模型参数(推荐)
torch.save(the_model.state_dict().PATH) the_model = TheModelClass(*args,**kwargs) the_model.load_state_dict(torch.load(PATH))
- 保存和加载整个模型
torch.save(the_model, PATH)
the_model = torch.load(PATH)
- 但是这种情况,序列化的数据被绑定到特定类和固定目录结构,所以可能造成break
CODE
1 import torchvision 2 from torch.autograd import Variable 3 import torch 4 5 #requires_grad 6 x = Variable(torch.randn(5, 5)) 7 y = Variable(torch.randn(5, 5)) 8 z = Variable(torch.randn(5, 5),requires_grad=True) 9 a = x + y 10 print(a.requires_grad) #False 11 b = a + z 12 print(b.requires_grad) #True 13 14 15 #volatile 16 regular_input = Variable(torch.randn(5,5)) 17 volaile_input = Variable(torch.randn(5,5),volatile = True) 18 model = torchvision.models.resnet18(pretrained = True) 19 print(model(regular_input).requires_grad) #True 20 print(model(volaile_input).requires_grad) #False 21 print(model(volaile_input).volatile) #True 22 print(model(volaile_input).requires_grad) #False 23 24 #cuda 25 x = torch.cuda.FloatTensor(1) 26 # x.get_device() == 0 27 y = torch.FloatTensor(1).cuda() 28 # y.get_device() == 0 29 30 with torch.cuda.device(1): 31 #当前分配给GPU1 32 a = torch.cuda.FloatTensor(1) 33 34 b = torch.FloatTensor(1).cuda() 35 36 c = a + b 37 # c.get_device() == 1 38 z = x + y 39 # z.get_device() == 0 40 d = torch.randn(2).cuda(2) 41 #d.get_device() == 2
常用包
torch
torch:张量相关的运算,包括创建,索引,切片,连接,换位,随机抽样,序列化,并行化,数学操作等
torch.nn:包含搭建网络层的模块和一系列的损失函数(卷积,池化,BN批处理,Linear , Dropout等)
torch.nn.functional:激活函数(线性,Dropout,,relu,leaky_relu,sigmoid等)
torch.autograd:提供了类和函数用来对任意标量函数进行求导
torch.optim:各种优化算法(SGD,Adam,Adagrad等)
torch.nn.init:更改模块参数初始化方式
torch.utils.data:加载数据
torch.Tensor:一种包含单一数据类型元素的多维矩阵
torch.Storage:一个单一数据类型的连续一维数组
torchvision
torchvision.datasets: 中包含了以下数据集
- MNIST
- COCO
- LSUN Classification
- ImageFolder
- Imagenet-12
- CIFAR10 and CIFAR100
- STL10
torchvision.models:包含以下模型结构
- AlexNet
- VGG
- ResNet
- SqueezeNet
- DenseNet
torchvision.transforms:PIL.Image相关
torchvision.utils:将给定的Tensor保存成image文件