Pytorch 的配置与基本操作
Pytorch 的配置与基本操作
Miniconda 配置 Pytorch
由于 poetry 配置 pytorch 很麻烦,所以我把 pytorch 配置在了 linux 环境下,并且采取 miniconda 作为包管理器。
到官网的 Get started 文档 选择你的 PC 端配置,可以在终端用nvidia-smi
命令查看 PC 的 CUDA
版本。我的配置是:
Pytorch Build
Stable(2.2.0)Your OS
linuxPackage
condaLanuage
pythonCompute Platform
CUDA 11.8 运行以下代码来配置环境:
conda install pytorch torchvision torchaudio pytorch-cuda=11.8 -c pytorch -c nvidia
踩坑:
如果决定采用
conda
做包管理器,就老老实实用conda
创建虚拟环境,并且在虚拟环境中安装pytorch
,GPU 加速版会大概占用 7 ~ 8 GB 空间,请注意磁盘空间的规划。不要像我一样没搞清楚,用了conda
管理环境,又反用pip
作包管理,最后这个环境整了一天才整出来
- 安装脚本
conda create -n torch python=3.9
conda activate torch
conda install pytorch torchvision torchaudio pytorch-cuda=11.8 -c pytorch -c nvidia
使用:
import torch
Tensor 创建及基本操作
x = torch.tensor([1, 2]) # 指定数据创建 tensor
y = torch.empty(2, 3) # 创建 2x3 空 tensor
x1 = torch.random(2, 3) # 创建 2x3 随机 tensor
x2 = torch.zeros(2, 3, dtype=torch.long) # 创建 long 型的 0 tensor
x3 = torch.ones(2, 3) # 创建 2x3 全 1 tensor
tuple = x1.size() # 返回一个 tuple,任何对于 tuple 的操作都可以适用
# 加法
x + y
torch.add(x, y, out=result) # 通过 out 参数指定输出
y.add_(x) # pytorch 的 inplace 操作都有在最后加上下划线
Torch 中的乘法
Torch
包中包括多种乘法方式,具体的细则可以看这篇博客
总结
torch.mul()
有广播机制,各个元素相乘torch.multiply()
与torch.mul()
相同torch.dot()
计算两向量的点积torch.mv()
计算矩阵和向量的乘积(二者一定有一个维度尺寸相同)torch.mm()
线代中严格的矩阵乘法torch.bmm()
批量矩阵相乘,比如torch.matmul()
混合型矩阵乘法,会根据输入维度自动匹配,易出错,不建议使用。
的那是该博文中没有明确写torch.matmul()
的用法,具体可以查官方文档
索引
可以采用类似 numpy 的索引,y=x[0,:]
,但是索引出的数据与原数据共享内存,修改一个另一个也会改变。
改变形状
view(*size)
可以改变tensor
的形状,同理,与原数据共享内存,可以理解为:view 仅仅是改变了对这个张量的观察角度,内部数据并未改变。
如果需要返回一个新的独立副本,应该先clone
再view
,即:x.clone().view(3,5)
\
线性代数
与 MATLAB 语法类似:
语法 | 功能 |
---|---|
trace | 矩阵的迹 |
diag | 对角线元素 |
triu/tril | 上三角或下三角矩阵 |
mm | 矩阵乘法 |
t | 矩阵转置 |
dot | 矩阵内积 |
inverse | 求逆矩阵 |
svd | 奇异值分解 |
Tensor 转 numpy
a = torch.rand(2, 3)
b = a.numpy()
numpy 转 Tensor
a = torch.rand(2, 3)
b = a.from_numpy()
注意
以上两种方法得到的 Tensor/numpy 共享内存,改变一个另一个也会改变。
Tensor
的存储和读取
torch.save(x, 'tensor.pt') # 保存
x = torch.load('tensor.pt') # 读取
Tensor
的保存支持多种数据类型,可以是Tensor
,也可以是list
和dictionary
,保存的Tensor
和读取的Tensor
具有相同的类型。Tensor
会被保存到以.pt
为后缀名的文件中。
自动求梯度
Function
对象
如果将其属性.requires_grad
设置为True
,它将开始追踪 (track) 在其上的所有操作(这样就可以利用链式法则进行梯度传播了)。完成计算后,可以调用.backward()
来完成所有梯度计算。此Tensor
的梯度将累积到.grad
属性中。
如果不想要被继续追踪,可以调用.detach()
将其从追踪记录中分离出来,这样就可以防止将来的计算被追踪,这样梯度就传不过去了。此外,还可以用with torch.no_grad()
将不想被追踪的操作代码块包裹起来,这种方法在评估模型的时候很常用,因为在评估模型时,我们并不需要计算可训练参数(requires_grad=True)
的梯度。
Function
是另外一个很重要的类。Tensor
和Function
互相结合就可以构建一个记录有整个计算过程的有向无环图(DAG)。每个Tensor
都有一个.grad_fn
属性,该属性即创建该Tensor
的Function
, 就是说该Tensor
是不是通过某些运算得到的,若是,则grad_fn
返回一个与这些运算相关的对象,否则是None
。
提示
这个 Function 能够反映该Tensor
是如何被创建的,print(x.grad_fn)
后可以显示其对象名称,包括但不限于:<AddBackward>
, <MeanBackward1>
, <SumBackward0>
所以,梯度链一定是从一个 Tensor(requires_grad=True)
被创建开始的,这个 Tensor
被称作叶子节点,Pytorch 提供了 is_leaf()
函数来角读取其是否为叶子节点。
梯度
首先我们得明白在计算流中反向传播的概念,推荐参考colah's blog 有关反向传播的理解
前向传播与反向传播区别
前向传播:只能获得一个输出量对指定自变量的梯度
反向传播:遍历一次就可以获得输出量对于计算流图中任意节点的梯度
From Colah's Blog:
Forward-mode differentiation tracks how one input affects every node. Reverse-mode differentiation tracks how every node affects one output.That is, forward-mode differentiation applies the operator to every node, while reverse mode differentiation applies the operator to every node.
反向传播的过程是累加的(这一部分还并没有找到相关原理的文章做支撑,暂且先记住),所以在反向传播之前需要将梯度清零。
举例说明
现有如下 python 程序:
import torch
x = torch.ones(2, 2, requires_grad=True)
y = x + 2
z = y * y * 3
out = z.mean()
现在对out
反向传播,并求out
对x
的梯度(在反向传播之前需要将 x 的梯度清零)。
x.grad.data.zero_()
out.backward()
print(x.grad)
# 输出
tensor([[4.5000, 4.5000],
[4.5000, 4.5000]])
现在看不懂可以不用纠结,因为我也不会(