1. 什么叫mask?
我们在自然语言处理中,听到给一个句子加mask,意义是:
我们如果有3个句子:
今天天气真的好
我讨厌阳光强烈的天气
雨天真美
ok,这三个句子的句子长度分别是(按字算,当然你也可以分词处理):7,10,4。
我们假设从词表中获取每个字对应的数字后,句子变成:
12 13 14 15 16 18 20
23 24 25 26 27 28 29 18 13 14
30 13 16 45
但是我们的模型一般无法处理变长序列,因此需要统一长度。那么一般采用补的方法,即所有句子长度统一为所有句子中长度最长的句子长度,即10。
处理后的长度为:
12 13 14 15 16 18 20 0 0 0
23 24 25 26 27 28 29 18 13 14
30 13 16 45 0 0 0 0 0 0
我们发现其中0所代表的位置,其实并没有字,只是一个补充,此时我们需要一个mask(遮罩),来表示一下哪些位置有词,哪些位置没有词,遮罩的样子应该是:
1 1 1 1 1 1 1 0 0 0
1 1 1 1 1 1 1 1 1 1
1 1 1 1 0 0 0 0 0 0
ok,现在你知道什么是mask了,那么怎么构建一个mask呢?
2. 以Pytorch为例写个mask
sentence_lengths = torch.Tensor([7, 10, 4]) # 代表每个句子的长度
mask = torch.arange(sentence_lengths.max().item())[None, :] < sentence_lengths[:, None]
"""输出
tensor([[ True, True, True, True, True, True, True, False, False, False],
[ True, True, True, True, True, True, True, True, True, True],
[ True, True, True, True, False, False, False, False, False, False]])
"""
# 我们发现里面是Boolean值,需要将其转化成 0, 1值 只需要
mask = mask.float()
mask
"""输出
tensor([[1., 1., 1., 1., 1., 1., 1., 0., 0., 0.],
[1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],
[1., 1., 1., 1., 0., 0., 0., 0., 0., 0.]])
"""
3. 代码详解!!!
这段代码中max() 是取tensor中的最大值,返回值仍然是Tensor格式,需要用item()将其“值”取出来,返回一个float。
然后torch.arange(10)生成一个0到9的Tensor,即:tensor([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])。
然后通过[None,:]给其在“外层”添加一个维度,变成:tensor([[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]])。
倘若是在内层添加一个维度,torch.arange(10)[:, None],则变成:
tensor([
[0],
[1],
[2],
[3],
[4],
[5],
[6],
[7],
[8],
[9]])
其实sentence_lengths就是执行的[:, None],相当于变成列向量:
Tensor([
[7],
[10],
[4]])
然后是大小比较,是tensor([[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]])先复制3行,然后第一行中的每个元素去和[7]比较,第二行和[10]比较,第三行和[4]比较,
以第一行为例:如果小于7,则成立,返回True,即1;否则返回False,即0。
最后形成3*10的mask矩阵。
给 👴 懂!
希望没有为代码挣扎的孩子。