2.预备知识
文章目录
- 2.1. 数据操作
- 2.2. 数据预处理
- 2.3. 线性代数
- 2.4. 微积分
- 2.5.自动微分
2.1. 数据操作
- torch.rand(shape): [0, 1] 的均匀分布,torch.randn(shape): 均值为0、标准差为1的标准高斯分布(正态分布),torch.normal(mean, std, shape) 指定均值和标准差的正态分布
- torch.arange(num): [0, num) 的数组
- 如果我们用Y = X + Y,我们将取消引用Y指向的张量,而是指向新分配的内存处的张量。这是因为Python首先计算Y + X,为结果分配新的内存,然后使Y指向内存中的这个新位置。
- 原地操作:我们可以使用切片表示法将操作的结果分配给先前分配的数组,例如Y[:] = <expression>。
Z = torch.zeros_like(Y) print('id(Z):', id(Z)) Z[:] = X + Y print('id(Z):', id(Z))
如果在后续计算中没有重复使用X, 我们也可以使用X[:] = X + Y或X += Y来减少操作的内存开销。id(Z): 140327634811696 id(Z): 140327634811696
before = id(X) X += Y id(X) == before
True
- 要将大小为1的张量转换为Python标量,我们可以调用item函数或Python的内置函数。
a = torch.tensor([3.5]) a, a.item(), float(a), int(a)
2.2. 数据预处理
2.3. 线性代数
- tensor.sum(axis=0,keepdims=True): 按照某个轴求和,tensor.cumsum(axis=0)求累积和, tensor.mean一样的用法;tensor.numel():元素个数
- torch.dot(a, b) = torch.sum(a * b) 求两个向量的点积,torch.mv 专门用于二维矩阵 x 一维向量,torch.mm 专门用于二维矩阵 x 二维矩阵(也就是这里都是线性代数的用法),对于张量的矩阵乘法用 torch.matmul
2.4. 微积分
2.5.自动微分
-
torch中非标量变量的反向传播:对于高阶和高维的y和x,求导的结果可以是一个高阶张量。然而,虽然这些更奇特的对象确实出现在高级机器学习中(包括深度学习中), 但当调用向量的反向计算时,我们通常会试图计算一批训练样本中每个组成部分的损失函数的导数。 这里,我们的目的不是计算微分矩阵,而是单独计算批量中每个样本的偏导数之和。
# 对非标量调用backward需要传入一个gradient参数,该参数指定微分函数关于self的梯度。 # 本例只想求偏导数的和,所以传递一个1的梯度是合适的 x.grad.zero_() y = x * x # 等价于y.backward(torch.ones(len(x))) y.sum().backward() x.grad
注意:
- 如果y是矩阵,要先把y转化为标量,再求导。转化为方法是:backward()函数传入一个矩阵m,计算y*m(y的各元素与m的元素对应相乘,不是矩阵相乘),再求矩阵元素之和,这样得到一个标量(实际就是y中的元素加权求和),然后才能求导。
- pytorch不支持对非标量进行backward。sum可以理解为对f(x)增加了一个复合函数,z=sum(y), 而 dz/dy 是一个单位向量或者单位矩阵,这样不影响最终的结果。
- 参考:https://www.cnblogs.com/Davy-Chen/articles/17317031.html
-
分离计算
有时,我们希望将某些计算移动到记录的计算图之外。 例如,假设y是作为x的函数计算的,而z则是作为y和x的函数计算的。 想象一下,我们想计算z关于x的梯度,但由于某种原因,希望将y视为一个常数, 并且只考虑到x在y被计算后发挥的作用。这里可以分离y来返回一个新变量u,该变量与y具有相同的值, 但丢弃计算图中如何计算y的任何信息。 换句话说,梯度不会向后流经u到x。 因此,下面的反向传播函数计算z=ux关于x的偏导数,同时将u作为常数处理, 而不是z=xx*x关于x的偏导数。
x.grad.zero_() y = x * x u = y.detach() z = u * x z.sum().backward() x.grad == u
tensor([True, True, True, True])