我有一个矩阵:
t = torch.rand(2,3)
print(t)
>>>tensor([[0.5164, 0.3651, 0.0882],
[0.4488, 0.9824, 0.4067]])
我正在关注 this 规范介绍,并想在 PyTorch 中尝试一下。
看起来像:
norm
是“向量的大小或长度是一个非负数,描述向量在空间中的范围,有时称为向量的大小或范数”1-Norm
是“绝对向量值的总和,其中标量的绝对值使用符号 |a1|。实际上,范数是距向量空间原点的曼哈顿距离的计算。”2-Norm
是“向量坐标距向量空间原点的距离。L2 范数计算为向量值平方和的平方根。”我目前只知道这个:
print(torch.linalg.norm(t, dim=1))
>>>tensor([0.6385, 1.1541])
但是我无法从这里计算出这三个(范数,1-范数,2-范数)中的哪一个,以及如何计算其余的
torch.linalg.norm
,并提供 ord
参数(分别为 0
、1
和 2
)。或者直接在张量上:Tensor.norm
,带有 p
参数。以下是三种变体:手动计算、使用 torch.linalg.norm
和使用 Tensor.norm
。
0-范数
>>> x.norm(dim=1, p=0)
>>> torch.linalg.norm(x, dim=1, ord=0)
>>> x.ne(0).sum(dim=1)
1-范数
>>> x.norm(dim=1, p=1)
>>> torch.linalg.norm(x, dim=1, ord=1)
>>> x.abs().sum(dim=1)
2-范数
>>> x.norm(dim=1, p=2)
>>> torch.linalg.norm(x, dim=1, ord=2)
>>> x.pow(2).sum(dim=1).sqrt()
要计算不同阶数的范数,您只需传入
ord
参数和您想要的阶数。例如:
torch.linalg.norm(t, dim=1, ord = 0)
应该适用于 norm。torch.linalg.norm(t, dim=1, ord = 1)
应该适用于 1-Norm。torch.linalg.norm(t, dim=1, ord = 2)
应该适用于 2-Norm。我想提出一个非常重要的观点。
在 pytorch 中计算 p 范数以进行神经网络训练时,我强烈鼓励您使用 pytorch 内置函数。
我尝试变得聪明,并使用以下方法自己实现了 2-范数:
loss = diff.pow(2).sum(dim=1).sqrt().mean()
# ^ diff is some difference between 2 pytorch tensors
然而,这在数值上是不稳定的,因为随着时间的推移,损失会促使
diff
接近0,但sqrt(x) = 1/(2 * sqrt(x)
的梯度。正如你所看到的,如果 x 为 0,梯度将是无限的,你的模型将在没有警告的情况下发散(特别是因为损失接近 0,你不会怀疑这是爆炸性损失或梯度问题)。
我的情况的修复方法是修剪
diff
,使其不小于某个 epsilon,例如 1e-8
diff = diff.pow(2).sum(dim=1)
diff = torch.where(diff < eps, torch.tensor(eps, device=diff.device), diff)
loss = diff.sqrt().mean()
这具有更加稳定的数值行为,并且您的模型不应再发散。
我非常确定 pytorch 开发人员已经考虑过这样的问题,并在内置函数中解决了它。