可随意转载!Update 2023.10.15

一、 PyTorch使用指南

1. 版本选择

我们复现基于Pytorch代码的时候最好使用项目里面约定的版本。一般来说有三种约束:

  • Pytorch的版本号
  • 对应的cuda的版本号
  • torchvision等Pytorch官方库

尤其是有自定义C++算子的代码复现,所有版本号必须匹配。可以下载Pytorch的extension-cpp项目来测试是否完美安装。

我们可以去官网查看版本号配对的安装包集合。

例子1:

# CUDA 11.1
# 注意"+cu111"也是版本号的一部分,它跟不带"+cu111"的同名包完全不兼容
pip install torch==1.10.0+cu111 torchvision==0.11.0+cu111 torchaudio==0.10.0 -f https://download.pytorch.org/whl/torch_stable.html

例子2:

因为网络慢的问题,我通常不会采用例子2的安装方法,我会单独下载torch本地安装(pip install xxx.whl),这个时候就要注意torchvision和torchaudio的版本号了。如果不加版本号,torch会默认cuda版本,它的查看方法是:

# 因为国内网络一般都比较慢,选择默认安装后发现cuda版本不匹配会比较耗时
# 建议指定torch版本和cuda版本做离线安装
import torch
print(torch.__version__)
print(torch.cuda.is_available())
print(torch.version.cuda)

默认安装下,Pytorch并不知道你本机的cuda版本,因此不一定兼容哦。

单机多版本cuda安装教程

PyTorch官网镜像源会下线老版本,可以在仓库下载之后再安装。

2. 性能剖析Profiler

torch.autograd.profiler.xx 记录函数的性能:

>>> x = torch.randn((1, 1), requires_grad=True)
>>> with torch.autograd.profiler.profile() as prof:
...     y = x ** 2
...     with torch.autograd.profiler.record_function("label-z"): # label the block
...         z = y ** 3
...     y.backward()
...
>>> # NOTE: some columns were removed for brevity
>>> print(prof.key_averages().table(sort_by="self_cpu_time_total"))
-----------------------------------  ---------------  ---------------  ---------------
Name                                 Self CPU total %  CPU time avg     Number of Calls
-----------------------------------  ---------------  ---------------  ---------------
pow                                  60.77%           47.470us         3
mul                                  21.73%           25.465us         2
PowBackward0                         12.03%           121.891us        1
torch::autograd::AccumulateGrad      2.70%            6.324us          1
label-z                              2.13%            12.421us         1
torch::autograd::GraphRoot           0.64%            1.503us          1
-----------------------------------  ---------------  ---------------  ---------------
Self CPU time total: 234.344us
CUDA time total: 0.000us

二、Pytorch语言特性

1.初始化数组

>>> import torch as th
>>> a = th.ones(2,3)
>>> a
tensor([[1., 1., 1.],
        [1., 1., 1.]])
>>> 
>>> 
>>> b = 2*th.ones(5,3)
>>> 
>>> 

>>> d = th.arange(0,27,1)
>>> d
tensor([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17,
        18, 19, 20, 21, 22, 23, 24, 25, 26])

2.cat方法

拼接数组, 参数:待拼接数组,待拼接数组,拼接的目标维度

除了参数3之外的数组维度都必须相等。

>>> c = th.cat( (a,b), 0 )
>>> 
>>> c
tensor([[1., 1., 1.],
        [1., 1., 1.],
        [2., 2., 2.],
        [2., 2., 2.],
        [2., 2., 2.],
        [2., 2., 2.],
        [2., 2., 2.]])

对应numpy.concatenate()

3. view方法

修改维度。类似numpy的reshape。

>>> d = th.ones(27)
>>> d
tensor([1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.,
        1., 1., 1., 1., 1., 1., 1., 1., 1.])
>>> d.view(3,3,3)
tensor([[[1., 1., 1.],
         [1., 1., 1.],
         [1., 1., 1.]],

        [[1., 1., 1.],
         [1., 1., 1.],
         [1., 1., 1.]],

        [[1., 1., 1.],
         [1., 1., 1.],
         [1., 1., 1.]]])
>>> 

4.squeeze方法和unsqueeze方法

挤压和扩张,参数表示目标维度。参数不填表示自动寻找。无法挤压和扩张则保持不变。

>>> a = th.arange(6).view(2,3)
>>> a
tensor([[0, 1, 2],
        [3, 4, 5]])
>>> b = a.unsqueeze(0)
>>> b
tensor([[[0, 1, 2],
         [3, 4, 5]]])
>>> b.squeeze()
tensor([[0, 1, 2],
        [3, 4, 5]])
>>> 

unsqueeze在numpy里面叫expand_dims

5.expand方法

把单维扩展。本身不变

>>> a = th.arange(4).view(4,1)
>>> a
tensor([[0],
        [1],
        [2],
        [3]])
>>> a.expand(-1,4)
tensor([[0, 0, 0, 0],
        [1, 1, 1, 1],
        [2, 2, 2, 2],
        [3, 3, 3, 3]])
>>> a
tensor([[0],
        [1],
        [2],
        [3]])
>>> 
>>> a.expand(4,4,4)
tensor([[[0, 0, 0, 0],
         [1, 1, 1, 1],
         [2, 2, 2, 2],
         [3, 3, 3, 3]],

        [[0, 0, 0, 0],
         [1, 1, 1, 1],
         [2, 2, 2, 2],
         [3, 3, 3, 3]],

        [[0, 0, 0, 0],
         [1, 1, 1, 1],
         [2, 2, 2, 2],
         [3, 3, 3, 3]],

        [[0, 0, 0, 0],
         [1, 1, 1, 1],
         [2, 2, 2, 2],
         [3, 3, 3, 3]]])

对应numpy叫np.broadcast_to

6. 高级索引(slice)

>>> x
array([[ 0,  1,  2],
       [ 3,  4,  5],
       [ 6,  7,  8],
       [ 9, 10, 11]])
>>> rows = np.array([[0,1],[3,3]])
>>> cols = np.array([[0,2],[0,2]])
>>> y = x[rows,cols] 
>>> y
array([[ 0,  5],
       [ 9, 11]])

7. zip 方法

把数组组合成元组(tuple)

x = [1,2,3,4,5]
y = ['a','b','c','d']
xy = zip(x,y)
print xy
[(1, 'a'), (2, 'b'), (3, 'c'), (4, 'd')]