这几天正在看NLP中的注意力机制,代码中涉及到了一些关于张量矩阵乘法和填充一些代码,这里积累一下。主要参考了pytorch2.0的官方文档。
①torch.mm(input,mat2,*,out=None)
②torch.bmm(input,mat2,*,out=None)
③torch.matmul(input, other, *, out=None)
④Tensor.masked_fill
torch.mm语法为:
torch.mm(input, mat2, *, out=None) → Tensor
就是矩阵的乘法。如果输入input是(n,m),mat2是(m, p),则输出为(n, p)。
示例:
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.bmm语法为:
torch.bmm(input, mat2, *, out=None) → Tensor
示例:
input = torch.randn(10, 3, 4)
mat2 = torch.randn(10, 4, 5)
res = torch.bmm(input, mat2)
res.size()
-->torch.Size([10, 3, 5])
解读:实际上刻画的就是一组矩阵与另一组张量矩阵的乘积,至于一组有多少个矩阵,由input和mat2的第一个输入维度决定,上述代码第一个维度为10,就代表着10个形状为(3, 4)的矩阵与10个形状为(4, 5)的矩阵分别对应相乘,得到10个形状为(3, 5)的矩阵。
torch.matmul语法为:
torch.matmul(input, other, *, out=None) → Tensor
该函数刻画的是两个张量的乘积,且计算过程与张量的维度密切相关。
① 如果张量是一维的,输出结果是点乘,是一个标量。
a = torch.tensor([1,2,4])
b = torch.tensor([2,5,6])
print(torch.matmul(a, b))
print(a.shape)
--> tensor(36)
-->torch.Size([3])
注意:张量a.shape显示的是torch.Size([3]),只有一个维度,3是指这个维度中有3个数。
② 如果两个张量都是二维的,执行的是矩阵的乘法。
a = torch.tensor([
[1,2,4],
[6,2,1]
])
b = torch.tensor([
[2,5],
[1,2],
[6,8]
])
print(a.shape)
print(b.shape)
print(torch.matmul(a, b))
-->torch.Size([2, 3])
-->torch.Size([3, 2])
-->tensor([[28, 41],
[20, 42]])
由上述示例可知,如果两个张量均为2维,那么其运算和torch.mm是一样的。
③如果第一个参数input是1维的,第二个参数是二维的,那么在计算时,在第一个参数前增加一个维度1,计算完毕之后再把这个维度去掉。
a = torch.tensor([1,2,4])
b = torch.tensor([
[2,5],
[1,2],
[6,8]
])
print(a.shape)
print(b.shape)
print(torch.matmul(a, b))
-->torch.Size([3])
-->torch.Size([3, 2])
-->tensor([28, 41])
如上所示,a只有一个维度,在进行计算时,变成了(1, 3),则变成了(1, 3)乘以(3, 2),变成(1, 2),最后在去掉1这个维度。
④如果第一个参数是2维的,第二个参数是1维的,则返回矩阵-向量乘积。
a = torch.tensor([1,2])
b = torch.tensor([
[2,5],
[1,2],
[6,8]
])
print(b.shape)
print(a.shape)
print(torch.matmul(b, a))
-->torch.Size([3, 2])
-->torch.Size([2])
-->tensor([12, 5, 22])
矩阵乘以张量,就是矩阵中的每一行都与这个张量相乘,最终得到一个一维的,大小为3的结果。
⑤多个维度
tensor1 = torch.randn(10, 3, 4, 5)
tensor2 = torch.randn(5, 4)
torch.matmul(tensor1, tensor2).size()
-->torch.Size([10, 3, 4, 4])
tensor1 = torch.randn(10, 3, 4, 5)
tensor2 = torch.randn(1, 5, 4)
torch.matmul(tensor1, tensor2).size()
-->torch.Size([10, 3, 4, 4])
tensor1 = torch.randn(10, 3, 4, 5)
tensor2 = torch.randn(1, 1, 5, 4)
torch.matmul(tensor1, tensor2).size()
-->torch.Size([10, 3, 4, 4])
仔细比较上述三个代码块,其最终的结果是一样的。可以简单记为如果两个维度不一致的话,多出的维度就看作是batch维,相当于在低维度前面增加一个维度。
语法为:
Tensor.masked_fill_(mask, value)
参数:
mask是一个pytorch张量,元素是布尔值,value是要填充的值,填充规则是mask中取值为True的位置对应与需要填充的张量中的位置用value填充。
a = torch.tensor([
[0, 8],
[ 6, 8],
[ 7, 1]
])
mask = torch.tensor([
[ True, False],
[False, False],
[False, True]
])
b = a.masked_fill(mask, -1e9)
print(b)
-->tensor([[-1000000000, 8],
[ 6, 8],
[ 7, -1000000000]])