来看一下 NLP 里面另外一个很经典的 task, POS 词性标注
一点背景
Part-Of-Speech (POS) tagging 词性标注
词性标注任务是为给定句子中的每个单词分配给定标签集中的词性标签。 就是对句子中的词进行分类和标注的过程,实际上是一个多分类任务。 我们根据词在句法结构或语言形式中的成分,通过词性分类给每个词赋予相应的词性。
即判断句子中的每个单词是名词、动词、形容词还是其他词性。
词性标注是自然语言处理中的一项基本任务,在语音识别、信息检索等诸多领域都有应用。词性标注的常用方法是使用序列标注模型,例如 RNN 或 transformer。 序列标注模型以一个单词序列作为输入,输出将是一个 POS 标签序列,其中每个 POS 标签都是对输入序列中相应单词的预测。
例如,用于词性标注的简单 RNN 模型可能包含一个 embedding 层,用于将单词映射到 dense 向量,一个 recurrent 层(例如 LSTM),用于处理词向量序列,以及一个全连接层,用于预测词性标签。
该模型将被训练以最小化给定输入句子的预测词性标签和真实词性标签之间的交叉熵损失。
Multi-stack BiLSTM
在我们的实验中,我们使用了 Multi-stack BiLSTM。
首先,BiLSTM 网络是 LSTM 的一种,它在正向和反向两个方向上处理输入序列,允许模型从过去和未来的上下文中捕获输入数据中的上下文依赖性。 顾名思义,Multi-stack BiLSTM 是一种由多层 BiLSTM 组成的 BiLSTM。 在多Multi-stack BiLSTM 中,输入序列由多层 BiLSTM 处理,其中每一层堆叠在前一层之上。
这允许模型学习输入数据的层次表示,随着输入数据通过层进行处理,捕获越来越复杂的模式。
Fast-text embeddings
FastText 是一个用于高效学习单词表示和句子分类的库。 它是由 Facebook AI Research 开发的。 它包括许多用于学习 word embeddings 的技术,还提供了许多已经预训练好的 word embeddings。 由于我们想在跨语言领域进行评估,因此我们会同时使用英语和法语的 Embeddings。
具体实现
数据预处理
Data loader
ID column 在输入文件中包含 3 种类型的值,所以我们使用 .isdigit() 来检查它是否是我们需要的正确的 row。然后我们将所有单词转换为小写。
def read_file(path):
sentences, upos_list, sentence, upos = [], [], [], []
with open(path) as inf:
for line in inf:
line = line.strip()
if line == "":
sentences.append(" ".join(sentence))
upos_list.append(upos)
sentence, upos = [], []
elif line[0].isdigit():
line_list = line.split()
sentence.append(line_list[1].lower())
upos.append(line_list[3].lower())
return sentences, upos_list
然后我们从给定的文档中读取 word embeddings,并构建一个词词典
同时映射单词和 index。 请注意,我们添加了一个带有零向量 embeddings 的 token,去处理 unseen 的词。
def read_embedding(file_path):
with open(file_path, 'r') as f:
lines = f.readlines()
embedding_dim = len(lines[0].split())-1
embedding = torch.empty(size=(len(lines), embedding_dim))
word_to_id = {}
id_to_word = {}
for i, line in enumerate(lines):
splitted_lines = line.split()
word = splitted_lines[0]
word_to_id[word] = i
id_to_word[i] = word
embedding[i] = torch.tensor(list(map(float, splitted_lines[-embedding_dim:])))
return embedding, word_to_id, id_to_word
Data encoder
首先,为了减少 unseen 词的数量,我们对词进行了预处理删除复数的“s”,这样可以将 unseen 减少一半。 然后,我们对两者进行 encoder,将文本和标签放入一个句子列表中,每个句子由一个整数列表(单词 ID 或标签 ID)组成。
def encoder(txt, pos, word_to_id, pos_to_id):
def word_encoder(word):
if word not in word_to_id and word[-1]=='s' and word[:-1] in word_to_id:
word = word[:-1]
elif word not in word_to_id:
word = '<unk>'
return word_to_id[word]
sentence_encoder = lambda sentence: list(map(word_encoder, sentence))
pos_encoder = lambda sentence: list(map(lambda p: pos_to_id[p], sentence))
txt_encoded = list(map(sentence_encoder, txt))
pos_encoded = list(map(pos_encoder, pos))
return txt_encoded, pos_encoded
Modelling
在本实验中,由于我们使用的是 pretrained wordEmedding, 并且用了不同的语言,所以我们把 WordEmbedding 单独提出来,实现了两个模块:WordEmbedding 类和 POSTagging 类。
Embedding Module
Embedding Module 用于从快速文本文件中检索 word embedding。 它以一个句子列表(每个句子都是一个 ID 列表)作为输入,并输出一个 tensor 列表,每个 tensor 的大小为 ( l e n _ s e n t e n c e , 300 ) (len\_sentence, 300) (len_sentence,300)</