被迫要使用语义角色标注(Deep Semantic Role Labeling)技术,本来想直接使用github上的项目Tagger,奈何作者说自己本来用tensorflow写的,后来改成pytorch但没完全改(Model ensemble不可用,且预训练好的模型只提供了tensorflow版本的,需要用pytorch来调用),所以计划来读这篇文章,方便日后的改动
任务设置给定一个句子,SRL(Semantic Role Labeling)的目标是定义每个目标动词的论元(可以简单理解为与目标动词有关系的词),并将他们分类为语义角色。如下图这个例子:
SRL就需要为“发表”这个目标动词定义论元,并指定这些论元的语义角色(包括who did what to whom, when and where等)
所以,SRL中就包括定义论元和分类论元这两个任务。有时在定义论元前,也会对明显的非候选论元进行剪枝,或者是在分类论元后,应用后处理流程去调整不一致的预测。在测试中,动态规划算法经常被用来寻找全局最优解。
引入问题:训练阶段是需要指定目标动词和论元角色的,但是测试阶段需不需要也指定目标动词呢?
背景:最初的SRL方法是需要句法输入的(也就是把输入句子的结构同时告诉算法),后来提出了堆叠的LSTM网络并获得了很好的效果,这种方法能够端到端地处理潜在的句法结构
动机:现在的RNN方法存在两个问题:1)内存压缩问题,也就是处理长句和短句都使用单个固定大小的向量,这种不平衡的方式导致网络在长句上表现差、短句上浪费内存 2)缺乏处理树结构输入的方式(?)
提出的方法:1)能建立任意两个token之间的直接关系 2)提供了一个更灵活的方式案例挑选、表示和合成输入信息 3)这使得网络在领域外的数据集上表现也很好
网络简介:输入原本的句子和动词mask,首先转化为embedding,然后将其放入深度注意力神经网络(由多个相同的层组成,每层包括非线性子层和注意力子层)来获取句子的嵌套结构和label之间的潜在关系,其中,非线性子层可选RNN/CNN/FNN或合成,分别称为DeepAtt-RNN/CNN/FFN以及Model ensemble。测试阶段,只有最高层的attention子层输出被放入逻辑回归层来进行最终的预测(训练阶段不也是?)
其中每个模块在当时看来可能是比较新的技术,但在2022年已经屡见不鲜了,这里就不再一一赘述了
问题:仍然不知道训练阶段需不需要输入谓词判别向量mask,还需要去代码中找答案
代码学习./tagger/bin/predictor.py 目测要测试的代码应该从这里找,简单学习下
# coding=utf-8
# Copyright 2017-2019 The THUMT Authors
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import argparse
import logging
import os
import six
import time
import torch
import tagger.data as data
import tagger.models as models
import tagger.utils as utils
def parse_args():
# 创建ArgumentParser()对象,用于之后添加参数
parser = argparse.ArgumentParser(
description="Predict using SRL models",
usage="translator.py [] [-h | --help]"
)
# input files
parser.add_argument("--input", type=str, required=True,
help="Path of input file")
parser.add_argument("--output", type=str, required=True,
help="Path of output file")
parser.add_argument("--checkpoint", type=str, required=True,
help="Path of trained models")
# 源词汇和目标词汇的路径?不太懂
parser.add_argument("--vocabulary", type=str, nargs=2, required=True,
help="Path of source and target vocabulary")
# model and configuration
parser.add_argument("--model", type=str, required=True,
help="Name of the model")
parser.add_argument("--parameters", type=str, default="",
help="Additional hyper parameters")
# 编码时是否使用半精度
parser.add_argument("--half", action="store_true",
help="Use half precision for decoding")
return parser.parse_args()
def default_params():
# utils: import tagger.utils as utils
# utils.HParams: utils/__init__.py
# from tagger.utils.hparams import HParams
params = utils.HParams(
input=None,
output=None,
vocabulary=None,
embedding="",
# vocabulary specific
pad="" ,
bos="" ,
eos="" ,
unk="" ,
device=0,
decode_batch_size=128
)
return params
def merge_params(params1, params2):
params = utils.HParams()
for (k, v) in six.iteritems(params1.values()):
params.add_hparam(k, v)
params_dict = params.values()
for (k, v) in six.iteritems(params2.values()):
if k in params_dict:
# Override
setattr(params, k, v)
else:
params.add_hparam(k, v)
return params
def import_params(model_dir, model_name, params):
model_dir = os.path.abspath(model_dir)
m_name = os.path.join(model_dir, model_name + ".json")
if not os.path.exists(m_name):
return params
with open(m_name) as fd:
logging.info("Restoring model parameters from %s" % m_name)
json_str = fd.readline()
params.parse_json(json_str)
return params
def override_params(params, args):
params.parse(args.parameters)
src_vocab, src_w2idx, src_idx2w = data.load_vocabulary(args.vocabulary[0])
tgt_vocab, tgt_w2idx, tgt_idx2w = data.load_vocabulary(args.vocabulary[1])
params.vocabulary = {
"source": src_vocab, "target": tgt_vocab
}
params.lookup = {
"source": src_w2idx, "target": tgt_w2idx
}
params.mapping = {
"source": src_idx2w, "target": tgt_idx2w
}
return params
def convert_to_string(inputs, tensor, params):
inputs = torch.squeeze(inputs)
inputs = inputs.tolist()
tensor = torch.squeeze(tensor, dim=1)
tensor = tensor.tolist()
decoded = []
for wids, lids in zip(inputs, tensor):
output = []
for wid, lid in zip(wids, lids):
if wid == 0:
break
output.append(params.mapping["target"][lid])
decoded.append(b" ".join(output))
return decoded
# 所以args包含parse_args上定义的所有参数,可以通过args.来调用
def main(args):
# Load configs
# models: import tagger.models as models
# models.get_model: models/__init__,py
# def get_model()
model_cls = models.get_model(args.model)
#
params = default_params()
params = merge_params(params, model_cls.default_params())
params = import_params(args.checkpoint, args.model, params)
params = override_params(params, args)
torch.cuda.set_device(params.device)
torch.set_default_tensor_type(torch.cuda.FloatTensor)
# Create model
with torch.no_grad():
model = model_cls(params).cuda()
if args.half:
model = model.half()
torch.set_default_tensor_type(torch.cuda.HalfTensor)
model.eval()
model.load_state_dict(
torch.load(utils.best_checkpoint(args.checkpoint),
map_location="cpu")["model"])
# Decoding
dataset = data.get_dataset(args.input, "infer", params)
fd = open(args.output, "wb")
counter = 0
if params.embedding is not None:
embedding = data.load_glove_embedding(params.embedding)
else:
embedding = None
for features in dataset:
t = time.time()
counter += 1
features = data.lookup(features, "infer", params, embedding)
labels = model.argmax_decode(features)
batch = convert_to_string(features["inputs"], labels, params)
for seq in batch:
fd.write(seq)
fd.write(b"\n")
t = time.time() - t
print("Finished batch: %d (%.3f sec)" % (counter, t))
fd.close()
if __name__ == "__main__":
# 以parse_args()函数返回的结果作为参数传递给main
main(parse_args())
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)