sequence_mask

文章目录

  • 1. True 和 False
  • 2. 矩阵广播
  • 3. sequence_mask
  • 4. masked_softmax

1. True 和 False

我们可以通过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]])

2. 矩阵广播

我们假设矩阵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])

3. sequence_mask

  • 作用:给定一个矩阵A,一个张量B,我们根据张量B中的元素来屏蔽A中元素
  • 思路
    (1)创建一个矩阵m,将给定的张量B中元素跟m进行比较
    (2)得到一个同等大小的True,False矩阵,取反
    (3)将矩阵里面的需要屏蔽的元素值赋值为0
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]])

4. masked_softmax

在进行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]]])

你可能感兴趣的:(python,pytorch,深度学习,pytorch,python)