PyTorch:tensor-数学API
Posted -柚子皮-
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了PyTorch:tensor-数学API相关的知识,希望对你有一定的参考价值。
乘法API
一维tensor相乘:torch.dot
这个只支持一维相同维度的向量相乘,不支持2维以上。
torch.dot(torch.tensor([2, 3]), torch.tensor([2, 1]))
Note: np.dot就有点类似下面的matmul,和torch.dot完全不一样。
[TORCH.DOT]
二维tensor相乘:torch.mm
a是 [m, k],b是[k, n],结果是 [m, n]
c = torch.mm(a, b)
三维tensor相乘torch.bmm
只能用于三维tensor相乘,这个函数不支持广播,也就是第一维必须相同,另外两维符合矩阵相乘法则
c = torch.bmm(a, b)
任意多维tensor相乘:torch.matmul
等价于@运算符。
支持广播;当两个都是一维时,表示点积
c = torch.matmul(a, b)
广播的意思同numpy,如ab维度为[1,2,1152,1,8][10,1,1152,8,16],则matmul结果c的维度为[10,2,1152,1,16],即只有最后两维会执行一一的矩阵运算,其它都是取最大。
另外,如下例,[2,3,1]和[2,1,3]的结果维度是[2,3,3]。
利用这个可以实现规避batch维度功能,如想实现[https://zhuanlan.zhihu.com/p/55234968]中x0*x0^t*w0,假如inputs = batch*feature_dim = 2*3,w0 = 3*1这里不需要batch维度,则x_l = x_0 = inputs.unsqueeze(2)变成x_0 = 2*3*1,x_l^t = x0^t = 2*1*3,则xl_w = torch.matmul(x_l.transpose(1, 2), self.weight[i].unsqueeze(0))就是2*1*3 matmul 1*3*1,0维不管,结果是2*1*1,然后dot_ = torch.matmul(x_0, xl_w)就是2*3*1 matmul 2*1*1,结果是2*3*1,正确。
按元素相乘/element-wise乘法:torch.mul /*
两个相同尺寸的张量,对应元素相乘,就是哈达玛积,也叫element wise乘法。
1 element wise乘法是支持广播的,如维度为[10,2,1152,1,16]和[10,2,1,1,16]的张量相乘结果是取大的[10,2,1152,1,16]。
2 tensor ** 2 表示的含义是 tensor * tensor,也是element wise乘法。
示例:
两种等价方式
c = torch.mul(a, b)
c = a * b
Note: 可以发现的torch.div()
其实就是/
, 类似的:torch.add
就是+
,torch.sub()
就是-
,不过符号的运算更简单常用。
通用的张量相乘方法:torch.tensordot
tensordot是一种非常简单灵活的乘法计算函数。可以这样理解:输入数组a, b,通过参数axes指定要计算的维度(这里axes 是一个元组,里面必须有两个tuple元素 ,第一个元素是a要用于计算的 axis,第二个元素是b要用于计算的 axis)被参数axis指定的维度会执行sum-reduction,简单来说就是相乘之后求和这样被指定的axes将不会出现在输出中;而输入数组的其他维度将会变成输出数组的维度,对应的顺序和输入的顺序相同。
c = torch.tensordot(a, b, dims)
## 输入A和B,维度如size参数所示
A = np.random.randint(2, size=(2, 6, 5))
B = np.random.randint(2, size=(3, 2, 4))
## 指定axes=((0), (1)),也就是说,
## 按A的axis=0的列和B的axis=1列取元素,对应元素相乘求和
## 于是两个维度从输出中消失
np.tensordot(A, B, axes=((0),(1))).shape
np.tensordot(A, B, axes=((0),(1))).shape
Output: (6, 5, 3, 4)
A : (2, 6, 5) -> reduction of axis=0
B : (3, 2, 4) -> reduction of axis=1
Output : `(2, 6, 5)`, `(3, 2, 4)` ===(2 gone)==> `(6,5)` + `(3,4)` => `(6,5,3,4)`
[TORCH.TENSORDOT]
爱因斯坦求和约定einsum
求和简记法,能够以一种统一的方式表示各种各样的张量运算(内积、外积、转置、点乘、矩阵的迹、其他自定义运算),为不同运算的实现提供了一个统一模型。
示例
# trace
>>> torch.einsum('ii', torch.randn(4, 4))
tensor(-1.2104)
# diagonal
>>> torch.einsum('ii->i', torch.randn(4, 4))
tensor([-0.1034, 0.7952, -0.2433, 0.4545])
# outer product
>>> x = torch.randn(5)
>>> y = torch.randn(4)
>>> torch.einsum('i,j->ij', x, y)
tensor([[ 0.1156, -0.2897, -0.3918, 0.4963],
[-0.3744, 0.9381, 1.2685, -1.6070],
[ 0.7208, -1.8058, -2.4419, 3.0936],
[ 0.1713, -0.4291, -0.5802, 0.7350],
[ 0.5704, -1.4290, -1.9323, 2.4480]])
其它:torch.einsum('bld,brd->blr', x, y)
# batch matrix multiplication
>>> As = torch.randn(3,2,5)
>>> Bs = torch.randn(3,5,4)
>>> torch.einsum('bij,bjk->bik', As, Bs)
tensor([[[-1.0564, -1.5904, 3.2023, 3.1271],
[-1.6706, -0.8097, -0.8025, -2.1183]],
[[ 4.2239, 0.3107, -0.5756, -0.2354],
[-1.4558, -0.3460, 1.5087, -0.8530]],
[[ 2.8153, 1.8787, -4.3839, -1.2112],
[ 0.3728, -2.1131, 0.0921, 0.8305]]])
# batch permute
>>> A = torch.randn(2, 3, 4, 5)
>>> torch.einsum('...ij->...ji', A).shape
torch.Size([2, 3, 5, 4])
# equivalent to torch.nn.functional.bilinear
>>> A = torch.randn(3,5,4)
>>> l = torch.randn(2,5)
>>> r = torch.randn(2,4)
>>> torch.einsum('bn,anm,bm->ba', l, A, r)
tensor([[-0.3430, -5.2405, 0.4494],
[ 0.3311, 5.5201, -3.0356]])
[einsum满足你一切需要:深度学习中的爱因斯坦求和约定]
xDeepFM中每层向量计算:即h个d维向量 点乘 m个d维向量,形成h*m个d维向量。
x = torch.einsum('bhd,bmd->bhmd', hidden_nn_layers[-1], hidden_nn_layers[0])
[torch.einsum(equation, *operands) → Tensor]
TORCH.MAX
形式: torch.max(input) → Tensor
返回输入tensor中所有元素的最大值:
a = torch.randn(1, 3)
>>0.4729 -0.2266 -0.2085
torch.max(a) #也可以写成a.max()
>>0.4729
形式: torch.max(input, dim, keepdim=False, out=None) -> (Tensor, LongTensor)
参数:keepdim=True时,原size是(2,3),返回时就不是(2,)或者(3,)而是(2,1)或者(1,3)。
dim参数:按维度dim 返回最大值,并且返回索引(dim未指定时,不返回索引)。
torch.max(a,0)返回每一列中最大值的那个元素,且返回索引(返回最大元素在这一列的行索引)。返回的最大值和索引各是一个tensor,一起构成元组(Tensor, LongTensor)。
torch.max()[0], 只返回最大值的每个数。即一般用法tensor1.mean(dim=0).values。
troch.max()[1], 只返回最大值的每个索引。
a = torch.randn(4, 4)
tensor([[-1.2360, -0.2942, -0.1222, 0.8475],
[ 1.1949, -1.1127, -2.2379, -0.6702],
[ 1.5717, -0.9207, 0.1297, -1.8768],
[-0.6172, 1.0036, -0.6060, -0.2432]])
>>> torch.max(a, 1)
torch.return_types.max(values=tensor([0.8475, 1.1949, 1.5717, 1.0036]), indices=tensor([3, 0, 0, 1]))
Note: 在有的地方我们会看到torch.max(a, 1).data.numpy()的写法,这是因为在早期的pytorch的版本中,variable变量和tenosr是不一样的数据格式,variable可以进行反向传播,tensor不可以,需要将variable转变成tensor再转变成numpy。现在的版本已经将variable和tenosr合并,所以只用torch.max(a,1).numpy()就可以了。
TORCH.MEAN
torch.mean(input) → Tensor
Returns the mean value of all elements in the input tensor.
torch.mean(input, dim, keepdim=False, *, out=None) → Tensor
Returns the mean value of each row of the input tensor in the given dimension dim. If dim is a list of dimensions, reduce over all of them.
和max区别在于返回的值只有一个tensor,没有最大值多余的位置索引tensor。
用法tensor1.mean(dim=0)。
torch.softmax归一化
对于n维张量,如果dim=k,那就是对k维度进行softmax(这时其它维度取固定值时,维度k上的值加起来为1。)。比k更高维度的d(d<k)是不需要考虑的,直接去掉分析。
示例1:
t = torch.zeros([5,2,3])
t1 = torch.softmax(t, dim = 0)
t1:
tensor([[[0.2000, 0.2000, 0.2000],
[0.2000, 0.2000, 0.2000]],
[[0.2000, 0.2000, 0.2000],
[0.2000, 0.2000, 0.2000]],
[[0.2000, 0.2000, 0.2000],
[0.2000, 0.2000, 0.2000]],
[[0.2000, 0.2000, 0.2000],
[0.2000, 0.2000, 0.2000]],
[[0.2000, 0.2000, 0.2000],
[0.2000, 0.2000, 0.2000]]])
t1[:,0,0]
tensor([0.2000, 0.2000, 0.2000, 0.2000, 0.2000])
sum(t1[:,0,0])
tensor(1.)
图的表示为(只对立方体中的k维度进行):
示例2:如果有更高维度不用管
t = torch.zeros([4,5,2,3])
t1 = torch.softmax(t, dim = 1)
sum(t1[0,:,0,0])
tensor(1.)
示例3:
对2个维度同时进行softmax(即其它维度固定时,这2个维度的值加起来为1)。
t = torch.zeros([4,5,2,3])
# t1 = torch.softmax(t, dim = (1,2)), dim只能是数字,下面就是要模拟这个操作。
t1 = t.view(t.size(0), -1, t.size()[-1])
t2 = torch.softmax(t1, dim = 1).view(t.size())
t2[0,:,:,0].sum()
Out[14]: tensor(1.0000)
# sum(t2[0,:,:,0])
# Out[13]: tensor([0.5000, 0.5000])
[torch.nn.Softmax(dim=None)]
from: -柚子皮-
ref: [[Pytorch和Tensorflow对比(一)]:乘法、正则化]
以上是关于PyTorch:tensor-数学API的主要内容,如果未能解决你的问题,请参考以下文章
PyTorch:tensor-张量维度操作(拼接维度扩展压缩转置重复……)