我们可以通过true和false 来抽取矩阵中的元素
import torch
input = torch.arange(9).reshape(3, 3)
print(f"input_before={input}")
# 定义一个跟input相同大小的矩阵,True表示提取,False表示不用处理
mask = torch.tensor([[False, False, True],
[False, True, False],
[True, False, False]])
# 将对应为True的元素提取出来
output_tensor = input[mask]
# 将对应为True的元素用-1取代,其他元素不变,矩阵大小不变
input[mask] = -1
print(f"output_tensor={output_tensor}")
print(f"input_after={input}")
input_before=tensor([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])
# 将反对角线的元素提取出来,放在一个张量中
output_tensor=tensor([2, 4, 6])
# 将反对角线的元素值用-1代替,其他保持不变
input_after=tensor([[ 0, 1, -1],
[ 3, -1, 5],
[-1, 7, 8]])
我们假设矩阵A =[1,m],矩阵B=[n,1],如果我们矩阵C = A-B 那么我们就需要进行
x = torch.arange(3)
m = x[None, :]
n = x[:, None]
z = m+n
print(f"x={x}")
print(f"x.shape={x.shape}")
print(f"m={m}")
print(f"m.shape={m.shape}")
print(f"n={n}")
print(f"n.shape={n.shape}")
print(f"z={z}")
print(f"z.shape={z.shape}")
x=tensor([0, 1, 2])
x.shape=torch.Size([3])
m=tensor([[0, 1, 2]])
m.shape=torch.Size([1, 3])
n=tensor([[0],
[1],
[2]])
n.shape=torch.Size([3, 1])
z=tensor([[0, 1, 2],
[1, 2, 3],
[2, 3, 4]])
z.shape=torch.Size([3, 3])
import torch
from torch import nn
from d2l import torch as d2l
def sequence_mask(X, valid_len, value=0):
"""Mask irrelevant entries in sequences.
Defined in :numref:`sec_seq2seq_decoder`"""
maxlen = X.size(1)
mask = torch.arange((maxlen), dtype=torch.float32,
device=X.device)[None, :] < valid_len[:, None]
X[~mask] = value
return X
x = torch.arange(12).reshape(3, 4) + 1
y = torch.tensor([1, 2, 2])
z = sequence_mask(x, y)
print(z)
tensor([[ 1, 0, 0, 0],
[ 5, 6, 0, 0],
[ 9, 10, 0, 0]])
在进行masked_softmax的时候,我们的输入变成了三维的数据,为了解决上述问题,我们需要将输入的数据X转换成二维数据,也需要把mask矩阵的复制成行数;
import torch
from torch import nn
from d2l import torch as d2l
def masked_softmax(X, valid_lens):
# X=torch.randn(2,2,4);valid_lens = torch.tensor(2,3)
# 如果不做掩码,就直接进行softmax计算
"""通过在最后⼀个轴上掩蔽元素来执⾏softmax操作"""
# X:3D张量,valid_lens:1D或2D张量
if valid_lens is None:
return nn.functional.softmax(X, dim=-1)
else:
# shape=torch.size([2,3,4])
shape = X.shape
if valid_lens.dim() == 1:
# 因为 d2l.sequence_mask是作用在二维矩阵里面的,如果成为三维数据
# 那么就需要
valid_lens = torch.repeat_interleave(valid_lens, shape[1])
else:
valid_lens = valid_lens.reshape(-1)
# 先将三维数据X转换成列不变的二维数据,这样X的大小变成了(6,4)
# 为了保证valid_lens也应该是行数一样,所以valid_lens需要复制shape[1]次->6
# 最后⼀轴上被掩蔽的元素使⽤⼀个⾮常⼤的负值替换,从⽽其softmax输出为0
X = d2l.sequence_mask(X.reshape(-1, shape[-1]), valid_lens,
value=-1e6)
return nn.functional.softmax(X.reshape(shape), dim=-1)
x = torch.rand(2, 3, 4)
y = torch.tensor([2, 1])
z = masked_softmax(x, y)
print(f"x={x}")
print(f"y={y}")
print(f"z={z}")
x=tensor([[[ 8.8442e-02, 7.5017e-01, -1.0000e+06, -1.0000e+06],
[ 2.0534e-01, 7.1450e-01, -1.0000e+06, -1.0000e+06],
[ 7.1561e-01, 9.5432e-01, -1.0000e+06, -1.0000e+06]],
[[ 6.5720e-01, -1.0000e+06, -1.0000e+06, -1.0000e+06],
[ 5.2476e-01, -1.0000e+06, -1.0000e+06, -1.0000e+06],
[ 1.4059e-01, -1.0000e+06, -1.0000e+06, -1.0000e+06]]])
y=tensor([2, 1])
z=tensor([[[0.3404, 0.6596, 0.0000, 0.0000],
[0.3754, 0.6246, 0.0000, 0.0000],
[0.4406, 0.5594, 0.0000, 0.0000]],
[[1.0000, 0.0000, 0.0000, 0.0000],
[1.0000, 0.0000, 0.0000, 0.0000],
[1.0000, 0.0000, 0.0000, 0.0000]]])