《动手学深度学习》——第二章笔记
第二章 预备知识
01 张量与其他 Python 对象的互相转换
# numpy 张量(ndarray)转化为 tensor 张量
A = X.numpy() # A是 ndarray 张量
B = torch.tensor(A) # B是 tensor 张量
# tensor 张量转化为其他值
a = torch.tensor([3.5])
a, a.item(), float(a), int(a) # 输出为 (tensor([3.5]), 3.5, 3.5, 3),注意这里只有tensor为单个值才能这样用,当 # tensor为具有多个值的矩阵时会报错
02 自动微分
x = torch.arange(4.0) # 这里必须写成4.0,若写成4的话则后续会报错,RuntimeError: only Tensors of floating point dtype can require gradients
x.requires_grad_(Ture) # 等价于 x = torch.arange(4.0, requires_grad = True)
x.grad # 默认值是 None
03 requires_grad,requires_grad_() 的区别
- x.requires_grad:是否要求微分的属性,默认为False;
- x.requires_grad_():设置积分的方法,设置之后requires_grad为True
04 torch.no_grad()
torch.no_grad()
是一个上下文管理器,用来禁止梯度的计算,通常用来网络推断中,它可以减少计算内存的使用量
>>> a = torch.tensor([1.0, 2.0], requires_grad=True)
>>> with torch.no_grad():
... b = n.pow(2).sum()
...
>>> b
tensor(5.)
>>> b.requires_grad
False
>>> c = a.pow(2).sum()
>>> c.requires_grad
True
# 上例中,当a的requires_grad=True时,不使用torch.no_grad(),c.requires_grad为True,使用torch.no_grad()时,b.requires_grad为False;
# 当不需要进行反向传播时(推断)或不需要计算梯度(网络输入)时,requires_grad=True会占用更多的计算资源及存储资源。
05 x.grad
- x.grad : 默认值为 None;
- 一个标量函数关于向量 x \mathbf x x 的梯度是向量,并且与 x \mathbf x x 有相同的形状;
06 非标量变量的反向传播
在PyTorch中有个简单的规定,不让张量对张量求导,只允许标量对张量求导。因此,目标量对一个非标量调用backward(),需要传入一个gradient参数。传入这个参数就是为了把张量对张量的求导转换为标量对张量的求导。
# 非标量反向传播
import torch
# 1、定义叶子节点及计算节点
# 定义叶子节点张量x
x = torch.tensor([2, 3], dtype=torch.float, requires_grad=True)
# 初始化雅克比矩阵
J = torch.zeros(2, 2)
# 初始化目标张量,形状为1×2
y = torch.zeros(1, 2)
# 定义y与x之间的映射关系
y[0, 0] = x[0] ** 2 + 3 * x[1]
y[0, 1] = x[1] ** 2 + 2 * x[0]
# 非标量反向传播
import torch
# 1、定义叶子节点及计算节点
# 定义叶子节点张量x
x = torch.tensor([2, 3], dtype=torch.float, requires_grad=True)
# 初始化雅克比矩阵
J = torch.zeros(2, 2)
# 初始化目标张量,形状为1×2
y = torch.zeros(1, 2)
# 定义y与x之间的映射关系
y[0, 0] = x[0] ** 2 + 3 * x[1]
y[0, 1] = x[1] ** 2 + 2 * x[0]
# 2、调用backward来获取y对x的梯度
y.backward(torch.Tensor([[1, 1]]))
print(x.grad)
# 结果显然是错误的
结果:tensor([6., 9.])
# 3、正确计算张量对张量求导
# 生成y1对x的梯度
y.backward(torch.Tensor([[1, 0]]), retain_graph=True)
J[0] = x.grad
# 梯度是累加的,故需要对x的梯度清零
x.grad = torch.zeros_like(x.grad)
# 生成y2对x的梯度
y.backward(torch.Tensor([[0, 1]]))
J[1] = x.grad
# 显示雅克比矩阵的值
print("J雅克比矩阵的值:{}".format(J))
结果:
J雅克比矩阵的值:tensor([[4., 3.],[2., 6.]])
07 分离计算detach
[分离计算参考]Pytorch-detach()用法_detach pytorch_维他柠檬可乐的博客-CSDN博客
08 x.grad.zero_()
- x.grad.zero_(): 用来“清除”x的梯度值,也就是重新赋值为0。需要注意的是,只有当x被求过一次梯度的时候,这个函数才能使用,否则会报错。
09 查阅文档
- 查找模块中的所有函数和类:print(dir(torch.distributions)) (通常可以忽略以"__"开始和结束的函数,它们是Pytorch中的特殊对象;或以单下划线开始的函数,它们通常是内部函数)
- 查找特定函数和类的用法:help(torch.ones)
10 torch 的 dot,mm,matmul函数
- torch.dot():
torch.dot(input, tensor) → Tensor
#计算两个张量的点积(内积)
#官方提示:不能进行广播(broadcast).
#example
>>> torch.dot(torch.tensor([2, 3]), torch.tensor([2, 1])) #即对应位置相乘再相加
tensor(7)
>>> torch.dot(torch.rand(2, 3), torch.rand(2, 2))
#报错,只允许一维的tensor
RuntimeError: 1D tensors expected, got 2D, 2D tensors at /Users/distiller/project/conda/conda-bld/pytorch_1570710797334/work/aten/src/TH/generic/THTensorEvenMoreMath.cpp:774
- torch.mm
torch.mm(input, mat2, out=None) → Tensor
#对矩阵imput和mat2执行矩阵乘法。 如果input为(n x m)张量,则mat2为(m x p)张量,out将为(n x p)张量。
#官方提示此功能不广播。有关广播的矩阵乘法,请参见torch.matmul()。
#example
>>> mat1 = torch.randn(2, 3)
>>> mat2 = torch.randn(3, 3)
>>> torch.mm(mat1, mat2)
tensor([[ 0.4851, 0.5037, -0.3633],
[-0.0760, -3.6705, 2.4784]])
- torch.matmul
torch.matmul(input, other, out=None) → Tensor
#两个张量的矩阵乘积。行为取决于张量的维数,如下所示:
#1. 如果两个张量都是一维的,则返回点积(标量)。
>>> # vector x vector
>>> tensor1 = torch.randn(3)
>>> tensor2 = torch.randn(3)
>>> torch.matmul(tensor1, tensor2).size()
torch.Size([])
#2. 如果两个参数都是二维的,则返回矩阵矩阵乘积。
# matrix x matrix
>>> tensor1 = torch.randn(3, 4)
>>> tensor2 = torch.randn(4, 5)
>>> torch.matmul(tensor1, tensor2).size()
torch.Size([3, 5])
#3. 如果第一个参数是一维的,而第二个参数是二维的,则为了矩阵乘法,会将1附加到其维数上。矩阵相乘后,将删除前置尺寸。
# 也就是让tensor2变成矩阵表示,1x3的矩阵和 3x4的矩阵,得到1x4的矩阵,然后删除1
>>> tensor1 = torch.randn(3, 4)
>>> tensor2 = torch.randn(3)
>>> torch.matmul(tensor2, tensor1).size()
torch.Size([4])
#4. 如果第一个参数为二维,第二个参数为一维,则返回矩阵向量乘积。
# matrix x vector
>>> tensor1 = torch.randn(3, 4)
>>> tensor2 = torch.randn(4)
>>> torch.matmul(tensor1, tensor2).size()
torch.Size([3])
#5. 如果两个自变量至少为一维且至少一个自变量为N维(其中N> 2),则返回批处理矩阵乘法。如果第一个参数是一维的,则在其维数之前添加一个1,以实现批量矩阵乘法并在其后删除。如果第二个参数为一维,则将1附加到其维上,以实现成批矩阵倍数的目的,然后将其删除。非矩阵(即批量)维度可以被广播(因此必须是可广播的)。例如,如果input为(jx1xnxm)张量,而other为(k×m×p)张量,out将是(j×k×n×p)张量。
>>> # batched matrix x broadcasted vector
>>> tensor1 = torch.randn(10, 3, 4)
>>> tensor2 = torch.randn(4)
>>> torch.matmul(tensor1, tensor2).size()
torch.Size([10, 3])
>>> # batched matrix x batched matrix
>>> tensor1 = torch.randn(10, 3, 4)
>>> tensor2 = torch.randn(10, 4, 5)
>>> torch.matmul(tensor1, tensor2).size()
torch.Size([10, 3, 5])
>>> # batched matrix x broadcasted matrix
>>> tensor1 = torch.randn(10, 3, 4)
>>> tensor2 = torch.randn(4, 5)
>>> torch.matmul(tensor1, tensor2).size()
torch.Size([10, 3, 5])
>>> tensor1 = torch.randn(10, 1, 3, 4)
>>> tensor2 = torch.randn(2, 4, 5)
>>> torch.matmul(tensor1, tensor2).size()
torch.Size([10, 2, 3, 5])
参考
Pytorch阅读文档之dot,mm,matmul函数_torch.dot_GhostintheCode的博客-CSDN博客